Skip to content

Commit 77dca35

Browse files
committed
docs: Add documentation for rp2 DMA support.
Signed-off-by: Nicko van Someren <nicko@nicko.org>
1 parent 516385c commit 77dca35

File tree

3 files changed

+174
-0
lines changed

3 files changed

+174
-0
lines changed

docs/library/rp2.DMA.rst

Lines changed: 172 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,172 @@
1+
.. currentmodule:: rp2
2+
.. _rp2.DMA:
3+
4+
class DMA -- access to the RP2040's DMA controller
5+
==================================================
6+
7+
The :class:`DMA` class gives access the channels in the RP2040's Direct Memory Access (DMA)
8+
controller, providing the ability move data between memory blocks and/or IO registers. The DMA
9+
controller has its own, separate read and write master connections onto the bus fabric and each DMA
10+
channel can independently read data from one address and write it back to another address,
11+
optionally incrementing one or both pointers, allowing it to perform transfers on behalf of the
12+
process while the processor carries out other tasks or enters a low power state. The RP2040's DMA
13+
controller has 12 independent DMA channels that can run concurrently. For full details of the
14+
RP2040's DMA system see section 2.5 of the `RP2040 Datasheet
15+
<https://datasheets.raspberrypi.org/rp2040/rp2040-datasheet.pdf>`_.
16+
17+
18+
Examples
19+
--------
20+
21+
The simplest use of the DMA controller is to move data from one block of memory to another.
22+
This can be accomplished with the following code::
23+
24+
a = bytearray(32*1024)
25+
b = bytearray(32*1024)
26+
d = rp2.DMA()
27+
c = d.pack_ctrl() # Just use the default control value.
28+
# The count is in transfers, which default to four-byte words, so divide length by 4
29+
d.setup(read=a, write=b, count=len(a)//4, config=c, trigger=True)
30+
# Wait for completion
31+
while d.active:
32+
pass
33+
34+
Note that while this example sits in an idle loop while it waits for the transfer to complete,
35+
the program could just as well do some useful work in this time instead.
36+
37+
Another, perhaps more common use of the DMA controller is to transfer between memory and an IO
38+
peripheral. In this situation the address of the IO register does not change for each transfer but
39+
the memory address needs to be incremented. It is also necessary to control the pace of the
40+
transfer so as to not write data before it can be accepted by a peripheral or read it before the
41+
data is read, and this can be controlled with the ``treq_sel`` field of the DMA channel's control
42+
register. The various fields of the control register for each DMA channel can be packed
43+
using the :meth:`DMA.pack_crtl()` method and unpacked using the :meth:`DMA.unpack_crtl()`
44+
static method. Code to transfer data from a byte array to the TX FIFO of a PIO state machine,
45+
one byte at a time, looks like this::
46+
47+
# pio_num is index of the PIO block being used, sm_num is the state machine in that block.
48+
# my_state_machine is an rp2.PIO() instance.
49+
DATA_REQUEST_INDEX = (pio_num << 3) + sm_num
50+
51+
src_data = bytearray(1024)
52+
d = rp2.DMA()
53+
54+
# Transfer bytes, rather than words, don't increment the write address and pace the transfer.
55+
c = d.pack_ctrl(size=0, inc_write=False, c.treq_sel=DATA_REQUEST_INDEX)
56+
57+
d.setup(
58+
read=src_data,
59+
write=my_state_machine.get_fifo_addr(False), # The address of the write FIFO
60+
count=len(a),
61+
config=c,
62+
trigger=True
63+
)
64+
65+
66+
67+
Constructor
68+
-----------
69+
70+
.. class:: DMA( )
71+
72+
Claim one of the DMA controller channels for exclusive use.
73+
74+
75+
Methods
76+
-------
77+
78+
.. method:: DMA.config(read=None, write=None, count=None, ctrl=None, trigger=False)
79+
80+
Configure the DMA registers for the channel and optionally start the transfer.
81+
82+
:param read: The address from which the DMA controller will start reading data or
83+
an object that will provide data to be read. It can be an integer or any
84+
object that supports the buffer protocol.
85+
:param write: The address to which the DMA controller will start writing or an
86+
object into which data will be written. It can be an integer or any object
87+
that supports the buffer protocol.
88+
:param count: The number of bus transfers that will execute before this channel
89+
stops. Note that this is the number of transfers, not the number of bytes.
90+
If the transfers are 2 or 4 bytes wide then the total amount of data moved
91+
(and thus the size of required buffer) needs to be multiplied accordingly.
92+
:param ctrl: The value for the DMA control register. This is an integer value
93+
that is typically packed using the :meth:`DMA.pack_ctrl()`.
94+
:param trigger: Optionally commence the transfer immediately.
95+
96+
.. method:: DMA.irq(handler=None, hard=False)
97+
98+
Returns the IRQ object for this DMA channel and optionally configures it.
99+
100+
.. method:: DMA.close()
101+
102+
Release the claim on the underlying DMA channel and free the interrupt
103+
handler. The :class:`DMA` object can not be used after this operation.
104+
105+
.. method:: DMA.pack_crtl(default=None, **kwargs)
106+
107+
Pack the values provided in the keyword arguments into the named fields of a new control
108+
register value. Any field that is not provided will be set to a default value. The
109+
default will either be taken from the provided ``default`` value, or if that is not
110+
given, a default suitable for the current channel.
111+
112+
The keys for the keyword arguments can be any key returned by the :meth:`DMA.unpack_crtl()`
113+
method. That method will also return values for the read-only fields in the control register;
114+
these values will be ignored when packing, so that the dictionary created by unpacking a
115+
control register can be used directly as the keyword arguments for packing.
116+
117+
.. method:: DMA.unpack_crtl(value)
118+
119+
Unpack a value for a DMA channel control register into a dictionary with key/value pairs
120+
for each of the fields in the control register.
121+
122+
:param value: The ``crtl`` register value to unpack.
123+
124+
125+
126+
Attributes
127+
----------
128+
129+
.. attribute:: DMA.active
130+
131+
An attribute to get or set whether the DMA channel is currently running.
132+
133+
>>> sm.active
134+
0
135+
>>> sm.active = 1
136+
>>> while sm.active:
137+
... pass
138+
139+
.. attribute:: DMA.read
140+
141+
This attribute reflects the address from which the next bus transfer
142+
will read. May be written with either an integer or an object
143+
that supports the buffer protocol and doing so has immediate effect.
144+
145+
.. attribute:: DMA.write
146+
147+
This attribute reflects the address to which the next bus transfer
148+
will write. May be written with either an integer or an object
149+
that supports the buffer protocol and doing so has immediate effect.
150+
151+
.. attribute:: DMA.count
152+
153+
Reading this attribute will return the number of remaining bus
154+
transfers in the *current* transfer sequence. Writing this attribute
155+
sets the total number of transfers to be the *next* transfer sequence.
156+
157+
.. attribute:: DMA.ctrl
158+
159+
This attribute reflects DMA channel control register. It is typicall written
160+
with an integer packed using the :meth:`DMA.pack_crtl()` method. The returned
161+
register value can be unpacked using the :meth:`DMA.unpack_crtl()` method.
162+
163+
.. attribute:: DMA.channel_id
164+
165+
The channel number of the DMA channel.
166+
167+
.. attribute:: DMA.registers
168+
169+
This attribute is an array-like object that allows direct access to
170+
the DMA channel's registers. The index is by word, rather than by byte,
171+
so the register indicies are the register address offsets divided by 4.
172+
See the RP2040 data sheet for register details.

docs/library/rp2.StateMachine.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,3 +140,4 @@ Methods
140140

141141
Optionally configure it.
142142

143+
.. method:: StateMachine.get_fifo_proxy(read_not_write)

docs/library/rp2.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -244,3 +244,4 @@ Classes
244244
rp2.Flash.rst
245245
rp2.PIO.rst
246246
rp2.StateMachine.rst
247+
rp2.DMA.rst

0 commit comments

Comments
 (0)