Proper print abstraction and ring buffer works
This commit is contained in:
parent
5009a15280
commit
09893c47d1
3 changed files with 134 additions and 83 deletions
39
src/demo.c
39
src/demo.c
|
|
@ -33,6 +33,9 @@
|
|||
#include <libopencm3/stm32/timer.h>
|
||||
#include <libopencm3/stm32/otg_hs.h>
|
||||
#include <libopencm3/stm32/otg_fs.h>
|
||||
#include <libopencm3/stm32/dma.h>
|
||||
#include <libopencm3/cm3/nvic.h>
|
||||
#include <libopencmsis/core_cm3.h>
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
void usart_dma_init(uint32_t usart, uint32_t baudrate, uint32_t dma, uint8_t stream, uint8_t channel) {
|
||||
usart_init(usart, baudrate);
|
||||
|
||||
/* 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);
|
||||
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 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
nvic_enable_irq(DEBUG_USART_NVIC_DMA_IRQ);
|
||||
nvic_enable_irq(f->irqn);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -26,18 +26,55 @@
|
|||
#include "usbh_core.h"
|
||||
#include <stdint.h>
|
||||
#include <stdarg.h>
|
||||
#include <errno.h>
|
||||
|
||||
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);
|
||||
|
||||
#define LOG_PRINTF(format, ...) usart_printf(format, ##__VA_ARGS__);
|
||||
/* 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 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
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue