Skip to content

Commit 459d169

Browse files
BriscoeTechBriscoeTech
authored andcommitted
added the automatic firing of multiple dma transactions if the transfer size is over 65535 bytes. This should work for poling or asynchronous dma transfers.
* addDescriptor and changeDescriptor in Adafruit_ZeroDMA function signature changed. Count parameter changed to be a uint16_t instead of uint32_t. Reflects the limitation that desc->BTCNT.reg is a uint16_t and cannot actually accept a uint32_t value. * Not tested on hardware yet, pushed so it can be read by others. Will test on hardware soon. Need to make sure line 312 and 313 pointer assignment math in checkDmaComplete actually works properly.
1 parent c9400ea commit 459d169

File tree

4 files changed

+94
-29
lines changed

4 files changed

+94
-29
lines changed

libraries/Adafruit_ZeroDMA/Adafruit_ZeroDMA.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -449,7 +449,7 @@ bool Adafruit_ZeroDMA::isActive(void) const {
449449
DmacDescriptor *Adafruit_ZeroDMA::addDescriptor(
450450
void *src,
451451
void *dst,
452-
uint32_t count,
452+
uint16_t count,
453453
dma_beat_size size,
454454
bool srcInc,
455455
bool dstInc,
@@ -537,7 +537,7 @@ DmacDescriptor *Adafruit_ZeroDMA::addDescriptor(
537537
// etc.) are unchanged. Mostly for changing the data being pushed to a
538538
// peripheral (DAC, SPI, whatev.)
539539
void Adafruit_ZeroDMA::changeDescriptor(DmacDescriptor *desc,
540-
void *src, void *dst, uint32_t count) {
540+
void *src, void *dst, uint16_t count) {
541541

542542
uint8_t bytesPerBeat; // Beat transfer size IN BYTES
543543
switch(desc->BTCTRL.bit.BEATSIZE) {

libraries/Adafruit_ZeroDMA/Adafruit_ZeroDMA.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,13 +41,13 @@ class Adafruit_ZeroDMA {
4141
uint8_t getChannel(void) const { return channel; }
4242

4343
// DMA descriptor functions
44-
DmacDescriptor *addDescriptor(void *src, void *dst, uint32_t count = 0,
44+
DmacDescriptor *addDescriptor(void *src, void *dst, uint16_t count = 0,
4545
dma_beat_size size = DMA_BEAT_SIZE_BYTE,
4646
bool srcInc = true, bool dstInc = true,
4747
uint32_t stepSize = DMA_ADDRESS_INCREMENT_STEP_SIZE_1,
4848
bool stepSel = DMA_STEPSEL_DST);
4949
void changeDescriptor(DmacDescriptor *d, void *src = NULL,
50-
void *dst = NULL, uint32_t count = 0);
50+
void *dst = NULL, uint16_t count = 0);
5151
bool isActive(void) const;
5252

5353
void _IRQhandler(uint8_t flags); // DO NOT TOUCH

libraries/SPI/SPI.cpp

Lines changed: 76 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -275,16 +275,8 @@ void SPIClass::dmaCallback_read(Adafruit_ZeroDMA *dma)
275275
// flag this part of the dma done
276276
spiPtr[channel]->dma_read_done = true;
277277

278-
// read and write dmas are both done
279-
if(spiPtr[channel]->dma_read_done && spiPtr[channel]->dma_write_done)
280-
{
281-
// is a user specified callback to call on completion
282-
if(spiPtr[channel]->userDmaCallback != NULL)
283-
{
284-
// call the callback function the user specified
285-
spiPtr[channel]->userDmaCallback();
286-
}
287-
}
278+
// see if the entire transaction is completed
279+
checkDmaComplete(channel);
288280
}
289281

290282
// dma callback when the write part is completed
@@ -298,15 +290,43 @@ void SPIClass::dmaCallback_write(Adafruit_ZeroDMA *dma)
298290
// flag this part of the dma done
299291
spiPtr[channel]->dma_write_done = true;
300292

293+
// see if the entire transaction is completed
294+
checkDmaComplete(channel);
295+
296+
}
297+
298+
// see if the entire dma transaction is completed
299+
// will automatically initiate another dma if we have bytes remaining to transfer
300+
void SPIClass::checkDmaComplete(uint8_t channel)
301+
{
301302
// read and write dmas are both done
302303
if(spiPtr[channel]->dma_read_done && spiPtr[channel]->dma_write_done)
303304
{
304-
// is a user specified callback to call on completion
305-
if(spiPtr[channel]->userDmaCallback != NULL)
305+
// are more bytes that need to be transfered
306+
// fire another dma transaction
307+
if( (spiPtr[channel]->dma_bytes_remaining) > 0)
306308
{
307-
// call the callback function the user specified
308-
spiPtr[channel]->userDmaCallback();
309+
// initiate another transfer for the next section of bytes
310+
// update buffer pointers offsets
311+
// use the same user callback as last time if any
312+
void* txbuf = spiPtr[channel]->txbuf_last + DMA_MAX_TRANSFER_SIZE;
313+
void* rxbuf = spiPtr[channel]->rxbuf_last + DMA_MAX_TRANSFER_SIZE;
314+
spiPtr[channel]->transfer(txbuf, rxbuf, spiPtr[channel]->dma_bytes_remaining, spiPtr[channel]->userDmaCallback );
309315
}
316+
// the transfer is completed, no bytes remaining
317+
else
318+
{
319+
// flag as completed for anything poling for completion
320+
spiPtr[channel]->dma_complete = true;
321+
322+
// call the callback function the user specified if any
323+
if(spiPtr[channel]->userDmaCallback != NULL)
324+
{
325+
spiPtr[channel]->userDmaCallback();
326+
}
327+
328+
}
329+
310330
}
311331
}
312332

@@ -326,7 +346,7 @@ void SPIClass::transfer(const void* txbuf, void* rxbuf, uint32_t count, bool blo
326346
// Waits for a prior in-background DMA transfer to complete.
327347
void SPIClass::waitForTransfer(void)
328348
{
329-
while( !dma_read_done || !dma_write_done )
349+
while( !dma_complete )
330350
{
331351
// do nothing, wait for transfer completion
332352
}
@@ -337,9 +357,42 @@ void SPIClass::waitForTransfer(void)
337357
// the callback parameter should be passed in by the user, it is called when the dma is done
338358
void SPIClass::transfer(void* txbuf, void* rxbuf, uint32_t count, void (*functionToCallWhenComplete)(void) )
339359
{
340-
// save this function to call when the dma is done
360+
// remember these buffer pointers
361+
// will reuse if we have to do multiple dma transactions and pointer math
362+
txbuf_last = txbuf;
363+
rxbuf_last = rxbuf;
364+
365+
// save this function to call when the entire dma is done
341366
userDmaCallback = functionToCallWhenComplete;
342367

368+
// Maximum bytes per DMA descriptor is 65,535 (NOT 65,536).
369+
// We could set up a descriptor chain, but that gets more
370+
// complex. For now, instead, break up long transfers into
371+
// chunks of 65,535 bytes max...these transfers are all
372+
// blocking, regardless of the "block" argument, except
373+
// for the last one which will observe the background request.
374+
// The fractional part is done first, so for any "partially
375+
// blocking" transfers like these at least it's the largest
376+
// single-descriptor transfer possible that occurs in the
377+
// background, rather than the tail end.
378+
uint16_t bytesThisPass;
379+
380+
if(count > DMA_MAX_TRANSFER_SIZE)
381+
{
382+
// Too big for 1 descriptor
383+
// will need to do multiple dma transfers
384+
bytesThisPass = DMA_MAX_TRANSFER_SIZE;
385+
386+
// remember bytes remaining for future transfers
387+
dma_bytes_remaining = count - DMA_MAX_TRANSFER_SIZE;
388+
}
389+
else
390+
{
391+
// can do everything in one dma transfer
392+
bytesThisPass = count;
393+
dma_bytes_remaining = 0;
394+
}
395+
343396
//******************************
344397
// If the RX DMA channel is not yet allocated...
345398
if(readChannel.getChannel() >= DMAC_CH_NUM)
@@ -349,7 +402,7 @@ void SPIClass::transfer(void* txbuf, void* rxbuf, uint32_t count, void (*functio
349402
readDescriptor = readChannel.addDescriptor(
350403
(void *)getDataRegister(), // Source address (SPI data reg)
351404
rxbuf, // Dest address
352-
count, // Count
405+
bytesThisPass, // bytes to transfer
353406
DMA_BEAT_SIZE_BYTE, // Bytes/hwords/words
354407
false, // Don't increment source address
355408
true); // Increment dest address
@@ -366,7 +419,7 @@ void SPIClass::transfer(void* txbuf, void* rxbuf, uint32_t count, void (*functio
366419
readDescriptor,
367420
(void *)getDataRegister(), // Source address (SPI data reg)
368421
rxbuf, // Dest address
369-
count); // Count
422+
bytesThisPass); // bytes to transfer
370423
}
371424

372425
// If the TX DMA channel is not yet allocated...
@@ -377,7 +430,7 @@ void SPIClass::transfer(void* txbuf, void* rxbuf, uint32_t count, void (*functio
377430
writeDescriptor = writeChannel.addDescriptor(
378431
txbuf, // Source address
379432
(void *)getDataRegister(), // Dest (SPI data register)
380-
count, // Count
433+
bytesThisPass, // bytes to transfer
381434
DMA_BEAT_SIZE_BYTE, // Bytes/hwords/words
382435
true, // Increment source address
383436
false); // Don't increment dest address
@@ -394,14 +447,16 @@ void SPIClass::transfer(void* txbuf, void* rxbuf, uint32_t count, void (*functio
394447
writeDescriptor,
395448
txbuf, // Source address
396449
(void *)getDataRegister(), // Dest (SPI data register)
397-
count); // Count
450+
bytesThisPass); // bytes to transfer
398451
}
399452

400453
//******************************
401454
// clear the flags
402-
// fire the dma transactions
403455
dma_read_done = false;
404456
dma_write_done = false;
457+
dma_complete = false;
458+
459+
// fire the dma transactions
405460
readChannel.startJob();
406461
writeChannel.startJob();
407462
}

libraries/SPI/SPI.h

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -170,16 +170,26 @@ class SPIClass {
170170
char interruptSave;
171171
uint32_t interruptMask;
172172

173-
// objects and functions used for dma transfer
173+
//***********************************************************
174+
// constants, objects, and functions used for dma transfers
175+
176+
#define DMA_MAX_TRANSFER_SIZE 65535 // maximum bytes a dma can transfer per transaction
177+
174178
Adafruit_ZeroDMA readChannel;
175179
Adafruit_ZeroDMA writeChannel;
176180
DmacDescriptor *readDescriptor = NULL;
177181
DmacDescriptor *writeDescriptor = NULL;
178-
volatile bool dma_write_done = false;
179-
volatile bool dma_read_done = false;
180-
size_t dma_bytes_remaining;
182+
183+
volatile bool dma_write_done = false; // true when read dma callback completes
184+
volatile bool dma_read_done = false; // true when write dma callback completes
185+
uint32_t dma_bytes_remaining; // number of bytes remaining for future dma transactions
186+
volatile bool dma_complete = false; // all transactions completed and no bytes remaining
187+
void* txbuf_last; // pointer to buffer last used
188+
void* rxbuf_last; // pointer to buffer last used
189+
181190
static void dmaCallback_read(Adafruit_ZeroDMA *dma);
182191
static void dmaCallback_write(Adafruit_ZeroDMA *dma);
192+
static void checkDmaComplete(uint8_t channel);
183193
void (*userDmaCallback)(void) = NULL; //function pointer to users dma callback function
184194

185195
};

0 commit comments

Comments
 (0)