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

Clarification on SPI double buffer and EVENTS_READY

First: nRF52840 dongle or nRF52840-Preview_DK (doesn't matter which I get the same issue), SDK17.0.2, Segger, Windows 10.  I am trying to dump a FIFO buffer from a sensor as fast as possible.  I thought I had it working, but then I realized that my rx_buffer in the nrf52840 was all 0s.  Then I saw that I might need to use the EVENTS_READY flag in this post.  I have been trying to figure out how to get this to work using the datasheet so that I don't need to use the interrupt system (too slow), but the code I have doesn't quite do it.  I get 24 clocks, I see the correct data on the MOSI pin, and I'm pretty sure on the MISO pin as well, but I never see the CS go high.  I guess this tells me that somehow the last while (!EVENTS_READY) is hanging, but if I remove it I don't get the correct result either.

// First time through, fill the double buffer
NRF_SPI0->TXD = FIFO_DATA_OUT_L | 0x80; // TXD = FIFO, RXD-1 = 0xFF
NRF_SPI0->TXD = 0xFF;  // TXD = 0xFF, TXD+1 = FIFO, RXD = 0xFF, RXD-1 = Byte1

// Read garbage (0xFF) from address TX when Event is ready
while (!NRF_SPI0->EVENTS_READY);
NRF_SPI0->EVENTS_READY = 0;

(void)NRF_SPI0->RXD; // After this line: TXD = 0xFF, TXD+1 = FIFO, RXD = Byte1, RXD-1 = ?

// Now we can push the last TX into the double buffer
NRF_SPI0->TXD = 0xFF;

// Now read data when Event is ready
while (!NRF_SPI0->EVENTS_READY);
NRF_SPI0->EVENTS_READY = 0;

ble_buff[ble_idx++] = (uint8_t)NRF_SPI0->RXD;

// Now read data when Event is ready
// while (!NRF_SPI0->EVENTS_READY);
// NRF_SPI0->EVENTS_READY = 0;

ble_buff[ble_idx++] = (uint8_t)NRF_SPI0->RXD;

nrf_delay_us(3);
NRF_GPIO->OUTSET = 1 << SPIM_CS;

How can I get three bytes from SPI as fast as possible without using the interrupts?  (obviously(?) this will go into a loop to clear out the sensor FIFO)

  • Fingers crossed; a pint? - London Pride or Guinness, please :-)

  • Works great!  Getting around 6Mbps, which is impressive for 8MHz clock plus SS toggle.  On to the next problem!

    Glad to supply you with any kind of beer you like, in any quantity, any time!

  • 6Mbps? Pretty good .. how about adding the piece de resistance? 

       // Enable cache and hit/miss tracking
       NRF_NVMC->ICACHECNF = 0x101;

    This will remove 2 wait-states per instruction, assuming you don't have tons of interrupts thrashing away in the background.

  • No other interrupts should be firing, just dumping sensor buffer then transmitting to central.  I was unaware of this functionality, or maybe I should say I haven't gotten this far down the rabbit hole yet.  The speed I'm getting hits my requirement, but I can always use a current reduction.  I guess the idea is to monitor hits vs misses and multiply by the number of cycles then use that to determine power consumption, but what about hits?  I'm not seeing figures on the average current for the cache.  Or maybe it's just better to do a hard measurement over a full cycle both ways to determine which is optimal.  Do you happen to have a feel (since you appear to be some sort of wizard) for if the power consumption for cache is consistent across the product, or if there is a large variance between specimens?

  • You can ignore the non-resettable, saturating, hits and misses counters, I just use that to check the hit rate is high enough to be worth using in code which has lots of interrupts; there is a small power cost but a much bigger power saving for loop code like this which doesn't sleep. The cache means this code runs from RAM instead of Flash, so saving 2 wait states for each flash memory access is significant. In this code, dunno; maybe 6MHz bit rate goes up to 6.4 (guess). We'd have to count the flash accesses (look at assembler) then calculate ratio of clocks saved, then allow a bit for AHB bus issues .. nah, just run it and time it :-) Use 0x1 instead of 0x101 if you don't look at hits & misses. It's only turned on once; can always turn if off after the bulk transfer (set 0x0).

Related