Full Version : SWUART Full Duplex Software UART (GCC)
avr >>COMMUNICATIONS & WEB PROJECTS >>SWUART Full Duplex Software UART (GCC)


AVR_Admin- 04-16-2006
Full duplex SW UART

This is an implementation of a full duplex software UART i made when i was bored. =)

It uses one 8 bit TC, can share it when not active, and 6 bytes of memory.

I had the TINY13 in the back of my head when making it but it but it can simply be ported to any AVR.

CODE
/* Data defines
PORT
TX_MASK
PINS
RX_MASK
OCR  //TC Output Compare Register
TCNT //Acutal counter register
TCRB // TC control register b (register with clk selection options)


*/

/* Method defines
HANDEL_UART_DATA(data) //called when a data byte has sucessfully bin reseved
SETUP_TC //Setup the TC for the uart speed and TCNT = 0;
*/

/* Optional defines
FLIP_LEVELS //default rest 0, flipped to rest 1
TAKE  //Called when uart takes TC
GIVE  //Called when uart stops using TC
SENT_BYTE //Called when a data byte has bin sent
BAUD //BAUDrate 9600 baud default
CLK //clockrate default 8000000 (8MHz)
DIVIDER //Devision factor to be used default 8
TWO_STOPBITS //By default one stopbit is used by defining this two will be used
*/

// User TODOs: set interup vectors and DDRX registers, call UART_INIT() define options and funks

#ifndef BAUD
#define BAUD 9600
#endif

#ifndef CLK
#define CLK 8000000
#endif

#ifndef DIVIDER
#define DIVIDER 8
#endif

#define TIX_PER_BIT (CLK / DIVIDER / BAUD)

#ifndef FLIP_LEVELS
#define REST_O 0
#define ACTIVE_O TX_MASK
#define REST_I 0
#define ACTIVE_I RX_MASK
#else
#define REST_O TX_MASK
#define ACTIVE_O 0
#define REST_I RX_MASK
#define ACTIVE_I 0
#endif

uint8 flags;
uint8 nextFrame:
uint8 cntrs;
uint8 O_buffer;
uint8 I_buffer;
uint8 stack;

#define STACK_PUSH(data)         (stack = (data))
#define STACK_PEEK               (stack)
#define STACK_POP(target)        ((target) = stack)

#define NEXT_EVENT_IS_SEND_FLAG  4
#define NEXT_EVENT_IS_SEND       (flags & NEXT_EVENT_IS_SEND_FLAG)
#define SET_NEXT_EVENT_IS_SEND   (flags |= NEXT_EVENT_IS_SEND_FLAG)
#define SET_NEXT_EVENT_IS_RESEVE (flags &= ~NEXT_EVENT_IS_SEND_FLAG)

#define SENDING_FLAG             2
#define SENDING                  (flags & SENDING_FLAG)
#define START_SENDING            (flags |= SENDING_FLAG)
#define STOP_SENDING             (fags &= ~SENDING_FLAG)

#define RESEVING_FLAG            1
#define RESEVING                 (flags & RESEVING_FLAG)
#define START_RESEVING           (flags |= RESEVING_FLAG)
#define STOP_RESEVING            (flags &= ~RESEVING_FLAG)

#define UART_IS_ACTIVE           (flags & (RESEVING_FLAG | SENING_FLAG))

#define SEND_CNTR                (cntrs & 0x0F)
#define INC_SEND_CNTR            cntrs++
#define CLEAR_SEND_CNTR          (cntrs = cntrs &0xF0)

#define RES_CNTR                 (cntrs & 0xF0)
#define INC_RES_CNTR             (cntrs += 0x10)
#define CLEAR_RES_CNTR           (cntrs = cntrs & 0x0F)

#define UART_INIT()              \
 nextFrame = 0;                 \
 flags = 0;                     \
 cnters = 0;                    \
 PORT = (PORT & (~TX_MASK))

#define STOP_TC TCRB = 0;


