summaryrefslogtreecommitdiff
path: root/src/usart_helpers.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/usart_helpers.c')
-rw-r--r--src/usart_helpers.c131
1 files changed, 57 insertions, 74 deletions
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 <libopencm3/cm3/nvic.h>
#include <libopencmsis/core_cm3.h>
-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);
}