2025-10-10 4:16 AM
NUCLEO F411RE, MPU 9250
I'm reading acceleration data via SPI from an MPU 9250 directly to memory. This part is working for one off reads in a loop I can see my x, y, z values change in the debugger
I would like to do FFT on the acceleration data but at the same time not interrupt the flow of data so I can know for sure the sampling frequency. I'm thinking having a constant stream via DMA into a circular buffer or possibly a dual buffer set up, read one buffer whilst the other is processed?
About the frequency - I'm unclear about how calculate this accurately. SPI1 is on the APB2 bus which has a default frequency of 16MHz. I have a function that requests the acceleration data (sends register address & a read flag) & waits for the data to be received which is 6 bytes, then does it all over again.
So is my thinking right here, there's some over head for the actual request but the data is arriving in 3us (48/1600000) ~333KHz? Also, this is blocking isn't it (see mpu9250_accel_update() below), so its negating the concurrency advantage I thought I was getting by using the DMA?
Is there a method for having the DMA stream active & the CPU just dealing with the memory buffers or am I always going to have to deal with directing the traffic at some level with the CPU? I have the DMAStream IRQs set up (see below), I feel I'm missing a trick here.
I should mention that this is a learning exercise for me. As much as I appreciate that these things can be set up using Cube/HAL/LL etc. I'm trying to understand the bare metal implementation with as little abstraction as possible.
void mpu9250_accel_update(void)
{
dummy_buff[0] = MPU9250_ACCEL_XOUT_H | READ_FLAG;
dma2_stream3_spi_transfer((uint32_t)dummy_buff, (uint32_t)(MAX_TRANSFER_LEN + 1));
dma2_stream2_spi_receive((uint32_t)accel_buff, ((uint32_t)MAX_TRANSFER_LEN + 1));
/* wait for rx complete */
while(!g_rx_cmplt){}
}
void DMA2_Stream2_IRQHandler(void)
{
if(DMA2->LISR & LISR_TCIF2)
{
g_rx_cmplt = 1;
DMA2_Stream2->CR &=~ DMA_SxCR_EN;
/* Clear flag */
DMA2->LIFCR |= LIFCR_CTCIF2;
}
else if((DMA2->LISR) & LISR_TEIF2)
{
/* Clear flag */
DMA2->LIFCR |= LIFCR_CTEIF2;
}
}
void DMA2_Stream3_IRQHandler(void)
{
if(DMA2->LISR & LISR_TCIF3)
{
g_tx_cmplt = 1;
DMA2_Stream3->CR &=~ DMA_SxCR_EN;
/* Clear flag */
DMA2->LIFCR |= LIFCR_CTCIF3;
}
else if((DMA2->LISR) & LISR_TEIF3)
{
/* Clear flag */
DMA2->LIFCR |= LIFCR_CTEIF3;
}
}