USART access. More...
#include <stdint.h>
#include <avr/pgmspace.h>
#include <avr/io.h>
#include "fifo.h"
Go to the source code of this file.
Data Structures | |
struct | usart_rxdata_s |
type of data received from USART including status More... | |
struct | usart_control_s |
control and status for one USART More... | |
Defines | |
#define | USART_FRAME_ERROR (1<<4) |
fifo flag: FRAME ERROR | |
#define | USART_PARITY_ERROR (1<<2) |
fifo flag: PARITY ERROR | |
#define | USART_NO_RX (1<<7) |
flag: no RX buffer allocated | |
#define | USART_TIMESTAMPED (1<<6) |
this byte is timestamped | |
Typedefs | |
typedef uint32_t | baudrate_t |
type for baudrate | |
typedef struct usart_rxdata_s | usart_rxdata_t |
type of data received from USART including status | |
typedef uint8_t | usart_timestamp_t |
type of timestamp | |
typedef struct usart_control_s | usart_control_t |
control and status for one USART | |
Enumerations | |
enum | hlog_usart_t { usart_ext, usart_mod, USARTS_NUMBER, usart_none = -1 } |
selector for USART port More... | |
Functions | |
usart_control_t * | usart_init (hlog_usart_t which, fifo_item_t *txbuf, fifo_size_t txsize, fifo_item_t *rxbuf, fifo_size_t rxsize) |
baudrate_t | usart_set_baudrate (usart_control_t *uc, baudrate_t baud) |
set baud rate for USART | |
baudrate_t | usart_change_baudrate (usart_control_t *uc, int8_t incdec) |
change baud rate for USART | |
void | usart_disable (usart_control_t *) |
disable USART | |
void | usart_power (usart_control_t *, uint8_t onoff) |
power-off USART | |
void | usart_enable (usart_control_t *uc) |
enable USART | |
usart_rxdata_t | usart_recv (usart_control_t *uc) |
get one byte from USART (blocking) | |
uint8_t | usart_can_recv (usart_control_t *uc) |
check if usart_recv() will not block | |
void | usart_send (usart_control_t *uc, uint8_t b) |
send one byte to USART | |
void | usart_flush (usart_control_t *uc) |
flush TX FIFO | |
uint8_t | usart_ext_is_connected (void) |
check whether external RS232 interface is connected | |
uint8_t | usart_can_send (usart_control_t *uc) |
check if usart_send() will not block | |
size_t | usart_send_msg (usart_control_t *uc, uint8_t nonblock, const uint8_t *msg, const size_t msglen) |
send a number of bytes to USART | |
size_t | usart_send_msg_P (usart_control_t *uc, uint8_t nonblock, const uint8_t *msg, const size_t msglen) |
send a number of bytes to USART (FLASH) | |
void | usart_timestamp_set_trigger (usart_control_t *uc, uint8_t trigger) |
set trigger value for timestamping | |
usart_timestamp_t | usart_get_timestamp (usart_control_t *uc) |
get timestamp from last trigger |
USART access.
USART send and receive works via FIFO buffers. The functions usart_send() puts data into the TX buffer and usart_recv() pulls data from the RX buffer. Actual access to the USART data register is done in the interrupt functions.
enum hlog_usart_t |
uint8_t usart_can_recv | ( | usart_control_t * | uc | ) | [inline] |
check if usart_recv() will not block
uc | pointer to USART control structure |
{ return fifo_get_buffer (&uc->rxbuf) && !fifo_is_empty(&uc->rxbuf); }
uint8_t usart_can_send | ( | usart_control_t * | uc | ) | [inline] |
check if usart_send() will not block
uc | pointer to USART control structure |
{ return fifo_get_buffer (&uc->txbuf) && !fifo_is_full(&uc->txbuf); }
baudrate_t usart_change_baudrate | ( | usart_control_t * | uc, | |
int8_t | incdec | |||
) |
change baud rate for USART
usart_change_baudrate() increases or decreases the baudrate of the USART according to the sign of incdec.
uc | pointer to USART control structure | |
incdec | >0: increase rate, <0: decrease rate by one step |
{ const struct serial_param_s *p; uint16_t rate_used = UBRRn(uc); uint8_t using_2x = UCSRnA(uc) & _BV(U2X0); uint16_t rate; uint8_t use_2x; /* find current rate */ for (p = serial_param; (rate = pgm_read_word(&p->rate)); p++) { if (rate == rate_used && (using_2x!=0) == (pgm_read_byte(&p->use_2x) != 0)) break; } if (rate == 0) return 0; if (incdec < 0) { /* decrease rate */ if (p == serial_param) /* already at lowest, keep */ return pgm_read_dword (&p->baud); p--; rate = pgm_read_word(&p->rate); use_2x = pgm_read_byte (&p->use_2x); } else if (incdec > 0) { /* increase rate */ p++; rate = pgm_read_word (&p->rate); if (rate == 0) /* already at highest, keep */ return pgm_read_dword (&p[-1].baud); use_2x = pgm_read_byte (&p->use_2x); } else { /* keep rate, return actual rate */ return pgm_read_dword (&p->baud); } UBRRn(uc) = rate; if (use_2x) UCSRnA(uc) |= _BV(U2X0); else UCSRnA(uc) &= ~_BV(U2X0); return pgm_read_dword (&p->baud); }
void usart_disable | ( | usart_control_t * | ) |
disable USART
uc | pointer to USART control structure |
{ UCSRnB(uc) &= ~(_BV(RXCIE0)|_BV(TXCIE0)|_BV(UDRIE0) |_BV(RXEN0)|_BV(TXEN0)); }
void usart_enable | ( | usart_control_t * | uc | ) |
enable USART
This actually switches on the USART indicated by uc.
uc | pointer to USART control structure |
{ UCSRnA(uc) &= _BV(U2X0); /* reset all bits except U2X (double baudrate) */ UCSRnB(uc) |= (fifo_get_buffer(&uc->rxbuf) ? (_BV(RXCIE0)|_BV(RXEN0)) : 0) | (fifo_get_buffer(&uc->txbuf) ? (_BV(UDRIE0)|_BV(TXEN0)) : 0); }
uint8_t usart_ext_is_connected | ( | void | ) |
check whether external RS232 interface is connected
uc | pointer to USART control structure |
void usart_power | ( | usart_control_t * | , | |
uint8_t | onoff | |||
) |
power-off USART
This puts the USART into power-down mode
uc | pointer to USART control structure | |
onoff | when 0, power-off; else power-on |
{ if (onoff) { if (uc == &usart_control_3) { HL_EX232_CTL_PORT &= ~_BV(HL_EX232_EN); } /* enable power */ *(uc->prr) &= ~(uc->prusart); } else { *(uc->prr) |= (uc->prusart); if (uc == &usart_control_3) { /* external */ HL_EX232_CTL_PORT |= _BV(HL_EX232_EN); } } }
usart_rxdata_t usart_recv | ( | usart_control_t * | uc | ) |
get one byte from USART (blocking)
This function reads one byte from the USART RX FIFO. When the FIFO is empty, it blocks until data has been received.
uc | pointer to USART control structure |
{ fifo_item_t it; #if 0 /* duplicated in fifo_get_uint8_t() */ while (!usart_can_recv (uc)) hl_sleep_for_tick (0); #endif if (fifo_get_buffer (&uc->rxbuf)) { it = fifo_get_item (&uc->rxbuf); return (usart_rxdata_t) {.data = it.data, .flags = it.flags }; } else return (usart_rxdata_t) {.data = 0, .flags = USART_NO_RX}; }
void usart_send | ( | usart_control_t * | uc, | |
uint8_t | b | |||
) |
send one byte to USART
This function puts one byte into the USART TX FIFO. When the FIFO is full, it blocks until there is space again. If necessary, the USART Data Register Empty Interrupt is enabled.
uc | pointer to USART control structure | |
b | byte to send |
{ uint8_t tmp; if (!fifo_get_buffer (&uc->txbuf)) return; /* no FIFO buffer -> can not send anything */ #if 1 printf_P (PSTR("US%02x "), b); #endif fifo_put_uint8 (&uc->txbuf, b); /* will block if full */ /* Enable further interrupts (we have data now). * We do it this way instead of the more obvious * UCSRnB(uc) |= _BV(UDRIE0) * to not trigger an extra UDRE interrupt in the following case: * - UDRIE is set * - after reading UCSRnB transmission of one byte completes, * triggering UDRE_vect * - UDRE_vect removes the last byte from FIFO (the one we have * just written) and clears UDRIEn * -> we would set UDRIEn without having more bytes in the FIFO, * so UDRE_vect is possibly called without work to do. * * When UDRIEn is clear, the UDRE interrupt could not have been * triggered. Therefore we are safe in that case. */ tmp = UCSRnB(uc); if (!(tmp & _BV(UDRIE0))) { #if 1 printf_P(PSTR("UDRIEn ")); #endif UCSRnB(uc) = tmp | _BV(UDRIE0); /* Setting UDRIEn will trigger the UDRE interrupt * immediately if UDR is empty. */ } }
size_t usart_send_msg_P | ( | usart_control_t * | uc, | |
uint8_t | nonblock, | |||
const uint8_t * | msg, | |||
const size_t | msglen | |||
) | [inline] |
send a number of bytes to USART (FLASH)
uc | pointer to USART control structure | |
nonblock | when set, don't block, on writing - return from function instead | |
msg | bytes to write to USART (expected to reside in FLASH) | |
msglen | number of bytes to write |
{ size_t cnt = msglen; if (cnt) do { if (nonblock && !usart_can_send (uc)) break; usart_send (uc, pgm_read_byte (msg++)); } while (--cnt); return msglen - cnt; }
baudrate_t usart_set_baudrate | ( | usart_control_t * | uc, | |
baudrate_t | baud | |||
) |
set baud rate for USART
uc | pointer to USART control structure | |
baud | wanted rate |
{ const struct serial_param_s *p; baudrate_t bd; for (p = serial_param; (bd = pgm_read_dword(&p->baud), bd && (bd != baud)); p++); if (bd) { uint16_t rate = pgm_read_word (&p->rate); uint8_t use_2x = pgm_read_byte (&p->use_2x); UBRRn(uc) = rate; if (use_2x) UCSRnA(uc) |= _BV(U2X0); else UCSRnA(uc) &= ~_BV(U2X0); return baud; } return 0; }