|
ProtoCore v0.0.1
Deterministic, zero-heap network stack for embedded targets
|
Layer: Foundation ยท Build flags: PC_ENABLE_DMA, PC_ENABLE_PREEMPT_QUEUE, PC_DMA_SIMULATE
The high-throughput ingest path for field-bus peripherals (RS-485 UART, CAN over SPI, IO-Link). A DMA channel moves peripheral bytes into a static buffer while the CPU is free; when the transfer completes, a callback - ISR context on real silicon - does the smallest possible thing: it posts the completion onto the internal DMA lane of the preempting work queue (PreemptQueue). That lane runs above the user lane, so a dedicated high-priority task is preempted to process the bytes off the interrupt, ahead of user work.
RX is double-buffered (ping-pong): the completed buffer is handed up while the DMA engine fills the other, so there is a full transfer of headroom to consume it.
There is usually no physical TX->RX jumper on the bench, so the channel runs the built-in ingress/egress simulator (PC_DMA_SIMULATE=1, the default):
pc_dma_sim_feed() injects bytes as if they arrived on the RX line,pc_dma_sim_capture() reads back what egress DMA transmitted,loopback = true feeds its own egress into its ingress (an internal jumper),pc_dma_poll() advances the engine and fires the completions.This sketch opens a loopback channel and, each second, submits a 4-byte frame for egress DMA; the jumper feeds it back into RX, the completion posts to the queue, and the processing task prints it - the whole pipeline, end to end, on the device itself with no wiring. Expected serial output:
(The odd sequence numbers are the RX completions; the even ones are the paired TX-complete events on the same channel.)
Set PC_DMA_SIMULATE=0 and provide a real driver behind the pc_dma_hw_* hooks (a UART UHCI / spi_master DMA backend). The sketch above is unchanged - it only ever talks to pc_dma_open / pc_dma_tx_submit / the completion callback.
PC_DMA_CHANNELS (channels) and PC_DMA_BUF_SIZE (bytes per transfer, RX double-buffered at this size) are compile-time because the storage is static.
The flags must reach the library build (an in-sketch #define does not reach the separately compiled library), so pass them as build flags: