From ce8d0424b1a59bb2b0bd3ab8f69f4e4cf8c9930b Mon Sep 17 00:00:00 2001
From: Dean Camera <dean@fourwalledcubicle.com>
Date: Fri, 19 Feb 2010 05:17:41 +0000
Subject: [PATCH] AVRISP programmer project now has a more robust timeout
 system, allowing for a doubling of the software USART speed for PDI and TPI
 programming.

---
 LUFA/ManPages/ChangeLog.txt                  |  10 ++
 LUFA/ManPages/MigrationInformation.txt       |   1 +
 Projects/AVRISP-MKII/Lib/V2Protocol.c        |  15 ---
 Projects/AVRISP-MKII/Lib/V2Protocol.h        |   6 -
 Projects/AVRISP-MKII/Lib/XPROG/TINYNVM.c     |  18 ++-
 Projects/AVRISP-MKII/Lib/XPROG/XMEGANVM.c    |  18 ++-
 Projects/AVRISP-MKII/Lib/XPROG/XPROGTarget.c | 118 +++++++++++++------
 Projects/AVRISP-MKII/Lib/XPROG/XPROGTarget.h |   2 +-
 8 files changed, 122 insertions(+), 66 deletions(-)

diff --git a/LUFA/ManPages/ChangeLog.txt b/LUFA/ManPages/ChangeLog.txt
index 9b3154f04..5e2241d42 100644
--- a/LUFA/ManPages/ChangeLog.txt
+++ b/LUFA/ManPages/ChangeLog.txt
@@ -8,6 +8,16 @@
   *
   *  \section Sec_ChangeLogXXXXXX Version XXXXXX
   *
+  *  <b>New:</b>
+  *  - (None)
+  *
+  *  <b>Changed:</b>
+  *  - AVRISP programmer project now has a more robust timeout system, allowing for a doubling of the software USART speed
+  *    for PDI and TPI programming
+  *
+  *  <b>Fixed:</b>
+  *  - (None)
+  *
   *  \section Sec_ChangeLog100219 Version 100219
   *
   *  <b>New:</b>
diff --git a/LUFA/ManPages/MigrationInformation.txt b/LUFA/ManPages/MigrationInformation.txt
index 169b7870a..262364070 100644
--- a/LUFA/ManPages/MigrationInformation.txt
+++ b/LUFA/ManPages/MigrationInformation.txt
@@ -13,6 +13,7 @@
  * \section Sec_MigrationXXXXXX Migrating from 100219 to XXXXXX
  *
  * \section Sec_Migration100219 Migrating from 091223 to 100219
+ *    - (None)
  *
  *  <b>Non-USB Library Components</b>
  *    - Due to some ADC channels not being identical to their ADC MUX selection masks for single-ended conversions on some AVR models,
diff --git a/Projects/AVRISP-MKII/Lib/V2Protocol.c b/Projects/AVRISP-MKII/Lib/V2Protocol.c
index 8d8f2003f..cea42eae5 100644
--- a/Projects/AVRISP-MKII/Lib/V2Protocol.c
+++ b/Projects/AVRISP-MKII/Lib/V2Protocol.c
@@ -42,14 +42,6 @@ uint32_t CurrentAddress;
 /** Flag to indicate that the next read/write operation must update the device's current address */
 bool MustSetAddress;
 
