Frame format

The frame formats supported by the Atmega is the standard UART frame format, specifically it accepts all 30 combinations of the following as valid frame formats:

 1 start bit

 5, 6, 7, 8, or 9 data bits

 no, even or odd parity bit

 1 or 2 stop bits

 

The frame format used by the USART is set by the UCSZ02:0, UPM01:0 and USBS0 bits in UCSR0B and UCSR0C. The Receiver and Transmitter use the same setting.

The USART Character SiZe (UCSZ02:0) bits select the number of data bits in the frame. The USART Parity mode (UPM01:0) bits enable and set the type of parity bit. The selection between one or two stop bits is done by the USART Stop Bit Select (USBS0) bit. 

Note : The Receiver ignores the second stop bit. An FE (Frame Error) will therefore only be detected in the cases where the first stop bit is zero. 

Polling or Interrupt ?

From the above description, we can use the USART interface in two ways: 

polling the USART 

interrupt driven

In the following examples I'll introduce two functions : uart_putc and uart_getc. The former is used to send a character trow the serial line, while the latter is used to take characters  from the serial line. They could be used like the putchar and getchar C functions.

Polling the USART

The  simplest way to transmit data using the USART is to poll the UCSR0A register to check if the UDRE0 bit is set and, if the bit is set, we can put the data byte into the UDR0 register to start the transmission. 

If we want to receive data we need to poll the UCSR0A register to check if the RXC0 bit is set. If it isn't set, the rx buffer is empty, elsewhere the received data could be read from the UDR0 register. If the error check is enabled the errors, if any, could be read accessing the UCSR0A register before the read of the UDR0 register (an access to the UDR0 register empty the UCSR0A error flag).

The following C source code uses polling to receive/transmit data from USART. It also shows how to initialize the USART.

#include <avr/io.h>


/** \def UART_ONE_STOP_BIT

    define  used to specify 1 stop bit 

 */

#define UART_ONE_STOP_BIT (0x00)


/** \def UART_TWO_STOP_BIT

    define  used to specify 2 stop bit 

 */

#define UART_TWO_STOP_BIT (0x08)


/** \def UART_NO_PARITY

    define  used to specify no parity bit 

 */

#define UART_NO_PARITY (0x00)


/** \def UART_ODD_PARITY

    define  used to specify odd parity bit 

 */

#define UART_ODD_PARITY (0x30)


/** \def UART_EVEN_PARITY

    define  used to specify even parity bit 

 */

#define UART_EVEN_PARITY             (0x20)


/** \def UART_FIVE_DATA_BIT

    define  used to specify the data bit will be 5 bit 

 */

#define UART_FIVE_DATA_BIT (0x00)


/** \def UART_SIX_DATA_BIT

    define  used to specify the data bit will be 6 bit 

 */

#define UART_SIX_DATA_BIT (0x02)


/** \def UART_SEVEN_DATA_BIT

    define  used to specify the data bit will be 7 bit 

 */

#define UART_SEVEN_DATA_BIT (0x04)


/** \def UART_EIGHT_DATA_

    define  used to specify the data bit will be 8 bit 

 */

#define UART_EIGHT_DATA_BIT (0x06)


/** \def UART_NINE_DATA_BIT

    define  used to specify the data bit will be 9 bit @see init_uart

 */

#define UART_NINE_DATA_BIT       (0x0E)


/** compute the baud rate expression 

 */

#define UART_BAUD_COMPUTE(baudRate) ((F_CPU)/((baudRate)*16l)-1)


char  uart_init_p(unsigned long ulBaudRate, unsigned char ucParity, unsigned char ucDataBit, unsigned char ucStopBit)

{


    /* Compute the baud rate 

     */

    /* simple check !!

     */

    switch (ulBaudRate)

    {

        case 2400:         

        case 4800:

        case 9600:

        case 14400:

        case 19600:

        case 28800:

        case 38400:

        case 57600:

        case 115200:

        case 230400:

        break;

        default:

            return -1;

        

    }

    ulBaudRate = UART_BAUD_COMPUTE(ulBaudRate);

    

    /* Set baud rate 

*/

    UBRR0H = (unsigned char)(ulBaudRate>>8);

    UBRR0L = (unsigned char) ulBaudRate;

    

    /* Set the frame format asynchronous always, but you can init the usart with different

     * format (parity (odd/even/none) data (5-6-7-8-9 data bit) stop bit (1-2)

     */

if (ucDataBit != UART_NINE_DATA_BIT)

{

UCSR0B = _BV(RXEN0) | _BV(TXEN0);

UCSR0C =  ucParity | ucDataBit | ucStopBit;

}

else 

{

UCSR0B = _BV(RXEN0) | _BV(TXEN0) | _BV(UCSZ02);

UCSR0C = ucParity | UART_SIX_DATA_BIT | UART_SEVEN_DATA_BIT | ucStopBit;

}

    return 0;

}



/** receive a character from usart 

 */

unsigned int uart_getc(void)

{

unsigned int  uiChar;

unsigned char ucReadChar ;

       unsigned char ucError ;


/* Wait for incoming data 

*/

while (!(UCSR0A  & _BV(RXC0))) ;

 

/*  Get the error

*/


ucReadChar  = UART0_STATUS;


/* Get the char 

*/

uiChar = UDR0;


ucError = (ucReadChar & (_BV(FE0)|_BV(DOR0) | _BV(UPE0)) );

 

/* Return the data 

*/

return ((ucError << 8 ) | uiChar);

}


/** transmit a character by usart 

 */

void uart_putc(unsigned char ucData)

{

/* Wait for empty transmit buffer */

while ( !(UCSR0A  & _BV(UDRE0)) )

;                

/* Start transmission */

UDR0 = data;        

}


“Polling” is  a slower and CPU intensive method : 

The application needs to wait until a frame is received or transmitted. Generally it is unused but it isn't dismissed. It is the only way, for example, to send  characters (for debugging) during  ISR or in applications running with interrupt disabled. You need to note that “polling” uses low code size and it's very simple to use.

 

 

 

 

(to be continued…)

The index page