diff --git a/LUFA/ManPages/ChangeLog.txt b/LUFA/ManPages/ChangeLog.txt index 0a2f43a33b..8164f3084b 100644 --- a/LUFA/ManPages/ChangeLog.txt +++ b/LUFA/ManPages/ChangeLog.txt @@ -27,6 +27,7 @@ * - The USB_Device_IsRemoteWakeupSent() and USB_Device_IsUSBSuspended() macros have been deleted, as they are now obsolete * - Rewrote the implementation of the SwapEndian_16() and SwapEndian_32() functions so that they compile down in most instances to * minimal loads and stores rather than complicated shifts + * - The software UART in the XPLAINBridge has been largely altered to try to improve upon its performance and reliability * * Fixed: * - Fixed AVRISP project sending a LOAD EXTENDED ADDRESS command to 128KB AVRs after programming or reading from diff --git a/Projects/XPLAINBridge/Lib/SoftUART.c b/Projects/XPLAINBridge/Lib/SoftUART.c index 02223af982..458a505cd2 100644 --- a/Projects/XPLAINBridge/Lib/SoftUART.c +++ b/Projects/XPLAINBridge/Lib/SoftUART.c @@ -45,8 +45,8 @@ static uint8_t TX_BitsRemaining; /** Temporary data variable to hold the byte being transmitted as it is shifted out */ static uint8_t TX_Data; -/** Current bit mask of the bit being shifted into the received data byte */ -static uint8_t RX_BitMask; +/** Total number of bits remaining to be received in the current frame */ +static uint8_t RX_BitsRemaining; /** Temporary data variable to hold the byte being received as it is shifted in */ static uint8_t RX_Data; @@ -63,89 +63,83 @@ void SoftUART_Init(void) EICRA = (1 << ISC01); EIMSK = (1 << INT0); - /* Start software UART transmission and reception timers */ + /* Set reception timer compare period and enable compare ISR */ + OCR1A = BIT_TIME; + TIMSK1 = (1 << OCIE1A); + + /* Set transmission timer compare period, enable compare ISR and start the timer */ + OCR3A = BIT_TIME; TIMSK3 = (1 << OCIE3A); - TCCR3B = (1 << CS30); - TCCR1B = (1 << CS10); + TCCR3B = ((1 << CS30) | (1 << WGM32)); } /** ISR to detect the start of a bit being sent to the software UART. */ ISR(INT0_vect, ISR_BLOCK) { - /* Set reception channel to fire 1.5 bits past the beginning of the start bit */ - OCR1A = TCNT1 + (BIT_TIME + (BIT_TIME / 2)); - - /* Clear the received data temporary variable, reset the current received bit position mask */ - RX_Data = 0; - RX_BitMask = (1 << 0); + /* Reset and start the reception timer */ + TCNT1 = 0; + TCCR1B = ((1 << CS10) | (1 << WGM12)); - /* Clear reception channel ISR flag and enable the bit reception ISR */ - TIFR1 = (1 << OCF1A); - TIMSK1 = (1 << OCIE1A); + /* Reset the number of reception bits remaining counter */ + RX_BitsRemaining = 8; /* Disable start bit detection ISR while the next byte is received */ - EIMSK &= ~(1 << INT0); + EIMSK = 0; } /** ISR to manage the reception of bits to the software UART. */ ISR(TIMER1_COMPA_vect, ISR_BLOCK) { - /* Move the reception ISR compare position one bit ahead */ - OCR1A += BIT_TIME; + /* Cache the current RX pin value for later checking */ + uint8_t SRX_Cached = (SRXPIN & (1 << SRX)); /* Check if reception has finished */ - if (RX_BitMask) + if (RX_BitsRemaining) { - /* Store next bit into the received data variable */ - if (SRXPIN & (1 << SRX)) - RX_Data |= RX_BitMask; - /* Shift the current received bit mask to the next bit position */ - RX_BitMask <<= 1; + RX_Data >>= 1; + RX_BitsRemaining--; + + /* Store next bit into the received data variable */ + if (SRX_Cached) + RX_Data |= (1 << 7); } else { - /* Reception complete, store the received byte */ - RingBuffer_Insert(&UARTtoUSB_Buffer, RX_Data); - - /* Disable the reception ISR as all data has now been received, re-enable start bit detection ISR */ - TIMSK1 = 0; + /* Disable the reception timer as all data has now been received, re-enable start bit detection ISR */ + TCCR1B = 0; EIFR = (1 << INTF0); EIMSK = (1 << INT0); + + /* Reception complete, store the received byte if stop bit valid */ + if (SRX_Cached) + RingBuffer_Insert(&UARTtoUSB_Buffer, RX_Data); } } /** ISR to manage the transmission of bits via the software UART. */ ISR(TIMER3_COMPA_vect, ISR_NOBLOCK) { - /* Move the transmission ISR compare position one bit ahead */ - OCR3A += BIT_TIME; - /* Check if transmission has finished */ if (TX_BitsRemaining) { - /* Check if we are sending a data bit, or the start bit */ - if (--TX_BitsRemaining != 9) - { - /* Set the TX line to the value of the next bit in the byte to send */ - if (TX_Data & (1 << 0)) - STXPORT &= ~(1 << STX); - else - STXPORT |= (1 << STX); - - /* Shift the transmission byte to move the next bit into position */ - TX_Data >>= 1; - } + /* Set the TX line to the value of the next bit in the byte to send */ + if (TX_Data & (1 << 0)) + STXPORT &= ~(1 << STX); else - { - /* Start bit - keep TX line low */ - STXPORT &= ~(1 << STX); - } + STXPORT |= (1 << STX); + + /* Shift the transmission byte to move the next bit into position and decrement the bits remaining counter */ + TX_Data >>= 1; + TX_BitsRemaining--; } else if (USBtoUART_Buffer.Count) { + /* Start bit - TX line low */ + STXPORT &= ~(1 << STX); + /* Transmission complete, get the next byte to send (if available) */ - TX_Data = ~RingBuffer_Remove(&USBtoUART_Buffer); - TX_BitsRemaining = 10; + TX_Data = ~RingBuffer_Remove(&USBtoUART_Buffer); + TX_BitsRemaining = 9; } -} +} diff --git a/Projects/XPLAINBridge/Lib/SoftUART.h b/Projects/XPLAINBridge/Lib/SoftUART.h index a685a6d8fa..a107d48a8f 100644 --- a/Projects/XPLAINBridge/Lib/SoftUART.h +++ b/Projects/XPLAINBridge/Lib/SoftUART.h @@ -43,7 +43,7 @@ /* Macros: */ #define BAUD 9600 - #define BIT_TIME ((F_CPU + (BAUD / 2)) / BAUD) + #define BIT_TIME ((F_CPU / BAUD) - 1) #define SRX PD0 #define SRXPIN PIND diff --git a/Projects/XPLAINBridge/XPLAINBridge.c b/Projects/XPLAINBridge/XPLAINBridge.c index 4ba9fd9918..c08dfe980c 100644 --- a/Projects/XPLAINBridge/XPLAINBridge.c +++ b/Projects/XPLAINBridge/XPLAINBridge.c @@ -76,7 +76,6 @@ RingBuff_t UARTtoUSB_Buffer; int main(void) { SetupHardware(); - V2Protocol_Init(); RingBuffer_InitBuffer(&USBtoUART_Buffer); RingBuffer_InitBuffer(&UARTtoUSB_Buffer); @@ -127,9 +126,15 @@ void UARTBridge_Task(void) if (CDC_Device_BytesReceived(&VirtualSerial_CDC_Interface)) RingBuffer_Insert(&USBtoUART_Buffer, CDC_Device_ReceiveByte(&VirtualSerial_CDC_Interface)); - /* Read bytes from the UART receive buffer into the USB IN endpoint */ - if (UARTtoUSB_Buffer.Count) - CDC_Device_SendByte(&VirtualSerial_CDC_Interface, RingBuffer_Remove(&UARTtoUSB_Buffer)); + /* Check if the software UART flush timer has expired */ + if (TIFR0 & (1 << TOV0)) + { + TIFR0 |= (1 << TOV0); + + /* Read bytes from the UART receive buffer into the USB IN endpoint */ + while (UARTtoUSB_Buffer.Count) + CDC_Device_SendByte(&VirtualSerial_CDC_Interface, RingBuffer_Remove(&UARTtoUSB_Buffer)); + } CDC_Device_USBTask(&VirtualSerial_CDC_Interface); } @@ -174,6 +179,9 @@ void EVENT_USB_Device_ConfigurationChanged(void) if (CurrentFirmwareMode == MODE_USART_BRIDGE) { EndpointConfigSuccess &= CDC_Device_ConfigureEndpoints(&VirtualSerial_CDC_Interface); + + /* Configure the UART flush timer */ + TCCR0B = ((1 << CS02) | (1 << CS00)); } else { @@ -186,6 +194,9 @@ void EVENT_USB_Device_ConfigurationChanged(void) ENDPOINT_DIR_IN, AVRISP_DATA_EPSIZE, ENDPOINT_BANK_SINGLE); #endif + + /* Configure the V2 protocol packet handler */ + V2Protocol_Init(); } if (EndpointConfigSuccess)