void UART_SEND(uint8 data)
{
 if (!SENDING)
 {
   CLEAR_SEND_CNTR;
   O_buffer = data;
   nextFrame = REST_O;
   START_SENDING;
   if(!RESEVING)
   {
#ifdef TAKE
     TAKE;
#endif
     SETUP_TC;
     OCR = TIX_PER_BIT;
     SET_NEXT_EVENT_IS_SEND;
   }
   else
   {
     STACK_PUSH(TIX_PER_BIT - OCR + TCNT);
     if (STACK_PEEK < 2)
     {
       //STACK_POP();
       STACK_PUSH(2);
     }
   }
 }
}

void OnPinchange(void)
{
 if (!RESEVING && ((PINS & RX_MASK) == ACTIVE_I))
 {
   CLEAR_RES_CNTR;
   I_buffer = 0;
   START_RESEVING;
   if (!SENDING)
   {
#ifdef TAKE
     TAKE;
#endif
     SETUP_TC;
     OCR = TIX_PER_BIT / 2;
     SET_NEXT_EVENT_IS_RESEVE;
   }
   else
   {
     if ((TIX_PER_BIT / 2) > (OCR - TCNT - 2))
     {
       STACK_PUSH(TIX_PER_BIT / 2 - OCR + TCNT);
     }
     else
     {
       STACK_PUSH(OCR - TCNT - TIX_PER_BIT / 2);
       OCR = TIX_PER_BIT / 2 + TCNT;
     }
     if (STACK_PEEK <2)
     {
       //STACK_POP();
       STACK_PUSH(2);
     }
   }
 }
}

void OnOCM(void)
{
 if (NEXT_EVENT_IS_SEND)
 {
   PORT = (PORT & (~TX_MASK)) | nextFrame;

   if (RESEVING)
   {
     STACK_POP(OCR);
     SET_NEXT_EVENT_IS_RESEVE;
     STACK_PUSH(TIX_PER_BIT - OCR);
   }
   else
   {
     OCR = TIX_PER_BIT;
   }

   if (SEND_CNTR == 0)
   {// Send startbit
     nextFrame = ACTIVE_O;
   }
   else if (SEND_CNTR < 9)
   {//Send 8 bits
     nextFrame = REST_O;
     if (O_buffer & 1)
     {
       nextFrame = ACTIVE_O;
     }
     O_buffer >>= 1;
   }
#ifdef TWO_STOPBITS
   else if (SEND_CNTR < 0x0B)
#else
   else if (SEND_CNTR < 0x0A)
#endif
   {
     nextFrame = REST_O;
   }
   else
   {
     STOP_SENDING;

     if (!RESEVING)
     {
       STOP_TC;

#ifdef GIVE
       GIVE;
#endif
     }

#ifdef SENT_BYTE
     SENT_BYTE;
#endif

   }
   INC_SEND_CNTR;
 }
 else
 {

   if (SENDING)
   {
     STACK_POP(OCR);
     SET_NEXT_EVENT_IS_SEND;
     STACK_PUSH(TIX_PER_BIT - OCR);
   }
   else
   {
     OCR = TIX_PER_BIT;
   }

   if (RES_CNTR == 0)
   {//Read startbit
     if ((PINS & RX_MASK) != ACTIVE_I)
     {
       STOP_RESEVING;//Error

       if (!SENDING)
       {
         STOP_TC
#ifdef GIVE
         GIVE;
#endif
       }
     }
   }
   else if (RES_CNTR < 0x90)
   {//Read 8 bits
     if ((PINS & RX_MASK) == ACTIVE_I)
     {
       I_buffer += 0x80;
     }
     I_buffer >>= 1;
   }
#ifdef TWO_STOPBITS
   else if (RES_CNTR < 0xB0)
#else
   else if (RES_CNTR < 0xA0)
#endif
   {//Read stopbit
     if ((PINS & RX_MASK) != REST_I)
     {
       STOP_RESEVING;
       if (!SENDING)
       {
         STOP_TC;
#ifdef GIVE
         GIVE;
#endif
       }
     }
     else
     {
       HANDEL_UART_DATA(I_buffer);
     }
   }
   else
   {
   
     STOP_RESEVING;

     if (!SENDING)
     {
       STOP_TC;
#ifdef GIVE
       GIVE;
#endif
     }
   }
   INC_RES_CNTR;
 }

}



Forumer™ is Voted #1 Free Forum Hosting provider
Build your own community today with the largest message board hosting company.