From 9915d1ba46e30990ea149c7a09d1d2ed0d13a331 Mon Sep 17 00:00:00 2001 From: Fredrik Thulin Date: Wed, 1 Jun 2016 21:03:05 +0200 Subject: Implement circular buffer UART RX using interrupts. --- projects/cli-test/cli-test.c | 21 +++++++++++++++- projects/cli-test/mgmt-cli.c | 60 +++++++++++++++++++++++++++++++++++++++++--- projects/cli-test/mgmt-cli.h | 4 +++ 3 files changed, 80 insertions(+), 5 deletions(-) (limited to 'projects/cli-test') diff --git a/projects/cli-test/cli-test.c b/projects/cli-test/cli-test.c index 26ebbc2..b90d0dd 100644 --- a/projects/cli-test/cli-test.c +++ b/projects/cli-test/cli-test.c @@ -49,6 +49,9 @@ extern uint32_t update_crc(uint32_t crc, uint8_t *buf, int len); +/* MGMT UART interrupt receive buffer (data will be put in a larger ring buffer) */ +volatile uint8_t uart_rx; + int cmd_show_cpuspeed(struct cli_def *cli, const char *command, char *argv[], int argc) { @@ -286,6 +289,22 @@ void do_early_dfu_jump(void) while (1); } +/* Callback for HAL_UART_Receive_IT(). */ +void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) +{ + if (huart->Instance == huart_mgmt.Instance) { + mgmt_cli_uart_isr((const uint8_t *) &uart_rx, 1); + + /* Set things up to receive another byte. */ + HAL_UART_Receive_IT(huart, (uint8_t *) &uart_rx, 1); + } +} + +void HAL_UART_ErrorCallback(UART_HandleTypeDef *huart) +{ + led_on(LED_RED); + led_on(LED_YELLOW); +} int main() @@ -318,7 +337,7 @@ main() /* embedded_cli_loop returns when the user enters 'quit' or 'exit' */ - cli_print(&cli, "Rebooting in 4 seconds"); + cli_print(&cli, "Rebooting in 3 seconds"); HAL_Delay(3000); HAL_NVIC_SystemReset(); diff --git a/projects/cli-test/mgmt-cli.c b/projects/cli-test/mgmt-cli.c index 46faae8..abbd999 100644 --- a/projects/cli-test/mgmt-cli.c +++ b/projects/cli-test/mgmt-cli.c @@ -33,10 +33,27 @@ */ #include "stm-init.h" #include "stm-uart.h" +#include "stm-led.h" #include "mgmt-cli.h" #include +extern uint8_t uart_rx; + +struct uart_ringbuf_t { + uint32_t enabled, ridx, widx, overflow; + uint8_t buf[CLI_UART_RECVBUF_SIZE]; +}; + +volatile struct uart_ringbuf_t uart_ringbuf = {1, 0, 0, 0, {0}}; + +#define RINGBUF_RIDX(rb) (rb.ridx & CLI_UART_RECVBUF_MASK) +#define RINGBUF_WIDX(rb) (rb.widx & CLI_UART_RECVBUF_MASK) +#define RINGBUF_COUNT(rb) ((unsigned)(rb.widx - rb.ridx)) +#define RINGBUF_FULL(rb) (RINGBUF_RIDX(rb) == ((rb.widx + 1) & CLI_UART_RECVBUF_MASK)) +#define RINGBUF_READ(rb, dst) {dst = rb.buf[RINGBUF_RIDX(rb)]; rb.buf[RINGBUF_RIDX(rb)] = '.'; rb.ridx++;} +#define RINGBUF_WRITE(rb, src) {rb.buf[RINGBUF_WIDX(rb)] = src; rb.widx++;} + void uart_cli_print(struct cli_def *cli __attribute__ ((unused)), const char *buf) { char crlf[] = "\r\n"; @@ -46,8 +63,23 @@ void uart_cli_print(struct cli_def *cli __attribute__ ((unused)), const char *bu int uart_cli_read(struct cli_def *cli __attribute__ ((unused)), void *buf, size_t count) { - if (uart_recv_char2(STM_UART_MGMT, buf, count) != HAL_OK) { - return -1; + uint32_t timeout = 0xffffff; + + /* Always explicitly enable the RX interrupt when we get here. + * Prevents us getting stuck waiting for an interrupt that will never come. + */ + __HAL_UART_FLUSH_DRREGISTER(&huart_mgmt); + HAL_UART_Receive_IT(&huart_mgmt, (uint8_t *) &uart_rx, 1); + + while (count && timeout--) { + if (RINGBUF_COUNT(uart_ringbuf)) { + RINGBUF_READ(uart_ringbuf, *(uint8_t *) buf); + buf++; + count--; + } else { + led_toggle(LED_GREEN); + HAL_Delay(10); + } } return 1; } @@ -83,7 +115,11 @@ int embedded_cli_loop(struct cli_def *cli) n = cli_loop_read_next_char(cli, &ctx, &c); - //cli_print(cli, "Next char: '%c' (n == %i)", c, n); + /* + cli_print(cli, "Next char: '%c'/%i, ringbuf ridx %i, widx %i (%i/%i) - count %i", + c, (int) c, uart_ringbuf.ridx, uart_ringbuf.widx, RINGBUF_RIDX(uart_ringbuf), + RINGBUF_WIDX(uart_ringbuf), RINGBUF_COUNT(uart_ringbuf)); + */ if (n == CLI_LOOP_CTRL_BREAK) break; if (n == CLI_LOOP_CTRL_CONTINUE) @@ -98,7 +134,7 @@ int embedded_cli_loop(struct cli_def *cli) if (ctx.l < 0) break; - //cli_print(cli, "Process command: '%s'", ctx.cmd); + /* cli_print(cli, "Process command: '%s'", ctx.cmd); */ n = cli_loop_process_cmd(cli, &ctx); if (n == CLI_LOOP_CTRL_BREAK) break; @@ -107,6 +143,22 @@ int embedded_cli_loop(struct cli_def *cli) return CLI_OK; } +/* Interrupt service routine to be called when data has been received on the MGMT UART. */ +void mgmt_cli_uart_isr(const uint8_t *buf, size_t count) +{ + if (! uart_ringbuf.enabled) return; + + while (count) { + if (RINGBUF_FULL(uart_ringbuf)) { + uart_ringbuf.overflow++; + return; + } + RINGBUF_WRITE(uart_ringbuf, *buf); + buf++; + count--; + } +} + void mgmt_cli_init(struct cli_def *cli) { cli_init(cli); diff --git a/projects/cli-test/mgmt-cli.h b/projects/cli-test/mgmt-cli.h index dd6a58b..3b7f503 100644 --- a/projects/cli-test/mgmt-cli.h +++ b/projects/cli-test/mgmt-cli.h @@ -68,10 +68,14 @@ cli_register_command2(cli, &cmd_##name##_s, NULL) +#define CLI_UART_RECVBUF_SIZE 256 /* This must be a power of 2 */ +#define CLI_UART_RECVBUF_MASK (CLI_UART_RECVBUF_SIZE - 1) + extern void uart_cli_print(struct cli_def *cli __attribute__ ((unused)), const char *buf); extern int uart_cli_read(struct cli_def *cli __attribute__ ((unused)), void *buf, size_t count); extern int uart_cli_write(struct cli_def *cli __attribute__ ((unused)), const void *buf, size_t count); extern int embedded_cli_loop(struct cli_def *cli); extern void mgmt_cli_init(struct cli_def *cli); +extern void mgmt_cli_uart_isr(const uint8_t *buf, size_t count); #endif /* __STM32_MGMT_CLI_H */ -- cgit v1.2.3