-
-/** ISR for the management of the command execution timeout counter */
-ISR(TIMER0_COMPA_vect, ISR_BLOCK)
-{
-	if (TimeoutMSRemaining)
-	  TimeoutMSRemaining--;
-}
-
 /** Initializes the hardware and software associated with the V2 protocol command handling. */
 void V2Protocol_Init(void)
 {
@@ -76,10 +68,6 @@ void V2Protocol_ProcessCommand(void)
 {
 	uint8_t V2Command = Endpoint_Read_Byte();
 	
-	/* Set total command processing timeout value, enable timeout management interrupt */
-	TimeoutMSRemaining = COMMAND_TIMEOUT_MS;
-	TIMSK0 |= (1 << OCIE0A);
-
 	switch (V2Command)
 	{
 		case CMD_SIGN_ON:
@@ -139,9 +127,6 @@ void V2Protocol_ProcessCommand(void)
 			V2Protocol_UnknownCommand(V2Command);
 			break;
 	}
-		
-	/* Disable timeout management interrupt once processing has completed */
-	TIMSK0 &= ~(1 << OCIE0A);
 
 	Endpoint_WaitUntilReady();
 	Endpoint_SetEndpointDirection(ENDPOINT_DIR_OUT);
diff --git a/Projects/AVRISP-MKII/Lib/V2Protocol.h b/Projects/AVRISP-MKII/Lib/V2Protocol.h
index d67fb3dad..97fea471b 100644
--- a/Projects/AVRISP-MKII/Lib/V2Protocol.h
+++ b/Projects/AVRISP-MKII/Lib/V2Protocol.h
@@ -64,12 +64,6 @@
 		/** Programmer ID string, returned to the host during the CMD_SIGN_ON command processing */
 		#define PROGRAMMER_ID              "AVRISP_MK2"
 		
-		/** Timeout period for each issued command from the host before it is aborted */
-		#define COMMAND_TIMEOUT_MS         200
-		
-		/** Command timeout counter register, GPIOR for speed */
-		#define TimeoutMSRemaining         GPIOR0
-		
 		/** MUX mask for the VTARGET ADC channel number */
 		#define VTARGET_ADC_CHANNEL_MASK   _GETADCMUXMASK(ADC_CHANNEL, VTARGET_ADC_CHANNEL)
 
diff --git a/Projects/AVRISP-MKII/Lib/XPROG/TINYNVM.c b/Projects/AVRISP-MKII/Lib/XPROG/TINYNVM.c
index 0ab297538..428469df7 100644
--- a/Projects/AVRISP-MKII/Lib/XPROG/TINYNVM.c
+++ b/Projects/AVRISP-MKII/Lib/XPROG/TINYNVM.c
@@ -77,14 +77,19 @@ static void TINYNVM_SendWriteNVMRegister(const uint8_t Address)
 bool TINYNVM_WaitWhileNVMBusBusy(void)
 {
 	/* Poll the STATUS register to check to see if NVM access has been enabled */
+	uint8_t TimeoutMSRemaining = 100;
 	while (TimeoutMSRemaining)
 	{
 		/* Send the SLDCS command to read the TPI STATUS register to see the NVM bus is active */
 		XPROGTarget_SendByte(TPI_CMD_SLDCS | TPI_STATUS_REG);
 		if (XPROGTarget_ReceiveByte() & TPI_STATUS_NVM)
+		  return true;
+
+		/* Manage software timeout */
+		if (TIFR0 & (1 << OCF0A))
 		{
-			TimeoutMSRemaining = COMMAND_TIMEOUT_MS;
-			return true;
+			TIFR0 |= (1 << OCF0A);
+			TimeoutMSRemaining--;
 		}
 	}
 
@@ -99,6 +104,7 @@ bool TINYNVM_WaitWhileNVMBusBusy(void)
 bool TINYNVM_WaitWhileNVMControllerBusy(void)
 {
 	/* Poll the STATUS register to check to see if NVM access has been enabled */
+	uint8_t TimeoutMSRemaining = 100;
 	while (TimeoutMSRemaining)
 	{
 		/* Send the SIN command to read the TPI STATUS register to see the NVM bus is busy */
@@ -106,9 +112,13 @@ bool TINYNVM_WaitWhileNVMControllerBusy(void)
 
 		/* Check to see if the BUSY flag is still set */
 		if (!(XPROGTarget_ReceiveByte() & (1 << 7)))
+		  return true;
+
+		/* Manage software timeout */
+		if (TIFR0 & (1 << OCF0A))
 		{
-			TimeoutMSRemaining = COMMAND_TIMEOUT_MS;
-			return true;
+			TIFR0 |= (1 << OCF0A);
+			TimeoutMSRemaining--;
 		}
 	}
 
diff --git a/Projects/AVRISP-MKII/Lib/XPROG/XMEGANVM.c b/Projects/AVRISP-MKII/Lib/XPROG/XMEGANVM.c
index fc98cfceb..6ef59db37 100644
--- a/Projects/AVRISP-MKII/Lib/XPROG/XMEGANVM.c
+++ b/Projects/AVRISP-MKII/Lib/XPROG/XMEGANVM.c
@@ -72,14 +72,19 @@ static void XMEGANVM_SendNVMRegAddress(const uint8_t Register)
 bool XMEGANVM_WaitWhileNVMBusBusy(void)
 {
 	/* Poll the STATUS register to check to see if NVM access has been enabled */
+	uint8_t TimeoutMSRemaining = 100;
 	while (TimeoutMSRemaining)
 	{
 		/* Send the LDCS command to read the PDI STATUS register to see the NVM bus is active */
 		XPROGTarget_SendByte(PDI_CMD_LDCS | PDI_STATUS_REG);
 		if (XPROGTarget_ReceiveByte() & PDI_STATUS_NVM)
+		  return true;
+
+		/* Manage software timeout */
+		if (TIFR0 & (1 << OCF0A))
 		{
-			TimeoutMSRemaining = COMMAND_TIMEOUT_MS;
-			return true;
+			TIFR0 |= (1 << OCF0A);
+			TimeoutMSRemaining--;
 		}
 	}
 	
@@ -94,6 +99,7 @@ bool XMEGANVM_WaitWhileNVMBusBusy(void)
 bool XMEGANVM_WaitWhileNVMControllerBusy(void)
 {
 	/* Poll the NVM STATUS register while the NVM controller is busy */
+	uint8_t TimeoutMSRemaining = 100;
 	while (TimeoutMSRemaining)
 	{
 		/* Send a LDS command to read the NVM STATUS register to check the BUSY flag */
@@ -102,9 +108,13 @@ bool XMEGANVM_WaitWhileNVMControllerBusy(void)
 		
 		/* Check to see if the BUSY flag is still set */
 		if (!(XPROGTarget_ReceiveByte() & (1 << 7)))
+		  return true;
+
+		/* Manage software timeout */
+		if (TIFR0 & (1 << OCF0A))
 		{
-			TimeoutMSRemaining = COMMAND_TIMEOUT_MS;
-			return true;
+			TIFR0 |= (1 << OCF0A);
+			TimeoutMSRemaining--;
 		}
 	}
 	
diff --git a/Projects/AVRISP-MKII/Lib/XPROG/XPROGTarget.c b/Projects/AVRISP-MKII/Lib/XPROG/XPROGTarget.c
index e77d77bd5..45c1d225d 100644
--- a/Projects/AVRISP-MKII/Lib/XPROG/XPROGTarget.c
+++ b/Projects/AVRISP-MKII/Lib/XPROG/XPROGTarget.c
@@ -49,50 +49,59 @@ volatile uint16_t           SoftUSART_Data;
 #define SoftUSART_BitCount  GPIOR2
 
 
-/** ISR to manage the PDI software USART when bit-banged PDI USART mode is selected. */
+/** ISR to manage the rising edge of the PDI/TPI software USART when bit-banged USART mode is selected. */
 ISR(TIMER1_COMPA_vect, ISR_BLOCK)
 {
 	/* Toggle CLOCK pin in a single cycle (see AVR datasheet) */
 	BITBANG_PDICLOCK_PIN |= BITBANG_PDICLOCK_MASK;
+	TIFR1 |= (1 << OCF1B);
+	TIMSK1 = (1 << OCIE1B);
 
 	/* If not sending or receiving, just exit */
 	if (!(SoftUSART_BitCount))
 	  return;
 
-	/* Check to see if we are at a rising or falling edge of the clock */
-	if (BITBANG_PDICLOCK_PORT & BITBANG_PDICLOCK_MASK)
-	{
-		/* If at rising clock edge and we are in send mode, abort */
-		if (IsSending)
-		  return;
-		  
-		/* Wait for the start bit when receiving */
-		if ((SoftUSART_BitCount == BITS_IN_USART_FRAME) && (BITBANG_PDIDATA_PIN & BITBANG_PDIDATA_MASK))
-		  return;
-	
-		/* Shift in the bit one less than the frame size in position, so that the start bit will eventually
-		 * be discarded leaving the data to be byte-aligned for quick access (subtract 9 as we are ORing to the MSB) */
-		if (BITBANG_PDIDATA_PIN & BITBANG_PDIDATA_MASK)
-		  ((uint8_t*)&SoftUSART_Data)[1] |= (1 << (BITS_IN_USART_FRAME - 9));
+	/* If at rising clock edge and we are in send mode, abort */
+	if (IsSending)
+	  return;
+	  
+	/* Wait for the start bit when receiving */
+	if ((SoftUSART_BitCount == BITS_IN_USART_FRAME) && (BITBANG_PDIDATA_PIN & BITBANG_PDIDATA_MASK))
+	  return;
 
-		SoftUSART_Data >>= 1;
-		SoftUSART_BitCount--;
-	}
-	else
-	{
-		/* If at falling clock edge and we are in receive mode, abort */
-		if (!IsSending)
-		  return;
+	/* Shift in the bit one less than the frame size in position, so that the start bit will eventually
+	 * be discarded leaving the data to be byte-aligned for quick access (subtract 9 as we are ORing to the MSB) */
+	if (BITBANG_PDIDATA_PIN & BITBANG_PDIDATA_MASK)
+	  ((uint8_t*)&SoftUSART_Data)[1] |= (1 << (BITS_IN_USART_FRAME - 9));
 
-		/* Set the data line to the next bit value */
-		if (((uint8_t*)&SoftUSART_Data)[0] & 0x01)
-		  BITBANG_PDIDATA_PORT |=  BITBANG_PDIDATA_MASK;
-		else
-		  BITBANG_PDIDATA_PORT &= ~BITBANG_PDIDATA_MASK;		  
+	SoftUSART_Data >>= 1;
+	SoftUSART_BitCount--;
+}
 
-		SoftUSART_Data >>= 1;
-		SoftUSART_BitCount--;
-	}
+/** ISR to manage the falling edge of the PDI/TPI software USART when bit-banged USART mode is selected. */
+ISR(TIMER1_COMPB_vect, ISR_BLOCK)
+{
+	/* Toggle CLOCK pin in a single cycle (see AVR datasheet) */
+	BITBANG_PDICLOCK_PIN |= BITBANG_PDICLOCK_MASK;
+	TIFR1 |= (1 << OCF1A);
+	TIMSK1 = (1 << OCIE1A);
+
+	/* If not sending or receiving, just exit */
+	if (!(SoftUSART_BitCount))
+	  return;
+
+	/* If at falling clock edge and we are in receive mode, abort */
+	if (!IsSending)
+	  return;
+
+	/* Set the data line to the next bit value */
+	if (((uint8_t*)&SoftUSART_Data)[0] & 0x01)
+	  BITBANG_PDIDATA_PORT |=  BITBANG_PDIDATA_MASK;
+	else
+	  BITBANG_PDIDATA_PORT &= ~BITBANG_PDIDATA_MASK;		  
+
+	SoftUSART_Data >>= 1;
+	SoftUSART_BitCount--;
 }
 
 /** ISR to manage the TPI software USART when bit-banged TPI USART mode is selected. */
@@ -172,7 +181,9 @@ void XPROGTarget_EnableTargetPDI(void)
 
 	/* Fire timer compare channel A ISR to manage the software USART */
 	OCR1A   = BITS_BETWEEN_USART_CLOCKS;
+	OCR1B   = BITS_BETWEEN_USART_CLOCKS;
 	TCCR1B  = (1 << WGM12) | (1 << CS10);
+	TCCR1C  = (1 << FOC1B);
 	TIMSK1  = (1 << OCIE1A);
 #endif
 
@@ -240,6 +251,10 @@ void XPROGTarget_DisableTargetPDI(void)
 	DDRD  &= ~((1 << 5) | (1 << 3));
 	PORTD &= ~((1 << 5) | (1 << 3) | (1 << 2));
 #else
+	/* Turn off software USART management timer */
+	TCCR1B = 0;
+	TCCR1C = 0;
+
 	/* Set /RESET high for a one millisecond to ensure target device is restarted */
 	BITBANG_PDICLOCK_PORT |= BITBANG_PDICLOCK_MASK;
 	_delay_ms(1);
@@ -250,7 +265,7 @@ void XPROGTarget_DisableTargetPDI(void)
 	
 	/* Tristate DATA and CLOCK lines */
 	BITBANG_PDIDATA_PORT  &= ~BITBANG_PDIDATA_MASK;
-	BITBANG_PDICLOCK_PORT &= ~BITBANG_PDICLOCK_MASK;
+	BITBANG_PDICLOCK_PORT &= ~BITBANG_PDICLOCK_MASK;	
 #endif
 }
 
@@ -270,6 +285,9 @@ void XPROGTarget_DisableTargetTPI(void)
 	DDRD  &= ~((1 << 5) | (1 << 3));
 	PORTD &= ~((1 << 5) | (1 << 3) | (1 << 2));
 #else
+	/* Turn off software USART management timer */
+	TCCR1B = 0;
+
 	/* Set DATA and CLOCK lines to inputs */
 	BITBANG_TPIDATA_DDR   &= ~BITBANG_TPIDATA_MASK;
 	BITBANG_TPICLOCK_DDR  &= ~BITBANG_TPICLOCK_MASK;
@@ -332,12 +350,31 @@ uint8_t XPROGTarget_ReceiveByte(void)
 
 #if defined(XPROG_VIA_HARDWARE_USART)
 	/* Wait until a byte has been received before reading */
-	while (!(UCSR1A & (1 << RXC1)) && TimeoutMSRemaining);
+	uint8_t TimeoutMSRemaining = 100;
+	while (!(UCSR1A & (1 << RXC1)) && TimeoutMSRemaining)
+	{
+		/* Manage software timeout */
+		if (TIFR0 & (1 << OCF0A))
+		{
+			TIFR0 |= (1 << OCF0A);
+			TimeoutMSRemaining--;
+		}	
+	}
+	
 	return UDR1;
 #else
 	/* Wait until a byte has been received before reading */
 	SoftUSART_BitCount = BITS_IN_USART_FRAME;
-	while (SoftUSART_BitCount && TimeoutMSRemaining);
+	uint8_t TimeoutMSRemaining = 100;
+	while (SoftUSART_BitCount && TimeoutMSRemaining)
+	{
+		/* Manage software timeout */
+		if (TIFR0 & (1 << OCF0A))
+		{
+			TIFR0 |= (1 << OCF0A);
+			TimeoutMSRemaining--;
+		}
+	}
 
 	/* Throw away the parity and stop bits to leave only the data (start bit is already discarded) */
 	return (uint8_t)SoftUSART_Data;
@@ -431,7 +468,16 @@ static void XPROGTarget_SetRxMode(void)
 	}
 	
 	/* Wait until DATA line has been pulled up to idle by the target */
-	while (!(BITBANG_PDIDATA_PIN & BITBANG_PDIDATA_MASK) && TimeoutMSRemaining);
+	uint8_t TimeoutMSRemaining = 100;
+	while (!(BITBANG_PDIDATA_PIN & BITBANG_PDIDATA_MASK) && TimeoutMSRemaining)
+	{
+		/* Manage software timeout */
+		if (TIFR0 & (1 << OCF0A))
+		{
+			TIFR0 |= (1 << OCF0A);
+			TimeoutMSRemaining--;
+		}
+	}	
 #endif
 
 	IsSending = false;
diff --git a/Projects/AVRISP-MKII/Lib/XPROG/XPROGTarget.h b/Projects/AVRISP-MKII/Lib/XPROG/XPROGTarget.h
index bc2953dd2..d08a8b653 100644
--- a/Projects/AVRISP-MKII/Lib/XPROG/XPROGTarget.h
+++ b/Projects/AVRISP-MKII/Lib/XPROG/XPROGTarget.h
@@ -81,7 +81,7 @@
 		#endif
 		
 		/** Number of cycles between each clock when software USART mode is used */
-		#define BITS_BETWEEN_USART_CLOCKS  200
+		#define BITS_BETWEEN_USART_CLOCKS  100
 		
 		/** Total number of bits in a single USART frame */
 		#define BITS_IN_USART_FRAME        12
-- 
GitLab