I am using XIAO nRF52840 SENSE.
I want to get IMU data via DMA @ 104Hz, PDM data @16kHz/41.667kHz, and send the data via BLE @ 247,1M, gap = 7.5ms.
when enable IMU, disable PDM, the IMU data can be send via BLE correctly.
when enable both IMU and PDM, the BLE is disconnected, the IMU data are also correct.
when enable both IMU and PDM, and connected BLE and send realtime data. the IMU data will be about 0 in some frame. about 1 frame in 10 frames.
In the situation, the IMU data from DMA buffer are already 0, so I think it is none business of send data via BLE or parse data.
I try to change PDM from 41.667kHz to 16kHz, it appears no improvement.
Anyone know why and what happened. What can I do to solve this problem?
SO , it’s been a minute, always good stuff you bring and ask
Its a contention issue, the BLE (radio is the highest interrupt priority), the DMA is next, the PDM is LAST
the BLE interuppts causes a delay in returning he DMA start memory location basically, the short connection interval cuases that. The PDM has on ly a two sample buffer so it complicates the DMA and the data gets a ZERO…
Switch to DPPI /PPI
Do not rely on CPU interrupts to trigger the next IMU DMA transfer. Use hardware PPI/DPPI to connect the IMU data-ready GPIO pin directly to the SPI/I2C START task. This eliminates CPU interrupt latency from the transfer trigger path.
Also Increasing the interval to 15 ms–30 ms while transmitting multiple packets per connection event gives the CPU larger continuous time slices to handle peripheral ISRs and buffer swapping.
Check your dev tree and Kconfig for proper priority in Zephyr and with IMU instead of the PING-PONG double buffer , use a fifo 3 or 4 elements for the Queue so a brief delay in consumption does not result in reading an empty/unpopulated slot.
Another Question:
During the process of reading the IMU via DMA, at a sampling frequency of 104 Hz, over 60 seconds there will be multiple instances of IMU data being out of order. For example, in most of the data az=1.035, but in the out-of-order cases it may be ax=1.035, or it may be misplaced into gx. At this time, the Recursive_pattern read from FIFO_STATUS3 and FIFO_STATUS4 is still 0 or 6. Is this because the way Recursive_pattern is read is incorrect, or because the CPU is occupied during the IMU transfer process, or is there some other reason?
So, Glad to help… I see the FiFo sync problem before.
That axis-swapping behavior (az becoming ax or leaking into gx) indicates a FIFO byte-alignment offset shift rather than CPU ISR latency.
When parsing shifts by 2, 4, or 6 bytes, the DMA read pointer has fallen out of sync with the IMU’s 6-byte/12-byte FIFO word boundaries. Here is why it happens and how to address it:
Non-Integral DMA Read Lengths:
Each Accel + Gyro packet in the FIFO is 12 bytes (6 bytes for Gyro, 6 bytes for Accel). If a DMA transaction terminates or reads a byte count that is not an exact multiple of 12 bytes, the next DMA transfer begins reading from the middle of a sample frame instead of the start.
Status Register Race Conditions:
Reading FIFO_STATUS3/4 in a separate SPI/I2C transaction before or after the DMA payload read creates a race condition. If a sample is pushed to FIFO while the command sequence is in flight, the Recursive_pattern returned will not match the head of the DMA buffer.
Fixes to try:
Lock DMA Buffer Sizes: Ensure your SPI DMA read size is strictly an integer multiple of 12 bytes (or 6 bytes if using Accel only).
Trigger on FIFO Watermark (FTH), not DRDY: Configure INT1 to trigger on the FIFO Watermark (FIFO_CTRL1/2) set to a fixed number of complete frames (e.g., 2 frames = 24 bytes), rather than reading on simple data-ready interrupts.
Resync on Error: If an unexpected pattern or out-of-bounds delta is detected, toggle FIFO_CTRL5 to Bypass mode and back to Continuous mode to reset the internal FIFO pointers to index 0.
HTH
GL PJ
vLLM
Why this happens
Non-Multiple Word Reads via DMA:
In the LSM6DS3TR-C, each FIFO sample set consists of 6-byte frames per sensor (3 axes $\times$ 2 bytes). A combined Gyro + Accel entry is 12 bytes.
If a DMA transfer requests a byte count that is not an exact multiple of the dataset size (or stops midway due to a SPI/I2C transfer interrupt cutoff or bus timeout), the FIFO read pointer remains parked halfway through a sample.
On the very next DMA trigger, byte 0 read by the DMA is actually byte 2, 4, or 6 of the previous sample. This instantly shifts az into ax or gx.