Skip to content
Snippets Groups Projects
Commit bb9fb105 authored by Dean Camera's avatar Dean Camera
Browse files

Add better documentation to the Software UART code in the XPLAINBridge project.

parent 1c407b96
No related branches found
No related tags found
No related merge requests found
...@@ -39,85 +39,121 @@ ...@@ -39,85 +39,121 @@
#include "SoftUART.h" #include "SoftUART.h"
static uint8_t TX_BitsRemaining, TX_Data; /** Total number of bits remaining to be sent in the current frame */
static uint8_t RX_BitMask, RX_Data; 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;
/** Temporary data variable to hold the byte being received as it is shifted in */
static uint8_t RX_Data;
/** Initializes the software UART, ready for data transmission and reception into the global ring buffers. */
void SoftUART_Init(void) void SoftUART_Init(void)
{ {
OCR1B = TCNT1 + 1; // force first compare /* Set TX pin to output high, enable RX pullup */
TCCR1B = (1 << CS10); // CLK/1, T1 mode 0 STXPORT |= (1 << STX);
TCCR1C = (1 << FOC1B); STXDDR |= (1 << STX);
TIMSK1 = (1 << OCIE1B); // enable tx and wait for start SRXPORT |= (1 << SRX);
EICRA = (1 << ISC01); // -ve edge
EIMSK = (1 << INT0); // enable INT0 interrupt /* Enable INT0 for the detection of incomming start bits that signal the start of a byte */
EICRA = (1 << ISC01);
EIMSK = (1 << INT0);
STXPORT |= (1 << STX); // TX output /* Ensure that when the timer is enabled the transmission ISR runs immediately */
STXDDR |= (1 << STX); // TX output OCR1B = TCNT1 + 1;
SRXPORT |= (1 << SRX); // pullup on INT0
/* Start timer 1 with transmission channel force-enabled so that it will immediatly fire */
TCCR1C = (1 << FOC1B);
TIMSK1 = (1 << OCIE1B);
TCCR1B = (1 << CS10);
} }
/* ISR to detect the start of a bit being sent to the software UART. */ /** ISR to detect the start of a bit being sent to the software UART. */
ISR(INT0_vect) ISR(INT0_vect)
{ {
OCR1A = TCNT1 + ((BIT_TIME * 3) / 2) - 1; // scan 1.5 bits after start /* Set reception channel to fire 1.5 bits past the beginning of the start bit */
OCR1A = TCNT1 + ((BIT_TIME * 3) / 2) - 1;
RX_Data = 0; // clear bit storage /* Clear the received data temporary variable, reset the current received bit position mask */
RX_BitMask = (1 << 0); // bit mask RX_Data = 0;
RX_BitMask = (1 << 0);
TIFR1 = (1 << OCF1A); // clear pending interrupt /* Clear reception channel ISR flag in case it is pending */
TIFR1 = (1 << OCF1A);
if (!(SRXPIN & (1 << SRX))) // still low /* Check that the start bit is still low to prevent noise from triggering a reception */
if (!(SRXPIN & (1 << SRX)))
{ {
TIMSK1 = (1 << OCIE1A) | (1 << OCIE1B); // wait for first bit /* Still low, enable both send and receive channels */
TIMSK1 = (1 << OCIE1A) | (1 << OCIE1B);
/* Clear the start bit detection ISR flag if it is pending */
EIMSK &= ~(1 << INT0); EIMSK &= ~(1 << INT0);
} }
} }
/* ISR to manage the reception of bits to the software UART. */ /** ISR to manage the reception of bits to the software UART. */
ISR(TIMER1_COMPA_vect) ISR(TIMER1_COMPA_vect)
{ {
/* Move the reception ISR compare position one bit ahead */
OCR1A += BIT_TIME;
/* Check if reception has finished */
if (RX_BitMask) if (RX_BitMask)
{ {
/* Store next bit into the received data variable */
if (SRXPIN & (1 << SRX)) if (SRXPIN & (1 << SRX))
RX_Data |= RX_BitMask; RX_Data |= RX_BitMask;
/* Shift the current received bit mask to the next bit position */
RX_BitMask <<= 1; RX_BitMask <<= 1;
OCR1A += BIT_TIME; // next bit slice
} }
else else
{ {
/* Reception complete, store the received byte */
RingBuffer_Insert(&UARTtoUSB_Buffer, RX_Data); RingBuffer_Insert(&UARTtoUSB_Buffer, RX_Data);
TIMSK1 = (1 << OCIE1B); // enable tx and wait for start /* Disable the reception ISR as all data has now been received, re-enable start bit detection ISR */
EIMSK |= (1 << INT0); // enable START irq TIMSK1 = (1 << OCIE1B);
EIFR = (1 << INTF0); // clear any pending EIMSK |= (1 << INT0);
EIFR = (1 << INTF0);
} }
} }
/* ISR to manage the transmission of bits via the software UART. */ /** ISR to manage the transmission of bits via the software UART. */
ISR(TIMER1_COMPB_vect) ISR(TIMER1_COMPB_vect)
{ {
OCR1B += BIT_TIME; // next bit slice /* Move the transmission ISR compare position one bit ahead */
OCR1B += BIT_TIME;
/* Check if transmission has finished */
if (TX_BitsRemaining) if (TX_BitsRemaining)
{ {
if (--TX_BitsRemaining != 9) // no start bit /* Check if we are sending a data bit, or the start bit */
if (--TX_BitsRemaining != 9)
{ {
if (TX_Data & (1 << 0)) // test inverted data /* Set the TX line to the value of the next bit in the byte to send */
if (TX_Data & (1 << 0))
STXPORT &= ~(1 << STX); STXPORT &= ~(1 << STX);
else else
STXPORT = (1 << STX); STXPORT |= (1 << STX);
TX_Data >>= 1; // shift zero in from left /* Shift the transmission byte to move the next bit into position */
TX_Data >>= 1;
} }
else else
{ {
/* Start bit - keep TX line low */
STXPORT &= ~(1 << STX); STXPORT &= ~(1 << STX);
} }
} }
else if (USBtoUART_Buffer.Count) else if (USBtoUART_Buffer.Count)
{ {
/* Transmission complete, get the next byte to send (if available) */
TX_Data = ~RingBuffer_Remove(&USBtoUART_Buffer); TX_Data = ~RingBuffer_Remove(&USBtoUART_Buffer);
TX_BitsRemaining = 10; TX_BitsRemaining = 10;
} }
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment