Stairs/module/src/lib/TinyUART.c

162 lines
2.6 KiB
C

/*
* Stairs lighting
* Copyright 2017 (c) Mark van Renswoude
*
* https://git.x2software.net/pub/Stairs
*
* Source:
* https://github.com/akafugu/helloworld/blob/master/attiny2313/uart.c
*/
#include "TinyUART.h"
#include <avr/interrupt.h>
#include <avr/io.h>
#include <avr/pgmspace.h>
volatile static uint8_t rx_buffer[BUFFER_SIZE] = "xxxxxxxxxxxxxxxx";
volatile static uint8_t tx_buffer[BUFFER_SIZE] = "xxxxxxxxxxxxxxxx";
volatile static uint8_t rx_head = 0;
volatile static uint8_t rx_tail = 0;
volatile static uint8_t tx_head = 0;
volatile static uint8_t tx_tail = 0;
void uart_init(void)
{
// set baud rate
UBRRH = (uint8_t)(MYUBBR >> 8);
UBRRL = (uint8_t)(MYUBBR);
// enable receive and transmit
UCSRB = (1 << RXEN) | (1 << TXEN) | (1 << RXCIE);
// set frame format
UCSRC = (1 << USBS) | (3 << UCSZ0); // asynchron 8n1
}
void uart_send(uint8_t c)
{
// wait for empty data register
while (!(UCSRA & (1<<UDRE)));
// set data into data register
UDR = c;
}
uint8_t uart_available(void)
{
return rx_head - rx_tail;
}
uint8_t uart_receive(void)
{
while (!(UCSRA & (1<<RXC)))
;
return UDR;
}
uint16_t uart_getc(void)
{
uint8_t c = 0;
uint8_t tmp_tail = 0;
if (rx_head == rx_tail)
return UART_NO_DATA;
tmp_tail = (rx_tail + 1) % BUFFER_SIZE;
c = rx_buffer[rx_tail];
rx_tail = tmp_tail;
return c;
}
uint8_t uart_getc_wait(void)
{
uint16_t c;
while ((c = uart_getc()) == UART_NO_DATA) {}
return c;
}
void uart_putc(uint8_t c)
{
uint8_t tmp_head = (tx_head + 1) % BUFFER_SIZE;
// wait for space in buffer
while (tmp_head == tx_tail)
;
tx_buffer[tx_head] = c;
tx_head = tmp_head;
// enable uart data interrupt (send data)
UCSRB |= (1<<UDRIE);
}
void uart_puts(const char *s)
{
while (*s)
{
uart_putc(*s);
s++;
}
}
void uart_puts_P(const char *s)
{
while (pgm_read_byte(s) != 0x00)
{
uart_putc(pgm_read_byte(s++));
}
}
/*
* ISR User Data Regiser Empty
* Send a char out of buffer via UART. If sending is complete, the
* interrupt gets disabled.
*/
ISR(USART_UDRE_vect)
{
uint8_t tmp_tail = 0;
if (tx_head != tx_tail)
{
tmp_tail = (tx_tail + 1) % BUFFER_SIZE;
UDR = tx_buffer[tx_tail];
tx_tail = tmp_tail;
}
else
{
// disable this interrupt if nothing more to send
UCSRB &= ~(1 << UDRIE);
}
}
/*
* ISR RX complete
* Receives a char from UART and stores it in ring buffer.
*/
ISR(USART_RX_vect)
{
uint8_t tmp_head = 0;
tmp_head = (rx_head + 1) % BUFFER_SIZE;
if (tmp_head == rx_tail)
{
// buffer overflow error!
}
else
{
rx_buffer[rx_head] = UDR;
rx_head = tmp_head;
}
}