From 09893c47d186d8cdbbf43041ad5d5cfd45bc4a04 Mon Sep 17 00:00:00 2001 From: jaseg Date: Tue, 6 Nov 2018 14:21:10 +0900 Subject: Proper print abstraction and ring buffer works --- src/demo.c | 39 ++++++++++++++-- src/usart_helpers.c | 131 +++++++++++++++++++++++----------------------------- src/usart_helpers.h | 45 ++++++++++++++++-- 3 files changed, 133 insertions(+), 82 deletions(-) diff --git a/src/demo.c b/src/demo.c index 4458dd6..aa07378 100644 --- a/src/demo.c +++ b/src/demo.c @@ -33,6 +33,9 @@ #include #include #include +#include +#include +#include #include #include @@ -130,6 +133,33 @@ static const hid_config_t hid_config = { .hid_in_message_handler = &hid_in_message_handler }; +volatile struct { + struct dma_buf dma; + uint8_t data[256]; +} debug_buf = { + .dma = { + .xfr_start = -1, + .xfr_end = 0, + .wr_pos = 0, + .len = sizeof(debug_buf.data) + } +}; + +struct dma_usart_file debug_out_s = { + .dma = DMA(DEBUG_USART_DMA_NUM), + .stream = DEBUG_USART_DMA_STREAM_NUM, + .irqn = NVIC_DMA_IRQ(DEBUG_USART_DMA_NUM, DEBUG_USART_DMA_STREAM_NUM), + .buf = &debug_buf.dma +}; +struct dma_usart_file *debug_out = &debug_out_s; + +void DMA_ISR(DEBUG_USART_DMA_NUM, DEBUG_USART_DMA_STREAM_NUM)(void) { + dma_clear_interrupt_flags(debug_out->dma, debug_out->stream, DMA_TCIF); + + if (debug_out->buf->wr_pos != debug_out->buf->xfr_end) /* buffer not empty */ + schedule_dma(debug_out); +} + int main(void) { clock_setup(); @@ -139,7 +169,7 @@ int main(void) tim6_setup(); usart_init(USART2, 1000000); - debug_usart_init(); + DEBUG_USART_INIT(); LOG_PRINTF("SecureHID device side initializing"); @@ -161,10 +191,11 @@ int main(void) while (23) { usbh_poll(tim6_get_time_us()); delay_ms_busy_loop(1); /* approx 1ms interval between usbh_poll() */ - if (i++ == 200) { + //if (i++ == 200) { i = 0; - LOG_PRINTF("Loop iteration %d\n", j++); - } + LOG_PRINTF("0123456789ABCDEF\n"); + //LOG_PRINTF("%x %x %x %x\n", j++, debug_buf.dma.xfr_start, debug_buf.dma.xfr_end, debug_buf.dma.wr_pos); + //} } return 0; } diff --git a/src/usart_helpers.c b/src/usart_helpers.c index 6ba9cea..41b5533 100644 --- a/src/usart_helpers.c +++ b/src/usart_helpers.c @@ -35,21 +35,15 @@ #include #include -static void putf(void *file, char c) { - UNUSED(file); - usart_fifo_push(c); -} -void usart_printf(const char *str, ...) -{ +void usart_fprintf(struct dma_usart_file *f, const char *str, ...) { va_list va; va_start(va, str); - tfp_format(NULL, putf, str, va); + tfp_format(f, putf, str, va); va_end(va); } -void usart_init(uint32_t arg_usart, uint32_t baudrate) -{ +void usart_init(uint32_t arg_usart, uint32_t baudrate) { usart_set_baudrate(arg_usart, baudrate); usart_set_databits(arg_usart, 8); usart_set_flow_control(arg_usart, USART_FLOWCONTROL_NONE); @@ -59,79 +53,68 @@ void usart_init(uint32_t arg_usart, uint32_t baudrate) usart_enable(arg_usart); } -#define WRITE_BUF_LEN 256 -struct tx_buf { - uint8_t buf[WRITE_BUF_LEN]; - uint32_t pos; -} tx_buf[2]; -int tx_buf_active; - -/* This macro abomination templates a bunch of dma-specific register/constant names from preprocessor macros passed in - * from cmake. */ -#define DEBUG_USART_DMA_PASTE(num) DMA ## num -#define DEBUG_USART_DMA_EVAL(num) DEBUG_USART_DMA_PASTE(num) -#define DEBUG_USART_DMA DEBUG_USART_DMA_EVAL(DEBUG_USART_DMA_NUM) - -#define DEBUG_USART_DMA_STREAM_PASTE(num) DMA_STREAM ## num -#define DEBUG_USART_DMA_STREAM_EVAL(num) DEBUG_USART_DMA_STREAM_PASTE(num) -#define DEBUG_USART_DMA_STREAM DEBUG_USART_DMA_STREAM_EVAL(DEBUG_USART_DMA_STREAM_NUM) - -#define DEBUG_USART_NVIC_DMA_IRQ_PASTE(dma, stream) NVIC_ ## DMA ## dma ## _ ## STREAM ## stream ## _IRQ -#define DEBUG_USART_NVIC_DMA_IRQ_EVAL(dma, stream) DEBUG_USART_NVIC_DMA_IRQ_PASTE(dma, stream) -#define DEBUG_USART_NVIC_DMA_IRQ DEBUG_USART_NVIC_DMA_IRQ_EVAL(DEBUG_USART_DMA_NUM, DEBUG_USART_DMA_STREAM_NUM) - -#define DEBUG_USART_DMA_ISR_PASTE(dma, stream) DMA ## dma ## _ ## STREAM ## stream ## _IRQHandler -#define DEBUG_USART_DMA_ISR_EVAL(dma, stream) DEBUG_USART_DMA_ISR_PASTE(dma, stream) -#define DEBUG_USART_DMA_ISR DEBUG_USART_DMA_ISR_EVAL(DEBUG_USART_DMA_NUM, DEBUG_USART_DMA_STREAM_NUM) - -#define DEBUG_USART_DMA_CHANNEL_PASTE(channel) DMA_SxCR_CHSEL_ ## channel -#define DEBUG_USART_DMA_CHANNEL_EVAL(channel) DEBUG_USART_DMA_CHANNEL_PASTE(channel) -#define DEBUG_USART_DMA_CHANNEL DEBUG_USART_DMA_CHANNEL_EVAL(DEBUG_USART_DMA_CHANNEL_NUM) - -void debug_usart_init() { - tx_buf[0].pos = tx_buf[1].pos = 0; - tx_buf_active = 1; - - usart_init(DEBUG_USART, DEBUG_USART_BAUDRATE); - - dma_stream_reset(DEBUG_USART_DMA, DEBUG_USART_DMA_STREAM); - dma_channel_select(DEBUG_USART_DMA, DEBUG_USART_DMA_STREAM, DEBUG_USART_DMA_CHANNEL); - dma_set_peripheral_address(DEBUG_USART_DMA, DEBUG_USART_DMA_STREAM, (uint32_t)&USART_DR(DEBUG_USART)); - dma_set_transfer_mode(DEBUG_USART_DMA, DEBUG_USART_DMA_STREAM, DMA_SxCR_DIR_MEM_TO_PERIPHERAL); - dma_enable_memory_increment_mode(DEBUG_USART_DMA, DEBUG_USART_DMA_STREAM); - dma_set_peripheral_size(DEBUG_USART_DMA, DEBUG_USART_DMA_STREAM, DMA_SxCR_PSIZE_8BIT); - dma_set_memory_size(DEBUG_USART_DMA, DEBUG_USART_DMA_STREAM, DMA_SxCR_MSIZE_8BIT); - dma_set_priority(DEBUG_USART_DMA, DEBUG_USART_DMA_STREAM, DMA_SxCR_PL_VERY_HIGH); - dma_enable_transfer_complete_interrupt(DEBUG_USART_DMA, DEBUG_USART_DMA_STREAM); - usart_enable_tx_dma(DEBUG_USART); +void usart_dma_init(uint32_t usart, uint32_t baudrate, uint32_t dma, uint8_t stream, uint8_t channel) { + usart_init(usart, baudrate); + + dma_stream_reset(dma, stream); + dma_channel_select(dma, stream, DMA_SxCR_CHSEL(channel)); + dma_set_peripheral_address(dma, stream, (uint32_t)&USART_DR(usart)); + dma_set_transfer_mode(dma, stream, DMA_SxCR_DIR_MEM_TO_PERIPHERAL); + dma_enable_memory_increment_mode(dma, stream); + dma_set_peripheral_size(dma, stream, DMA_SxCR_PSIZE_8BIT); + dma_set_memory_size(dma, stream, DMA_SxCR_MSIZE_8BIT); + dma_set_priority(dma, stream, DMA_SxCR_PL_VERY_HIGH); + dma_enable_transfer_complete_interrupt(dma, stream); + usart_enable_tx_dma(usart); } -static void usart_kickoff_dma(void) { - tx_buf[tx_buf_active].pos = 0; /* clear old buffer */ - tx_buf_active = !tx_buf_active; /* swap buffers */ +void usart_kickoff_dma(uint32_t dma, uint8_t stream, uint8_t *buf, size_t len) { /* initiate transmission of new buffer */ - dma_set_memory_address(DEBUG_USART_DMA, DEBUG_USART_DMA_STREAM, (uint32_t)&tx_buf[tx_buf_active].buf); /* select active buffer address */ - dma_set_number_of_data(DEBUG_USART_DMA, DEBUG_USART_DMA_STREAM, tx_buf[tx_buf_active].pos); - dma_enable_stream(DEBUG_USART_DMA, DEBUG_USART_DMA_STREAM); + dma_set_memory_address(dma, stream, (uint32_t)buf); /* select active buffer address */ + dma_set_number_of_data(dma, stream, len); + dma_enable_stream(dma, stream); } -void DEBUG_USART_DMA_ISR(void) { - dma_clear_interrupt_flags(DEBUG_USART_DMA, DEBUG_USART_DMA_STREAM, DMA_TCIF); +void schedule_dma(volatile struct dma_usart_file *f) { + struct dma_buf *buf = f->buf; - struct tx_buf *buf = &tx_buf[!tx_buf_active]; /* select inactive buffer */ - if (buf->pos != 0) { - usart_kickoff_dma(); - } + uint32_t xfr_len, xfr_start = buf->xfr_end; + if (buf->wr_pos > xfr_start) /* no wraparound */ + xfr_len = buf->wr_pos - xfr_start; + else /* wraparound */ + xfr_len = buf->len - xfr_start; /* schedule transfer until end of buffer */ + + buf->xfr_start = xfr_start; + buf->xfr_end = (xfr_start + xfr_len) % buf->len; /* handle wraparound */ + usart_kickoff_dma(f->dma, f->stream, buf->data + xfr_start, xfr_len); +} + +int dma_fifo_push(volatile struct dma_buf *buf, char c) { + if (buf->wr_pos == buf->xfr_start) + return -EBUSY; + + buf->data[buf->wr_pos] = c; + buf->wr_pos = (buf->wr_pos + 1) % buf->len; + return 0; } -void usart_fifo_push(uint8_t c) { - nvic_disable_irq(DEBUG_USART_NVIC_DMA_IRQ); - struct tx_buf *buf = &tx_buf[!tx_buf_active]; /* select inactive buffer */ - buf->buf[buf->pos++] = c; - if (!(DMA_SCR(DEBUG_USART_DMA, DEBUG_USART_DMA_STREAM) & DMA_SxCR_EN) /* DMA is not running */ - && !dma_get_interrupt_flag(DEBUG_USART_DMA, DEBUG_USART_DMA_STREAM, DMA_TCIF)/* DMA interrupt is clear */) { - usart_kickoff_dma(); +void putf(void *file, char c) { + volatile struct dma_usart_file *f = (struct dma_usart_file *)file; + + nvic_disable_irq(f->irqn); + { + /* push char to fifo, busy-loop if stalled to wait for USART to empty fifo via DMA */ + while (dma_fifo_push(f->buf, c) == -EBUSY) { + nvic_enable_irq(f->irqn); + nvic_disable_irq(f->irqn); + } + + /* If the DMA stream is idle right now, schedule a transfer */ + if (!(DMA_SCR(f->dma, f->stream) & DMA_SxCR_EN) /* DMA is not running */ + && !dma_get_interrupt_flag(f->dma, f->stream, DMA_TCIF)/* DMA interrupt is clear */) { + schedule_dma(f); + } } - nvic_enable_irq(DEBUG_USART_NVIC_DMA_IRQ); + nvic_enable_irq(f->irqn); } diff --git a/src/usart_helpers.h b/src/usart_helpers.h index 18de3b4..d2cee0c 100644 --- a/src/usart_helpers.h +++ b/src/usart_helpers.h @@ -26,18 +26,55 @@ #include "usbh_core.h" #include #include +#include BEGIN_DECLS -#ifdef USART_DEBUG +struct dma_buf { + uint32_t xfr_start; /* Start index of running DMA transfer */ + uint32_t xfr_end; /* End index of running DMA transfer plus one */ + uint32_t wr_pos; /* Next index to be written */ + uint32_t len; + uint8_t data[0]; +}; + +struct dma_usart_file { + uint32_t dma; + uint8_t stream; + uint8_t irqn; + struct dma_buf *buf; +}; + + +extern struct dma_usart_file *debug_out; + + void usart_init(uint32_t usart, uint32_t baudrate); -void usart_printf(const char *str, ...); +void usart_fprintf(struct dma_usart_file *f, const char *str, ...); void usart_fifo_push(uint8_t c); -void debug_usart_init(void); +void usart_dma_init(uint32_t usart, uint32_t baudrate, uint32_t dma, uint8_t stream, uint8_t channel); +void usart_kickoff_dma(uint32_t dma, uint8_t stream, uint8_t *buf, size_t len); +void schedule_dma(volatile struct dma_usart_file *f); +int dma_fifo_push(volatile struct dma_buf *buf, char c); +void putf(void *file, char c); + +/* This macro abomination templates a bunch of dma-specific register/constant names from preprocessor macros passed in + * from cmake. */ +#define DMA_PASTE(num) DMA ## num +#define DMA(num) DMA_PASTE(num) + +#define NVIC_DMA_IRQ_PASTE(dma, stream) NVIC_ ## DMA ## dma ## _ ## STREAM ## stream ## _IRQ +#define NVIC_DMA_IRQ(dma, stream) NVIC_DMA_IRQ_PASTE(dma, stream) -#define LOG_PRINTF(format, ...) usart_printf(format, ##__VA_ARGS__); +#define DMA_ISR_PASTE(dma, stream) DMA ## dma ## _ ## STREAM ## stream ## _IRQHandler +#define DMA_ISR(dma, stream) DMA_ISR_PASTE(dma, stream) + +#ifdef USART_DEBUG +#define DEBUG_USART_INIT() usart_dma_init(DEBUG_USART, DEBUG_USART_BAUDRATE, DMA(DEBUG_USART_DMA_NUM), DEBUG_USART_DMA_STREAM_NUM, DEBUG_USART_DMA_CHANNEL_NUM) +#define LOG_PRINTF(format, ...) usart_fprintf(debug_out, format, ##__VA_ARGS__); #else +#define DEBUG_USART_INIT() ((void)0) #define LOG_PRINTF(dummy, ...) ((void)dummy) #endif -- cgit