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

SPI high-speed reading

Hello,

We use NRF52 and the SPI protocol to read the ADS7866. But we are facing a problem when reading at high speed, we want to make one read transaction of 2 Bytes every 5µs ( to achieve a 200KHz ADC )

Before explaining which method was used, there is the SPI configuration that we use:

#define NRF_DRV_SPI_CUSTOM_CONFIG                            \
{                                                            \
    .sck_pin      = SPI_SCK_PIN,                             \
    .mosi_pin     = SPI_MOSI_PIN,                            \
    .miso_pin     = SPI_MISO_PIN,                            \
    .ss_pin       = SPI_ADC7866_PIN,                         \
    .irq_priority = SPI_DEFAULT_CONFIG_IRQ_PRIORITY,         \
    .orc          = 0xFF,                                    \
    .frequency    = NRF_DRV_SPI_FREQ_4M,                     \
    .mode         = NRF_DRV_SPI_MODE_0,                      \
    .bit_order    = NRF_DRV_SPI_BIT_ORDER_MSB_FIRST,         \
}

We have tried 3 different ways:

1: Make on bulk read of 100 Bytes using the SPI driver  (`nrf_drv_spi_transfer()`). But it's does not work because, as you can see on the ADS7866 documentation, the CS signal should have a falling edge every 5µs to trigger the ADC acquisition.

2: Try to read 2 bytes per 2 bytes using the same driver  but the best performance we can get is 7.3µs between each transaction ; this is too slow as we need 5µs.

3: Try to use an external clock as a CS to force the CS to fall edge every 5µs. But we failed to synchronize the SPI driver and this external clock.

What do you think about our problem ?  In your opinion, what is the best way to do the job ?

  • You might try a creative solution by spoofing the /CS signal instead of using the real CS which is (usually) provided by the .ss_pin. I'd be inclined to keep the .ss_pin as you have it, but don't actually connect it to anything, just use it as a 'scope trigger while you tune the spoofed /CS. So where does the /CS connection to the ADS7866 come from? The answer is to use the .mosi_pin. The shape of this waveform is now controlled by using (say) a 3-byte Tx buffer which could have the values {0x00, 0x00, 0xFF} for the 16-bit active-low /CS. Use a 2-byte buffer {0x00, 0x0F} for the 12-bit version (assuming MSB first) which only requires 2 bytes. Set .orc to 0xFF. This may work as the .sck_pin can run indefinitely provided /CS remains high (the .mosi pin in your case) and only on the next falling edge will the new conversion start.

    I haven't tried this, so it may require a little experimentation, let us know if it works :-)

  • Hi

    An alternative approach is to use the TIMER, PPI and GPIOTE modules to automate the CS signal and the SPI transactions. 

    Essentially you set up individual CC (compare capture) registers in the timer to trigger events at different points in time. At the most you have 6 CC registers per timer, meaning you can repeatedly generate up to 6 different events at different points in time. 

    Two events can be used to clear and set the CS signal (by connecting the TIMER to the GPIOTE module through PPI), and the SPI module can also be triggered in this fashion to allow you to start the SPI transactions at the right points in the sequence. 

    The SPI buffers will have to be configured in advance so that the data will automatically be read from the RAM when the event from the timer occurs. 

    Best regards
    Torbjørn

Related