/* Round to nearest */
#define BITWIDTH ((CLK_FREQUENCY+(BAUD/2))/BAUD)
+enum state {
+ IDLE, START_BIT, BITS, STOP_BIT, ERROR
+};
+
/*
* Our UART uses 16x oversampling, so at 50 MHz and 115200 baud
* each sample is: 50000000/(115200*16) = 27 clock cycles. This
* means each bit is off by 0.47% so for 8 bits plus a start and
* stop bit the errors add to be 4.7%.
*/
-static double error = 0.05;
-
-enum state {
- IDLE, START_BIT, BITS, STOP_BIT, ERROR
+struct uart_tx_state {
+ double error = 0.05;
+
+ enum state tx_state = IDLE;
+ unsigned long tx_countbits;
+ unsigned char tx_bits;
+ unsigned char tx_byte;
+ unsigned char tx_prev;
+
+ enum state rx_state = IDLE;
+ unsigned char rx_char;
+ unsigned long rx_countbits;
+ unsigned char rx_bit;
+ unsigned char rx = 1;
};
-static enum state tx_state = IDLE;
-static unsigned long tx_countbits;
-static unsigned char tx_bits;
-static unsigned char tx_byte;
-static unsigned char tx_prev;
+static struct uart_tx_state uart;
/*
* Return an error if the transition is not close enough to the start or
*/
static bool is_error(unsigned long bits)
{
- double e = 1.0 * tx_countbits / BITWIDTH;
+ double e = 1.0 * uart.tx_countbits / BITWIDTH;
- if ((e <= (1.0-error)) && (e >= error))
+ if ((e <= (1.0-uart.error)) && (e >= uart.error))
return true;
return false;
void uart_tx(unsigned char tx)
{
- switch (tx_state) {
+ switch (uart.tx_state) {
case IDLE:
if (tx == 0) {
- tx_state = START_BIT;
- tx_countbits = BITWIDTH;
- tx_bits = 0;
- tx_byte = 0;
+ uart.tx_state = START_BIT;
+ uart.tx_countbits = BITWIDTH;
+ uart.tx_bits = 0;
+ uart.tx_byte = 0;
}
break;
case START_BIT:
- tx_countbits--;
+ uart.tx_countbits--;
if (tx == 1) {
- if (is_error(tx_countbits)) {
- printf("START_BIT error %ld %ld\n", BITWIDTH, tx_countbits);
- tx_countbits = BITWIDTH*2;
- tx_state = ERROR;
+ if (is_error(uart.tx_countbits)) {
+ printf("START_BIT error %ld %ld\n", BITWIDTH, uart.tx_countbits);
+ uart.tx_countbits = BITWIDTH*2;
+ uart.tx_state = ERROR;
break;
}
}
- if (tx_countbits == 0) {
- tx_state = BITS;
- tx_countbits = BITWIDTH;
+ if (uart.tx_countbits == 0) {
+ uart.tx_state = BITS;
+ uart.tx_countbits = BITWIDTH;
}
break;
case BITS:
- tx_countbits--;
- if (tx_countbits == BITWIDTH/2) {
- tx_byte = tx_byte | (tx << tx_bits);
- tx_bits = tx_bits + 1;
+ uart.tx_countbits--;
+ if (uart.tx_countbits == BITWIDTH/2) {
+ uart.tx_byte = uart.tx_byte | (tx << uart.tx_bits);
+ uart.tx_bits = uart.tx_bits + 1;
}
- if (tx != tx_prev) {
- if (is_error(tx_countbits)) {
- printf("BITS error %ld %ld\n", BITWIDTH, tx_countbits);
- tx_countbits = BITWIDTH*2;
- tx_state = ERROR;
+ if (tx != uart.tx_prev) {
+ if (is_error(uart.tx_countbits)) {
+ printf("BITS error %ld %ld\n", BITWIDTH, uart.tx_countbits);
+ uart.tx_countbits = BITWIDTH*2;
+ uart.tx_state = ERROR;
break;
}
}
- if (tx_countbits == 0) {
- if (tx_bits == 8) {
- tx_state = STOP_BIT;
+ if (uart.tx_countbits == 0) {
+ if (uart.tx_bits == 8) {
+ uart.tx_state = STOP_BIT;
}
- tx_countbits = BITWIDTH;
+ uart.tx_countbits = BITWIDTH;
}
break;
case STOP_BIT:
- tx_countbits--;
+ uart.tx_countbits--;
if (tx == 0) {
- if (is_error(tx_countbits)) {
- printf("STOP_BIT error %ld %ld\n", BITWIDTH, tx_countbits);
- tx_countbits = BITWIDTH*2;
- tx_state = ERROR;
+ if (is_error(uart.tx_countbits)) {
+ printf("STOP_BIT error %ld %ld\n", BITWIDTH, uart.tx_countbits);
+ uart.tx_countbits = BITWIDTH*2;
+ uart.tx_state = ERROR;
break;
}
/* Go straight to idle */
- write(STDOUT_FILENO, &tx_byte, 1);
- tx_state = IDLE;
+ write(STDOUT_FILENO, &uart.tx_byte, 1);
+ uart.tx_state = IDLE;
}
- if (tx_countbits == 0) {
- write(STDOUT_FILENO, &tx_byte, 1);
- tx_state = IDLE;
+ if (uart.tx_countbits == 0) {
+ write(STDOUT_FILENO, &uart.tx_byte, 1);
+ uart.tx_state = IDLE;
}
break;
case ERROR:
- tx_countbits--;
- if (tx_countbits == 0) {
- tx_state = IDLE;
+ uart.tx_countbits--;
+ if (uart.tx_countbits == 0) {
+ uart.tx_state = IDLE;
}
break;
}
- tx_prev = tx;
+ uart.tx_prev = tx;
}
static struct termios oldt;
}
}
-static enum state rx_state = IDLE;
-static unsigned char rx_char;
-static unsigned long rx_countbits;
-static unsigned char rx_bit;
-static unsigned char rx = 1;
-
/* Avoid calling poll() too much */
#define RX_INTERVAL 10000
static unsigned long rx_sometimes;
{
unsigned char c;
- switch (rx_state) {
+ switch (uart.rx_state) {
case IDLE:
if (rx_sometimes++ >= RX_INTERVAL) {
rx_sometimes = 0;
if (nonblocking_read(&c)) {
- rx_state = START_BIT;
- rx_char = c;
- rx_countbits = BITWIDTH;
- rx_bit = 0;
- rx = 0;
+ uart.rx_state = START_BIT;
+ uart.rx_char = c;
+ uart.rx_countbits = BITWIDTH;
+ uart.rx_bit = 0;
+ uart.rx = 0;
}
}
break;
case START_BIT:
- rx_countbits--;
- if (rx_countbits == 0) {
- rx_state = BITS;
- rx_countbits = BITWIDTH;
- rx = rx_char & 1;
+ uart.rx_countbits--;
+ if (uart.rx_countbits == 0) {
+ uart.rx_state = BITS;
+ uart.rx_countbits = BITWIDTH;
+ uart.rx = uart.rx_char & 1;
}
break;
case BITS:
- rx_countbits--;
- if (rx_countbits == 0) {
- rx_bit = rx_bit + 1;
- if (rx_bit == 8) {
- rx = 1;
- rx_state = STOP_BIT;
+ uart.rx_countbits--;
+ if (uart.rx_countbits == 0) {
+ uart.rx_bit = uart.rx_bit + 1;
+ if (uart.rx_bit == 8) {
+ uart.rx = 1;
+ uart.rx_state = STOP_BIT;
} else {
- rx = (rx_char >> rx_bit) & 1;
+ uart.rx = (uart.rx_char >> uart.rx_bit) & 1;
}
- rx_countbits = BITWIDTH;
+ uart.rx_countbits = BITWIDTH;
}
break;
case STOP_BIT:
- rx_countbits--;
- if (rx_countbits == 0) {
- rx_state = IDLE;
+ uart.rx_countbits--;
+ if (uart.rx_countbits == 0) {
+ uart.rx_state = IDLE;
}
break;
}
- return rx;
+ return uart.rx;
}
// cheating, here: to avoid having to save the uart state, check if it
// is idle (both tx and rx)
-bool uart_idle(void)
+bool uart_state(void)
{
- return (tx_state == IDLE && rx_state == IDLE);
+ return (uart.tx_state == IDLE && uart.rx_state == IDLE);
}