Commit 22993518 authored by Dean Camera's avatar Dean Camera
Browse files

Major changes to the XPLAINBridge software UART code for performance and...

Major changes to the XPLAINBridge software UART code for performance and reliability. New code reduces the number of missed characters and misread characters.
parent 2b0d93c1
......@@ -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
*
* <b>Fixed:</b>
* - Fixed AVRISP project sending a LOAD EXTENDED ADDRESS command to 128KB AVRs after programming or reading from
......
......@@ -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;
}
}
}
......@@ -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
......
......@@ -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)
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment