Overview
Direct Memory Access (DMA) promises big potential to relieve the processor, and consequently, the control program from babysitting peripheral devices. This program is a preparatory step towards integrating DMA into the RTK framework. It implements and demonstrates the basic infrastructure to use DMA for text output to the serial terminal in a next step.1
The program StringBufOut
shows how a program can write to a string buffer in lieu of directly to a serial terminal, and then flush the buffer in one go to the serial terminal.
DMA can empty a whole character buffer “into” a UART without any further interaction with the processor. However, as long as such a transfer from the buffer memory to the peripheral is in flight, no new output can be done, that is, the processor has to await the end of the transfer. If every, say, Out.Int
is written to the UART via DMA, the program has to wait until the corresponding character data has been completely transmitted to the peripheral terminal, and then for the subsequent Out.*
operation again. And again. We don’t gain too much.
The whole operation is much more efficient and effective, if we direct all our Out.*
operations towards a buffer first, and then ask DMA to transfer the whole in one go, thusly emptying the buffer. While the DMA handles this transfer and transmission, our program can do other stuff, or with the kernel, the thread can transfer back control to the scheduler, allowing other threads to run. The thread does not have to babysit the text output.
DMA itself is not employed yet. The modules introduced below are the first step to then plug in DMA-enabled writing to the terminal.
Program Description
Apart from the main program StringBufOut
, there are:
-
module
StringDev
: a TextIO-compatibleDevice
, implementing a string buffer, which can be written to using a TextIO-compatiblePutString
procedure, just as a UART;StringBuffers
usesPutString
to create theTextIO.Writer
to write to the buffer from the program, eg. using moduleOut
; -
module
StringBuffers
: implements a “virtual” analogue to moduleTerminals
, that is, two exportedTextIO.Writer
, which can be used to write to two correspondingStringDev.Device
, just asTerminals
provides twoWriter
to write to two UARTs.
The text buffer in StringDev.Device
is emptied by flushing its contents using another TextIO.Writer
, for example as provided by Terminals
. Hence, we can rewire the usual text output set-up as follows:
-
Module
Out
usesStringBuffers.W[0]
andStringBuffers.W[1]
, in lieu of the usualTerminals.W[0]
andTerminals.W[1]
, respectively. All output operations from moduleOut
now write into the text buffers. -
Module
StringBuffers
sets the outputTextIO.Writer
for its twoStringDev.Device
toTerminals.W[0]
andTerminals.W[1]
, respectively.
Hence, we have linked the two StringBuffers.W[x]
between Out
and Terminals
. The software will write all output into the buffers, and then flush the buffer through Terminals
. Right now, this example program just uses the old, usual UARTstr.PutString
for the terminals, but in a next step, we can replace this with a DMA-supported version of the same functionality, say, UARTdmaStr.PutString
. This will be implemented – or so I hope – in the next example program, when I have figured out the DMA stuff, and created a corresponding library module.
Threads
The program is implemented in one module StringBufOut.mod
.
- thread 0: heartbeat blinker, also writes two counter values to the eight LEDs via module
LEDext
, using the newLEDext.SetLedBits
procedure. - thread 1: writes test output to the serial terminal, via the string buffer as explained above.
Notes
- This program makes use of the kernel-v1 to run two threads on core 0, but the use of the kernel is not essential for the demonstrated functionality.
- The naming of modules
StringDev
andStringBuffers
is tentative. Also, for now, they are just part of the example program, ie. not yet “promoted” to library modules.
Output Terminal
See Set-up, one-terminal set-up.
Build and Run
Build module StringBufOut
with Astrobe, and create and upload the UF2 file using abin2uf2
.
Set Astrobe’s memory options as listed, and the library search path as explained. The program has been developed and tested with kernel-v1, which should be reflected in the library search path.
Repository
-
Better understanding the RP2040’s DMA functionality and creating corresponding library modules is also a prep step for further work on kernel-v2. ↩︎