Data Structures | Defines | Typedefs | Enumerations | Functions

usarts.h File Reference

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_tusart_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

Detailed Description

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.


Enumeration Type Documentation

selector for USART port

Enumerator:
usart_ext 

external port, uses RS-232 level converter

usart_mod 

GPS module mounted on board.

             {
  usart_ext, 
  usart_mod, 
  USARTS_NUMBER,
  usart_none = -1,
} hlog_usart_t;


Function Documentation

uint8_t usart_can_recv ( usart_control_t uc  )  [inline]

check if usart_recv() will not block

Parameters:
uc pointer to USART control structure
Returns:
1 if next call to usart_recv will not block

{
  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

Parameters:
uc pointer to USART control structure
Returns:
1 if next call to usart_send will not block

{
  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.

Parameters:
uc pointer to USART control structure
incdec >0: increase rate, <0: decrease rate by one step
Returns:
baud rate after change

{
  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

Parameters:
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.

Parameters:
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

Parameters:
uc pointer to USART control structure
Returns:
1 if externally connected line is detected
void usart_power ( usart_control_t ,
uint8_t  onoff 
)

power-off USART

This puts the USART into power-down mode

Parameters:
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.

Parameters:
uc pointer to USART control structure
Returns:
byte read from USART

{
  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.

Parameters:
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)

Parameters:
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
Returns:
number of bytes actually written

{
  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

Parameters:
uc pointer to USART control structure
baud wanted rate
Returns:
actual rate, 0 if not possible

{
  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;
}