paulies-project-pages / github-slideshow

A robot powered training repository :robot:
https://lab.github.com/githubtraining/introduction-to-github
MIT License
0 stars 0 forks source link

ATMega328p Interrupt driven UART #13

Closed paulies-project-pages closed 2 months ago

paulies-project-pages commented 2 months ago

Heavily based off the AVR application note 306, implements the USART functionality of the ATMega328p using interrupt handler routines.

paulies-project-pages commented 2 months ago

/**** PROGRAM DESCRIPTION *** A hardware based interrupt driven UART recieve and transmit driver based on the ATMega328p microcontroller. Uses the ring buffer technique for both transmit and receive functions.

Default data transfer settings (Hard Coded): Processor: ATMega328p Baud Rate: 9600 bits per second (baud). Packet : 8 data, No parity, 1 Stop bit (8N1).

References: ATMEL Application Note AVR306
****/

/**** DEFINITIONS **/

include <avr/io.h>

include <avr/interrupt.h>

define F_CPU 16000000UL

define BAUD 9600UL

define UART_RX_BUFFER_SIZE 64 // Must be a power of 2. Max size is 256

define UART_RX_BUFFER_MASK (UART_RX_BUFFER_SIZE - 1)

if (UART_RX_BUFFER_SIZE & UART_RX_BUFFER_MASK)

error RX buffer size is not a power of 2

endif

if (UART_RX_BUFFER_SIZE > 256)

error RX maximum permissible buffer size is 256 bytes

endif

define UART_TX_BUFFER_SIZE 64 // Must be a power of 2. Max size is 256

define UART_TX_BUFFER_MASK (UART_TX_BUFFER_SIZE - 1)

if (UART_TX_BUFFER_SIZE & UART_TX_BUFFER_MASK)

error TX buffer size is not a power of 2

endif

if (UART_TX_BUFFER_SIZE > 256)

error TX maximum permissible buffer size is 256 bytes

endif

// Use Asynchronous Normal mode (U2Xn = 0) - table 24.1 of ATmega328 datasheet

define UBBRn (F_CPU / (BAUD * 16UL)) - 1

// brief receive ringbuffer overflow

define UART_BUFFER_OVERFLOW 0x0200

static unsigned char UART_RxBuf[UART_RX_BUFFER_SIZE]; static volatile unsigned char UART_RxHead; static volatile unsigned char UART_RxTail; static unsigned char UART_TxBuf[UART_TX_BUFFER_SIZE]; static volatile unsigned char UART_TxHead; static volatile unsigned char UART_TxTail; static volatile unsigned char UART_LastRxError; char received_byte;

void usart_config(void); unsigned char receive_byte(void); void transmit_byte(unsigned char data); unsigned char data_in_receive_buffer(void); void capture_byte();

void usart_config(void) { // Ensure global interrupts are cleared during USART initialisation cli();

// Define the Baud rate in the ATmega328 chip UBRR0H = UBBRn >> 8; //shift upper 8 bits into the UBBR0H register UBRR0L = UBBRn; //and lower 8 bits into the UBBR0L register.

// Set Frame format to 8 bits, No parity and 1 stop bit (8N1) UCSR0C = (1 << UCSZ01) | (1 <<UCSZ00);

// Enable UART transmit + receive and receive complete interrupt UCSR0B = (1 << RXCIE0) | (1 << RXEN0) | (1 << TXEN0);

// Flush receive and transmit buffers
UART_RxHead = 0; UART_RxTail = 0;
UART_TxHead = 0; UART_TxTail = 0;
}

ISR (USART_RX_vect) { unsigned char data; unsigned char tmphead; unsigned char errorStatus; unsigned char lastRxError;

// Copy status/contents of buffer and error. data = UDR0;

// calculate buffer index tmphead = (UART_RxHead + 1) & UART_RX_BUFFER_MASK;

if(tmphead == UART_RxTail) { // ERROR! Receive buffer overfow lastRxError = UART_BUFFER_OVERFLOW >> 8; }

else { // store new index UART_RxHead = tmphead; // store received data in buffer UART_RxBuf[tmphead] = data; } }

ISR (USART_UDRE_vect) { unsigned char tmptail;

if(UART_TxHead != UART_TxTail) { // Calculate Buffer Index tmptail = (UART_TxTail + 1) & UART_TX_BUFFER_MASK; UART_TxTail = tmptail;

// Start Transmission
UDR0 = UART_TxBuf[tmptail];   

}

else // Tx buffer is empty { // Disable UDRE interrupt UCSR0B &= ~(1 << UDRIE0); } }

unsigned char receive_byte(void) { unsigned char tmptail;

// Wait for incoming data while(UART_RxHead == UART_RxTail);

// Calculate buffer index tmptail = (UART_RxTail + 1) & UART_RX_BUFFER_MASK; UART_RxTail = tmptail;

// Return data return UART_RxBuf[tmptail];
}

void transmit_byte(unsigned char data) { unsigned char tmphead;

// Calculate buffer index tmphead = (UART_TxHead + 1) & UART_TX_BUFFER_MASK;

// Wait for free space in buffer while(tmphead == UART_TxTail);

// Store data in buffer UART_TxBuf[tmphead] = data; UART_TxHead = tmphead;

// Enable UDRE interrupt UCSR0B |= (1<<UDRIE0);
}

unsigned char data_in_receive_buffer(void) { // FALSE if the receive buffer is empty return (UART_RxHead != UART_RxTail); }

// Obtain a single byte of data from ATMega328p UART void capture_byte() { sei(); received_byte = receive_byte(); cli(); }// end function capture_byte()