@@ -86,6 +86,12 @@ func (ch dmaChannel) Init(cfg dmaChannelConfig) {
8686 ch .HW ().CTRL_TRIG .Set (cfg .CTRL )
8787}
8888
89+ // CurrentConfig copies the actual configuration of the DMA channel.
90+ func (ch dmaChannel ) CurrentConfig () dmaChannelConfig {
91+ ch .mustValid ()
92+ return dmaChannelConfig {CTRL : ch .HW ().CTRL_TRIG .Get ()}
93+ }
94+
8995func (ch dmaChannel ) mustValid () {
9096 if ! ch .IsValid () {
9197 panic ("use of uninitialized DMA channel" )
@@ -165,64 +171,135 @@ const (
165171
166172// Push32 writes each element of src slice into the memory location at dst.
167173func (ch dmaChannel ) Push32 (dst * uint32 , src []uint32 , dreq uint32 ) error {
174+ return dmaPush (ch , dst , src , dreq )
175+ }
176+
177+ // Push16 writes each element of src slice into the memory location at dst.
178+ func (ch dmaChannel ) Push16 (dst * uint16 , src []uint16 , dreq uint32 ) error {
179+ return dmaPush (ch , dst , src , dreq )
180+ }
181+
182+ // Push8 writes each element of src slice into the memory location at dst.
183+ func (ch dmaChannel ) Push8 (dst * byte , src []byte , dreq uint32 ) error {
184+ return dmaPush (ch , dst , src , dreq )
185+ }
186+
187+ // Push32 writes each element of src slice into the memory location at dst.
188+ func dmaPush [T uint8 | uint16 | uint32 ](ch dmaChannel , dst * T , src []T , dreq uint32 ) error {
168189 hw := ch .HW ()
190+ hw .CTRL_TRIG .ClearBits (rp .DMA_CH0_CTRL_TRIG_EN_Msk )
169191 srcPtr := uint32 (uintptr (unsafe .Pointer (& src [0 ])))
170192 dstPtr := uint32 (uintptr (unsafe .Pointer (dst )))
171193 hw .READ_ADDR .Set (srcPtr )
172194 hw .WRITE_ADDR .Set (dstPtr )
173195 hw .TRANS_COUNT .Set (uint32 (len (src )))
196+
174197 // memfence
175- var cc dmaChannelConfig
176- cc . CTRL = hw . CTRL_TRIG . Get ()
198+
199+ cc := ch . CurrentConfig ()
177200 cc .setTREQ_SEL (dreq )
178- cc .setTransferDataSize (dmaTxSize32 )
201+ cc .setTransferDataSize (dmaSize [ T ]() )
179202 cc .setChainTo (ch .idx )
180203 cc .setReadIncrement (true )
181204 cc .setWriteIncrement (false )
182205 cc .setEnable (true )
183206
207+ deadline := ch .dl .newDeadline ()
208+ // If currently busy we wait.
209+ for ch .busy () {
210+ if deadline .expired () {
211+ return errContentionTimeout
212+ }
213+ gosched ()
214+ }
215+
216+ // We begin our DMA transfer here!
184217 hw .CTRL_TRIG .Set (cc .CTRL )
185218
186- deadline : = ch .dl .newDeadline ()
219+ deadline = ch .dl .newDeadline ()
187220 for ch .busy () {
188221 if deadline .expired () {
222+ ch .abort ()
189223 return errTimeout
190224 }
191225 gosched ()
192226 }
227+ hw .CTRL_TRIG .ClearBits (rp .DMA_CH0_CTRL_TRIG_EN_Msk )
193228 return nil
194229}
195230
196231// Pull32 reads the memory location at src into dst slice, incrementing dst pointer but not src.
197232func (ch dmaChannel ) Pull32 (dst []uint32 , src * uint32 , dreq uint32 ) error {
233+ return dmaPull (ch , dst , src , dreq )
234+ }
235+
236+ // Pull16 reads the memory location at src into dst slice, incrementing dst pointer but not src.
237+ func (ch dmaChannel ) Pull16 (dst []uint16 , src * uint16 , dreq uint32 ) error {
238+ return dmaPull (ch , dst , src , dreq )
239+ }
240+
241+ // Pull8 reads the memory location at src into dst slice, incrementing dst pointer but not src.
242+ func (ch dmaChannel ) Pull8 (dst []byte , src * byte , dreq uint32 ) error {
243+ return dmaPull (ch , dst , src , dreq )
244+ }
245+
246+ // Pull32 reads the memory location at src into dst slice, incrementing dst pointer but not src.
247+ func dmaPull [T uint8 | uint16 | uint32 ](ch dmaChannel , dst []T , src * T , dreq uint32 ) error {
198248 hw := ch .HW ()
249+ hw .CTRL_TRIG .ClearBits (rp .DMA_CH0_CTRL_TRIG_EN_Msk )
199250 srcPtr := uint32 (uintptr (unsafe .Pointer (src )))
200251 dstPtr := uint32 (uintptr (unsafe .Pointer (& dst [0 ])))
201252 hw .READ_ADDR .Set (srcPtr )
202253 hw .WRITE_ADDR .Set (dstPtr )
203254 hw .TRANS_COUNT .Set (uint32 (len (dst )))
255+
204256 // memfence
205- var cc dmaChannelConfig
206- cc . CTRL = hw . CTRL_TRIG . Get ()
257+
258+ cc := ch . CurrentConfig ()
207259 cc .setTREQ_SEL (dreq )
208- cc .setTransferDataSize (dmaTxSize32 )
260+ cc .setTransferDataSize (dmaSize [ T ]() )
209261 cc .setChainTo (ch .idx )
210262 cc .setReadIncrement (false )
211263 cc .setWriteIncrement (true )
212264 cc .setEnable (true )
213265
266+ // If currently busy we wait.
267+ deadline := ch .dl .newDeadline ()
268+ for ch .busy () {
269+ if deadline .expired () {
270+ return errContentionTimeout
271+ }
272+ gosched ()
273+ }
274+
275+ // We begin our DMA transfer here!
214276 hw .CTRL_TRIG .Set (cc .CTRL )
215277
216- deadline : = ch .dl .newDeadline ()
278+ deadline = ch .dl .newDeadline ()
217279 for ch .busy () {
218280 if deadline .expired () {
281+ ch .abort ()
219282 return errTimeout
220283 }
221284 gosched ()
222285 }
223286 return nil
224287}
225288
289+ func dmaSize [T uint8 | uint16 | uint32 ]() dmaTxSize {
290+ var a T
291+ switch unsafe .Sizeof (a ) {
292+ case 1 :
293+ return dmaTxSize8
294+ case 2 :
295+ return dmaTxSize16
296+ case 4 :
297+ return dmaTxSize32
298+ default :
299+ panic ("invalid DMA transfer size" )
300+ }
301+ }
302+
226303// abort aborts the current transfer sequence on the channel and blocks until
227304// all in-flight transfers have been flushed through the address and data FIFOs.
228305// After this, it is safe to restart the channel.
@@ -234,13 +311,14 @@ func (ch dmaChannel) abort() {
234311 // Until this point, it is unsafe to restart the channel.
235312 chMask := uint32 (1 << ch .idx )
236313 rp .DMA .CHAN_ABORT .Set (chMask )
237- retries := timeoutRetries
238- for rp .DMA .CHAN_ABORT .Get ()& chMask != 0 && retries > 0 {
314+
315+ deadline := ch .dl .newDeadline ()
316+ for rp .DMA .CHAN_ABORT .Get ()& chMask != 0 {
317+ if deadline .expired () {
318+ println ("DMA abort timeout" )
319+ break
320+ }
239321 gosched ()
240- retries --
241- }
242- if retries == 0 {
243- println ("DMA abort timeout" )
244322 }
245323}
246324
0 commit comments