@@ -6,11 +6,89 @@ import (
66 "device/rp"
77 "runtime/volatile"
88 "unsafe"
9+
10+ pio "github.com/tinygo-org/pio/rp2-pio"
911)
1012
13+ var _DMA = & dmaArbiter {}
14+
15+ type dmaArbiter struct {
16+ claimedChannels uint16
17+ }
18+
19+ // ClaimChannel returns a DMA channel that can be used for DMA transfers.
20+ func (arb * dmaArbiter ) ClaimChannel () (channel dmaChannel , ok bool ) {
21+ for i := uint8 (0 ); i < 12 ; i ++ {
22+ ch := arb .Channel (i )
23+ if ch .Claim () {
24+ return ch , true
25+ }
26+ }
27+ return dmaChannel {}, false
28+ }
29+
30+ func (arb * dmaArbiter ) Channel (channel uint8 ) dmaChannel {
31+ if channel > 11 {
32+ panic ("invalid DMA channel" )
33+ }
34+ // DMA channels usable on the RP2040. 12 in total.
35+ var dmaChannels = (* [12 ]dmaChannelHW )(unsafe .Pointer (rp .DMA ))
36+ return dmaChannel {
37+ hw : & dmaChannels [channel ],
38+ arb : arb ,
39+ idx : channel ,
40+ }
41+ }
42+
1143type dmaChannel struct {
12- hw * dmaChannelHW
13- channel uint8
44+ hw * dmaChannelHW
45+ arb * dmaArbiter
46+ idx uint8
47+ }
48+
49+ // Claim claims the DMA channel for use by a peripheral and returns if it succeeded in claiming the channel.
50+ func (ch dmaChannel ) Claim () bool {
51+ ch .mustValid ()
52+ if ch .IsClaimed () {
53+ return false
54+ }
55+ ch .arb .claimedChannels |= 1 << ch .idx
56+ return true
57+ }
58+
59+ // Unclaim releases the DMA channel so it can be used by other peripherals.
60+ // It does not check if the channel is currently claimed; it force-unclaims the channel.
61+ func (ch dmaChannel ) Unclaim () {
62+ ch .mustValid ()
63+ ch .arb .claimedChannels &^= 1 << ch .idx
64+ }
65+
66+ // IsClaimed returns true if the DMA channel is currently claimed through software.
67+ func (ch dmaChannel ) IsClaimed () bool {
68+ ch .mustValid ()
69+ return ch .arb .claimedChannels & (1 << ch .idx ) != 0
70+ }
71+
72+ // IsValid returns true if the DMA channel was created successfully.
73+ func (ch dmaChannel ) IsValid () bool {
74+ return ch .hw != nil && ch .arb == _DMA
75+ }
76+
77+ // ChannelIndex returns the channel number of the DMA channel. In range 0..11.
78+ func (ch dmaChannel ) ChannelIndex () uint8 { return ch .idx }
79+
80+ // HW returns the hardware registers for this DMA channel.
81+ func (ch dmaChannel ) HW () * dmaChannelHW { return ch .hw }
82+
83+ func (ch dmaChannel ) Init (cfg dmaChannelConfig ) {
84+ ch .mustValid ()
85+ ch .HW ().CTRL_TRIG .Set (cfg .CTRL )
86+ }
87+
88+ func (ch dmaChannel ) mustValid () {
89+ if ! ch .IsValid () {
90+ panic ("use of uninitialized DMA channel" )
91+ }
1492}
1593
1694// Single DMA channel. See rp.DMA_Type.
@@ -30,13 +108,17 @@ const (
30108 spi1DMAChannel
31109)
32110
33- // DMA channels usable on the RP2040.
34- var dmaChannels = (* [12 ]dmaChannelHW )(unsafe .Pointer (rp .DMA ))
111+ // dmaPIO_TREQ returns the Tx DREQ signal for a PIO state machine.
112+ func dmaPIO_TxDREQ (sm pio.StateMachine ) uint32 {
113+ return _DREQ_PIO0_TX0 + uint32 (sm .PIO ().BlockIndex ())* 8 + uint32 (sm .StateMachineIndex ())
114+ }
35115
36- func getDMAChannel (channel uint8 ) * dmaChannel {
37- return & dmaChannel {hw : & dmaChannels [channel ], channel : channel }
116+ // dmaPIO_TREQ returns the Rx DREQ signal for a PIO state machine.
117+ func dmaPIO_RxDREQ (sm pio.StateMachine ) uint32 {
118+ return dmaPIO_TxDREQ (sm ) + 4
38119}
39120
121+ // 2.5.3.1. System DREQ Table. Note: Another caveat is that multiple channels should not be connected to the same DREQ.
40122const (
41123 _DREQ_PIO0_TX0 = 0x0
42124 _DREQ_PIO0_TX1 = 0x1
@@ -80,37 +162,9 @@ const (
80162 _DREQ_XIP_SSIRX = 0x27
81163)
82164
83- type dmaTxSize uint32
84-
85- const (
86- dmaTxSize8 dmaTxSize = iota
87- dmaTxSize16
88- dmaTxSize32
89- )
90-
91- type dmaChannelConfig struct {
92- CTRL uint32
93- }
94-
95- func getDefaultDMAConfig (channel uint32 ) (cc dmaChannelConfig ) {
96- cc .setRing (false , 0 )
97- cc .setBSwap (false )
98- cc .setIRQQuiet (false )
99- cc .setWriteIncrement (false )
100- cc .setSniffEnable (false )
101- cc .setHighPriority (false )
102-
103- cc .setChainTo (channel )
104- cc .setTREQ_SEL (rp .DMA_CH0_CTRL_TRIG_TREQ_SEL_PERMANENT )
105- cc .setReadIncrement (true )
106- cc .setTransferDataSize (dmaTxSize32 )
107- cc .setEnable (true )
108- return cc
109- }
110-
111- // push32 writes each element of src slice into the memory location at dst.
112- func (ch * dmaChannel ) push32 (dst * uint32 , src []uint32 , dreq uint32 ) {
113- hw := ch .hw
165+ // Push32 writes each element of src slice into the memory location at dst.
166+ func (ch dmaChannel ) Push32 (dst * uint32 , src []uint32 , dreq uint32 ) {
167+ hw := ch .HW ()
114168 srcPtr := uint32 (uintptr (unsafe .Pointer (& src [0 ])))
115169 dstPtr := uint32 (uintptr (unsafe .Pointer (dst )))
116170 hw .READ_ADDR .Set (srcPtr )
@@ -121,7 +175,7 @@ func (ch *dmaChannel) push32(dst *uint32, src []uint32, dreq uint32) {
121175 cc .CTRL = hw .CTRL_TRIG .Get ()
122176 cc .setTREQ_SEL (dreq )
123177 cc .setTransferDataSize (dmaTxSize32 )
124- cc .setChainTo (uint32 ( ch .channel ) )
178+ cc .setChainTo (ch .idx )
125179 cc .setReadIncrement (true )
126180 cc .setWriteIncrement (false )
127181 cc .setEnable (true )
@@ -138,9 +192,9 @@ func (ch *dmaChannel) push32(dst *uint32, src []uint32, dreq uint32) {
138192 }
139193}
140194
141- // pull32 reads the memory location at src into dst slice, incrementing dst pointer but not src.
142- func (ch * dmaChannel ) pull32 (dst []uint32 , src * uint32 , dreq uint32 ) {
143- hw := ch .hw
195+ // Pull32 reads the memory location at src into dst slice, incrementing dst pointer but not src.
196+ func (ch dmaChannel ) Pull32 (dst []uint32 , src * uint32 , dreq uint32 ) {
197+ hw := ch .HW ()
144198 srcPtr := uint32 (uintptr (unsafe .Pointer (src )))
145199 dstPtr := uint32 (uintptr (unsafe .Pointer (& dst [0 ])))
146200 hw .READ_ADDR .Set (srcPtr )
@@ -151,7 +205,7 @@ func (ch *dmaChannel) pull32(dst []uint32, src *uint32, dreq uint32) {
151205 cc .CTRL = hw .CTRL_TRIG .Get ()
152206 cc .setTREQ_SEL (dreq )
153207 cc .setTransferDataSize (dmaTxSize32 )
154- cc .setChainTo (uint32 ( ch .channel ) )
208+ cc .setChainTo (ch .idx )
155209 cc .setReadIncrement (false )
156210 cc .setWriteIncrement (true )
157211 cc .setEnable (true )
@@ -171,13 +225,13 @@ func (ch *dmaChannel) pull32(dst []uint32, src *uint32, dreq uint32) {
171225// abort aborts the current transfer sequence on the channel and blocks until
172226// all in-flight transfers have been flushed through the address and data FIFOs.
173227// After this, it is safe to restart the channel.
174- func (ch * dmaChannel ) abort () {
228+ func (ch dmaChannel ) abort () {
175229 // Each bit corresponds to a channel. Writing a 1 aborts whatever transfer
176230 // sequence is in progress on that channel. The bit will remain high until
177231 // any in-flight transfers have been flushed through the address and data FIFOs.
178232 // After writing, this register must be polled until it returns all-zero.
179233 // Until this point, it is unsafe to restart the channel.
180- chMask := uint32 (1 << ch .channel )
234+ chMask := uint32 (1 << ch .idx )
181235 rp .DMA .CHAN_ABORT .Set (chMask )
182236 retries := timeoutRetries
183237 for rp .DMA .CHAN_ABORT .Get ()& chMask != 0 && retries > 0 {
@@ -189,8 +243,37 @@ func (ch *dmaChannel) abort() {
189243 }
190244}
191245
192- func (ch * dmaChannel ) busy () bool {
193- return ch .hw .CTRL_TRIG .Get ()& rp .DMA_CH0_CTRL_TRIG_BUSY != 0
246+ func (ch dmaChannel ) busy () bool {
247+ hw := ch .HW ()
248+ return hw .CTRL_TRIG .Get ()& rp .DMA_CH0_CTRL_TRIG_BUSY != 0
249+ }
250+
251+ type dmaTxSize uint32
252+
253+ const (
254+ dmaTxSize8 dmaTxSize = iota
255+ dmaTxSize16
256+ dmaTxSize32
257+ )
258+
259+ type dmaChannelConfig struct {
260+ CTRL uint32
261+ }
262+
263+ func dmaDefaultConfig (channel uint8 ) (cc dmaChannelConfig ) {
264+ cc .setRing (false , 0 )
265+ cc .setBSwap (false )
266+ cc .setIRQQuiet (false )
267+ cc .setWriteIncrement (false )
268+ cc .setSniffEnable (false )
269+ cc .setHighPriority (false )
270+
271+ cc .setChainTo (channel )
272+ cc .setTREQ_SEL (rp .DMA_CH0_CTRL_TRIG_TREQ_SEL_PERMANENT )
273+ cc .setReadIncrement (true )
274+ cc .setTransferDataSize (dmaTxSize32 )
275+ // cc.setEnable(true)
276+ return cc
194277}
195278
196279// Select a Transfer Request signal. The channel uses the transfer request signal
@@ -200,8 +283,8 @@ func (cc *dmaChannelConfig) setTREQ_SEL(dreq uint32) {
200283 cc .CTRL = (cc .CTRL & ^ uint32 (rp .DMA_CH0_CTRL_TRIG_TREQ_SEL_Msk )) | (uint32 (dreq ) << rp .DMA_CH0_CTRL_TRIG_TREQ_SEL_Pos )
201284}
202285
203- func (cc * dmaChannelConfig ) setChainTo (chainTo uint32 ) {
204- cc .CTRL = (cc .CTRL & ^ uint32 (rp .DMA_CH0_CTRL_TRIG_CHAIN_TO_Msk )) | (chainTo << rp .DMA_CH0_CTRL_TRIG_CHAIN_TO_Pos )
286+ func (cc * dmaChannelConfig ) setChainTo (chainTo uint8 ) {
287+ cc .CTRL = (cc .CTRL & ^ uint32 (rp .DMA_CH0_CTRL_TRIG_CHAIN_TO_Msk )) | (uint32 ( chainTo ) << rp .DMA_CH0_CTRL_TRIG_CHAIN_TO_Pos )
205288}
206289
207290func (cc * dmaChannelConfig ) setTransferDataSize (size dmaTxSize ) {
@@ -257,3 +340,7 @@ func setBitPos(cc *uint32, pos uint32, bit bool) {
257340 * cc = * cc & ^ (1 << pos ) // unset bit.
258341 }
259342}
343+
344+ func ptrAs [T ~ uint32 ](ptr * T ) uint32 {
345+ return uint32 (uintptr (unsafe .Pointer (ptr )))
346+ }
0 commit comments