cancel
Showing results for 
Search instead for 
Did you mean: 

SPI to DMA continuous data stream from peripheral questions & advice

NicRoberts
Senior II

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;
	}
}

 

 

 

 

 

 

0 REPLIES 0