Using DMA SPI w. WCE and Colibri T20

We are trying to acquire data from an ADC via the SPI port. The sampling rate is 500ksps with 16bits per sample and we need to acquire continuously, as we display the data on screen (with some downsampling).

DMA seemed the natural way of doing this, instead of CPU intensive polling.
We would like to set the SPI in DMA mode to read from the SPI straight into memory, possibly to one of two buffers. While data is being written by DMA to buffer 0, we display the data already in the second buffer. As buffer 0 is filled, the application switches to display these data, and acquisition proceeds to fill buffer 1.

Is there a specific SPIDMALib library? As we click on SPILib / SPIDMALib in the table of libraries (Toradex CE Libraries and Code Samples | Toradex Developer Center) we are directed to a page that reads: “This library manages the SPI interfaces via polling”.

How can we achieve truly continuous acquisition via SPI (no lost samples)? What would be the latency (silent SPI) while switching from buffer 0 to buffer 1 (i.e. betwren issuing two requests for acquisition of a large block of data?

Alternatively, any suggestion as to how to cycle a single buffer for continuous acquisition?

Just to be more specific:

A link to documentation or examples specifically on DMA SPI use with Colibri would be much appreciated.

Further, is “#define SPI_DMA_ENABLE TRUE” enough to switch from polling to DMA?

In the library package provided here you find a SPIDMA demo. Just use this one as reference. The lib currently does not foresee swapping buffers. In case you need a higher performance you could purchase the library source code for 2 support hours and start tweaking there to meet your requirements. I would recommend you to give it a try first as it is and check how much you would need to improve.

SPI DMA mode.

The demo code by Toradex (spi_dma_lib_demo in wincelib_v2_0bis_2868.zip) uses SPIReadWritePolling.
However several lines of code have been commented out and these would call SPIReadWrite.

Testing with an oscilloscope it looks as if SPIReadWrite() is the actual DMA code, as opposed to SPIReadWritePolling(), which drives CS up and down for each 32bytes, adding latency.

Should we use SPIReadWrite() for DMA. If so, what is the max number of frames when calling SPIReadWrite()? Around 120kbits seem to be the maximum DMA transfer.

Anyone can shed some light on this?

In case others might benefit from our progress:

  1. We have seen with an oscilloscope that SPIReadWrite() transmits a maximum of around 15000 packets, each packet with 1 to 32 bits.
  2. This is (possibly) consistent with the max block size for the Tegra 2 DMA, which is set with a 16 bits register, i.e. the max block size transmitted by the DMA is 65535. This info was found in the NVIA Tegra 2 technical ref manual.
    Assuming that the DMA block size is configured in bytes, then 65535 bytes would amount to around 15000 packets of 32 bits (4 bytes each).

We conclude that SPIReadWrite() is breaking up the data into chunks as big as allowed by the Tegra 2 DMA (65536 bytes each, equivalent to 65536/4 packets of 4 bytes each). In between blocks the latency can be as large as 25 milliseconds.

It seems that the existing SPI DMA lib can not do continuous DMA data acquisition from an ADC without data loss (at least not at sampling frequencies above 100 samples per second or so).