BLE radio interrupts interfering with SPI

I make a BLE/USB MIDI controller that has an NRF52840 receiving sensor data by SPI from an Atmega 32u4 at 2Mhz. The NRF52840 is the SPI master (SPIM3). When I'm using BLE and sending a lot of MIDI messages, an SPI transfer occasionally gets corrupted. I'm using the Arduino environment so I'm not sure if this is the correct place to ask this, but I'm curious if this is more likely to be a hardware issue or some fragility with my SPI protocol. The two microcontrollers are within a few centimeters of each other. I don't have series resisters on MOSO or MISO, and I don't have an external pullup on SS.

If it's a software issue rather than hardware, what are possible reasons why a radio interrupt would affect SPI?

I have also tried switching to SPIM2, and the results are the same, so I don't think is related to anomaly 198.

Parents
  • If it's helpful, I'm using P0_15 for MOSI, P0_20 for MISO, and P0_13 for SCK, and P1_02 for SS. I believe that MOSI and SCK are set to high drive by the Adafruit NRF board package that I'm using.

  • You are likely seeing an AHB bus stall caused by the BLE code/peripherals tying up the AHB bus when the SPIM is looking to transfer data. This can be avoided by placing SPIM buffers in separate Slave AHB areas by reserving RAM segments for those buffers. I wrote some details on how to do this which are applicable on the nRF52840 stallstat-on-spim3

    The stall is detectable on SPIM3 only, not SPIM0/1/2, though I'm not sure how reliable the detection is; clearing might require writing a '1' to the register, I forget now. Worth incrementing a counter on each occurrence to verify stall detection. The stall mechanism on SPIM3 is supposed to hold the SPIM3 SCK until the bus is available, but I'm not sure if this actually works.

    "6.25.6.13 STALLSTAT Address offset: 0x400
    Stall status for EasyDMA RAM accesses. The fields in this register are set to STALL by hardware whenever a stall occurs and can be cleared (set to NOSTALL) by the CPU."

    Edit: Also note SPIM3 has the lowest bus priority of all, which is not helpful! See spim3-peripheral-not-reliable and maybe also look at adc-infuriating-behaviour and start-pwms-synchronous

  • Thanks for your help. Would the stall occur with SPIM2 as well or this issue only related to SPIM3? In my tests the SPIM2 behavior seems very similar.

  • Yes, quite so; this issue affects all nRF52840 peripherals, and when multiple peripheral's DMA bus Masters are actively competing for a particular AHB RAM bus the peripheral priority order dictates those least affected. SPIM3 happens to be the worst, but BLE Radio DMA and CPU memory access eclipse all the SPIMs. The true test to indicate if this is the problem at hand is to enforce SPIM DMA buffers in isolated RAM sections, easy to do but compiler-dependent syntax. Verify linker success in isolating the DMA buffer memory addresses by examining the linker map before testing.

    One method is to simply reserve an entire RAM block and align on the RAM boundary so nothing other than the CPU can access, preferably between DMA transfers which implies double-buffering if not; doesn't matter which RAM segment is used:

    uint8_t Spim3BufferTx[8192] __attribute__((section(".bss"), aligned(0x2000), used));
    uint8_t Spim3BufferRx[8192] __attribute__((section(".bss"), aligned(0x2000), used));
    struct spi_buf *pSpiBufferTx = Spim3BufferTx;
    

Reply Children
No Data
Related