This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

NRF52840 SPIM3 : Hardware Chip Select Functionality / SDK Support

NRF52840 - SDK 15.0 - Tested with Softdevice and No Softdevice

We have an application that requires deterministic execution of a group of SPI transfers over EasyDMA, where NRF is the SPI master.
The data is grouped as 16, 16-bit transfers - 32 bytes - per "group." The SPIM needs to operate via DMA in full-duplex comm. The unfortunate thing is the slave requires a chip select toggle in between every transfer.
Under the first configuration tested, which is SPIM0 (no hardware CS), and transaction manager, shuffling 32 bytes of data every 0.5 ms (triggered by a timer/IRQ) over SPI and "DMA" takes ~45% of our CPU time - that's pretty atrocious. Even though the easyDMA flag is selected, there is no way this is using DMA and not CPU.

Question 1 : Does SPI Transaction Manager actually use EASY DMA if it's configured? It seems to poll waiting for each 16-bits to be done so that it can then software toggle the CS. I can scope the clock line and see massive, and non-uniform gaps in between each 16 bit SPI transfer, which indicates to me that this isn't DMA, or that it's a just a horribly wasteful driver implementation.

The plan is to use Timers and PPI to use no interrupt, trigger the start of SPI automatically (we will reset the easyDMA pointer register at the end of data acquisition). Since SPIM3 has a hardware chip select, we should be able to assert/de-assert that line via hardware and not using the CPU.

Question 2 : can SPIM w/ easyDMA assert / de-assert CS after each 16-bit transaction* - and if yes, how do we ensure this happens without software intervention? The driver looks like it's poking for a conditional even if extended hardware is defined in the sdk_config. If a start and stop condition has to be explicitly provided each 16-bits, we can use a fork at transaction "0" to start a sub-timer, which subsequently issues the individual SPI starts / stops to create the group, but the starts have to be deterministic or at least a predictable minimal bound of error (i.e. clock stalls described in PPI based on individual peripheral clock speeds/synchronization).

----

*I've seen different DMA architectures handle this differently, from CS asserted until all transfers are complete to a toggle between every single byte when coupled to a DMA controller, which is why I'm asking.

  • Hi,

    1. Yes, the SPIM peripheral always use DMA. But the CPU is still needed to set up transactions and to control the CSN pin (for other instances than SPIM3). When you use very short transactions as in this case (two bytes), then there will be a lot of CPU activity.

    2. Using SPIM3 CSN is handled in HW, but you still need to use the CPU to configure each transaction. Using the driver, I se no other way than configuring separate transaction for each 2 byte (16 bit) transaction. However, it might be possible to use a timer and counter with PPI to suspend the SPI transaction after every two bytes so that you can deassert and assert CSN to ready the slave for the next two bytes. From SPIM chapter in product specification:

    A transaction can be suspended and resumed using the SUSPEND and RESUME tasks, receptively. When the SUSPEND task is triggered the SPI master will complete transmitting and receiving the current ongoing byte before it is suspended.

  • Will the SUSPEND / RESUME definitely hardware toggle the CS pin? Or should I plan on forking a GPIO as CS from the same PPI channel as the SUSPEND/RESUME command is coming from?

  • No, using SUSPEND/RESUME will not toggle the CS pin. There is no explicit support for what you want to do in the nRF HW or SDK, but the idea is that you can use PPI to control both SUSPEND/RESUME and a GPIOTE pin used as CS. Possibly combined with a timer or RTC as you may need a delay after toggling CS before the transaction is resumed (depending on the timing requirements of the SPI slave device).

  • Thank you for your help. I've been testing a timer and GPIOTE so that's looking like the route I'll test.

Related