51#define DMA_STAGE_CAP (PC_DMA_BUF_SIZE * 3)
58 uint8_t buf[DMA_STAGE_CAP];
67 uint16_t space()
const
69 return (uint16_t)(DMA_STAGE_CAP - len);
72 bool push(
const uint8_t *p, uint16_t n)
78 for (uint16_t i = 0; i < n; i++)
80 buf[(head + len) % DMA_STAGE_CAP] = p[i];
86 uint16_t pop(uint8_t *out, uint16_t max)
88 uint16_t n = (len < max) ? len : max;
89 for (uint16_t i = 0; i < n; i++)
92 head = (head + 1) % DMA_STAGE_CAP;
111 pc_dma_periph periph;
125void emit(dma_channel &c, uint8_t
id, pc_dma_dir dir,
const uint8_t *data, uint16_t len)
130 ev.t_us = dma_now_us();
134 ev.periph = c.periph;
149void pump(dma_channel &c, uint8_t
id)
155 c.ingress.push(c.tx_buf, c.tx_len);
157 c.egress.push(c.tx_buf, c.tx_len);
158 uint16_t sent = c.tx_len;
161 emit(c,
id, pc_dma_dir::PC_DMA_TX,
nullptr, sent);
164 while (c.ingress.len > 0)
167 uint16_t got = c.ingress.pop(c.rx_buf[c.rx_active] + c.rx_fill, room);
171 emit(c,
id, pc_dma_dir::PC_DMA_RX, c.rx_buf[c.rx_active],
PC_DMA_BUF_SIZE);
178 emit(c,
id, pc_dma_dir::PC_DMA_RX, c.rx_buf[c.rx_active], c.rx_fill);
185bool pc_dma_open(
const pc_dma_config *cfg)
191 dma_channel &c = s_dma.ch[cfg->channel];
198 c.cb = cfg->on_complete;
204 c.periph = cfg->periph;
205 c.loopback = cfg->loopback;
211bool pc_dma_tx_submit(uint8_t ch,
const uint8_t *buf, uint16_t len)
217 dma_channel &c = s_dma.ch[ch];
218 if (!c.open || c.tx_busy)
222 memcpy(c.tx_buf, buf, len);
228void pc_dma_close(uint8_t ch)
234 s_dma.ch[ch].open =
false;
237void pc_dma_poll(
void)
241 if (s_dma.ch[i].open)
243 pump(s_dma.ch[i], i);
248bool pc_dma_sim_feed(uint8_t ch,
const uint8_t *bytes, uint16_t len)
254 dma_channel &c = s_dma.ch[ch];
259 return c.ingress.push(bytes, len);
262uint16_t pc_dma_sim_capture(uint8_t ch, uint8_t *out, uint16_t max)
268 dma_channel &c = s_dma.ch[ch];
273 return c.egress.pop(out, max);
280 __attribute__((weak))
bool pc_dma_hw_open(
const pc_dma_config *cfg)
285 __attribute__((weak))
bool pc_dma_hw_tx_submit(uint8_t ch,
const uint8_t *buf, uint16_t len)
292 __attribute__((weak))
void pc_dma_hw_close(uint8_t ch)
296 __attribute__((weak))
void pc_dma_hw_poll(
void)
301bool pc_dma_open(
const pc_dma_config *cfg)
307 return pc_dma_hw_open(cfg);
310bool pc_dma_tx_submit(uint8_t ch,
const uint8_t *buf, uint16_t len)
316 return pc_dma_hw_tx_submit(ch, buf, len);
319void pc_dma_close(uint8_t ch)
327void pc_dma_poll(
void)
Pluggable monotonic clock for all library timing.
uint32_t pc_millis(void)
The library's monotonic time at 1000 Hz (milliseconds).
uint32_t pc_micros(void)
Monotonic microseconds - the high-resolution time base for ISR timestamps and sub-millisecond latency...
DMA peripheral ingest / egress (PC_ENABLE_DMA) - the v5 high-throughput hardware-ingest path.
#define PC_DMA_BUF_SIZE
Bytes per DMA transfer buffer (RX is double-buffered at this size).
#define PC_DMA_CHANNELS
Number of DMA channels (static-allocated; each is one peripheral link).