Skip to main content
Senior
October 4, 2019
Question

Receiving a burts of data from SPI using DMA

  • October 4, 2019
  • 12 replies
  • 1895 views

Hi,

I am using an STM32f407VGT MCU and I am trying to receive a burst of data of 112 bytes from SPI1 and storing it in an array buffer, initially set with all its elements to 0.

According to the RM0090 TRF this should be easily done with the DMA, but unfortunately I cannot see the data as correctly stored into the memory.

The code I am using to configure the DMA and the SPI is the following:

#include "stm32f4xx.h"
#include "stm32f4xx_ll_cortex.h"
#include "stm32f4xx_ll_bus.h"
#include "stm32f4xx_ll_dma.h"
#include "stm32f4xx_ll_rcc.h"
#include "stm32f4xx_ll_usart.h"
#include "stm32f4xx_ll_gpio.h"
#include "stm32f4xx_ll_system.h"
#include "stm32f4xx_ll_pwr.h"
#include "stm32f4xx_ll_spi.h"
#include "stm32f4xx_ll_tim.h"
#include "stm32f4xx_ll_utils.h"
 
 
#define SPI1_MOSI LL_GPIO_PIN_7
#define SPI1_MISO LL_GPIO_PIN_6
#define SPI1_SCLK LL_GPIO_PIN_5
#define SPI1_NSS LL_GPIO_PIN_4
 
uint8_t data_buffer[28][5] = {{0}};
 
void init_DMA(\
		DMA_TypeDef *DMAx, \
 
		uint32_t channel,
		uint32_t dma_stream,
		uint32_t src_address, \
 
		uint32_t dst_address, \
		uint32_t direction, \
		uint32_t mode, \
 
		uint32_t periph_inc_mode, \
		uint32_t mem_inc_mode, \
		uint32_t src_data_size, \
 
		uint32_t dst_data_size, \
		uint32_t nb_data, \
		uint32_t priority, \
 
		uint32_t fifo_mode, \
		uint32_t fifo_threshold, \
		uint32_t mem_burst, \
 
		uint32_t periph_burst)
{
	LL_DMA_InitTypeDef dma_init = {0};
 
	LL_DMA_StructInit(&dma_init);
	dma_init.Channel = channel;
	dma_init.PeriphOrM2MSrcAddress = src_address;
	dma_init.MemoryOrM2MDstAddress = dst_address;
	dma_init.Direction = direction;
	dma_init.Mode = mode;
	dma_init.PeriphOrM2MSrcIncMode = periph_inc_mode;
	dma_init.MemoryOrM2MDstIncMode = mem_inc_mode;
	dma_init.PeriphOrM2MSrcDataSize = src_data_size;
	dma_init.MemoryOrM2MDstDataSize = dst_data_size;
	dma_init.NbData = nb_data;
	dma_init.Priority = priority;
	dma_init.FIFOMode = fifo_mode;
	dma_init.FIFOThreshold = fifo_threshold;
	dma_init.MemBurst = mem_burst;
	dma_init.PeriphBurst = periph_burst;
 
	LL_DMA_EnableIT_TE(DMAx, dma_stream);
	LL_DMA_EnableIT_TC(DMAx, dma_stream);
	LL_DMA_Init(DMAx, dma_stream, &dma_init);
	LL_DMA_EnableStream(DMA2, dma_stream);
}
 
void DMA2_Stream0_IRQHandler(void)
{
	if(LL_DMA_IsActiveFlag_TC0(DMA2))
		LL_DMA_ClearFlag_TC0(DMA2);
}
 
void init_SPI(
		SPI_TypeDef *SPIx, \
		uint32_t transfer_dir, \
		uint32_t mode, \
		uint32_t data_width, \
		uint32_t clock_pol, \
		uint32_t clock_phase, \
		uint32_t nss, \
		uint32_t baudrate, \
		uint32_t bit_order, \
		uint32_t crc_calc, \
		uint32_t crc_poly)
{
	LL_SPI_InitTypeDef spi_init = {0};
 
	if(SPIx == SPI1)
	{
		init_GPIO(
				GPIOA, \
				SPI1_MOSI | SPI1_MISO | SPI1_SCLK | SPI1_NSS, \
				LL_GPIO_MODE_ALTERNATE, \
				LL_GPIO_SPEED_FREQ_VERY_HIGH, \
				LL_GPIO_OUTPUT_PUSHPULL, \
				LL_GPIO_PULL_UP, \
				LL_GPIO_AF_5);
	}
 
	LL_SPI_Disable(SPIx);
	LL_I2S_Disable(SPIx);
	spi_init.TransferDirection = transfer_dir;
	spi_init.Mode = mode;
	spi_init.DataWidth = data_width;
	spi_init.ClockPolarity = clock_pol;
	spi_init.ClockPhase = clock_phase;
	spi_init.NSS = nss;
	spi_init.BaudRate = baudrate;
	spi_init.BitOrder = bit_order;
	spi_init.CRCCalculation = crc_calc;
	spi_init.CRCPoly = crc_poly;
 
	if(SPIx == SPI1)
	{
 LL_SPI_EnableDMAReq_RX(SPI1);
	}
 
	LL_SPI_Init(SPIx, &spi_init);
	LL_SPI_Enable(SPIx);
}
 
int main(void)
{
	LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_GPIOA | LL_AHB1_GRP1_PERIPH_GPIOB | LL_AHB1_GRP1_PERIPH_GPIOC | LL_AHB1_GRP1_PERIPH_GPIOD | LL_AHB1_GRP1_PERIPH_DMA1 | LL_AHB1_GRP1_PERIPH_DMA2);
	LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_USART1 | LL_APB2_GRP1_PERIPH_SPI1);
 
	// DMA2 Channel 3 Stream 0 is attached to SPI1_RX
	init_DMA(DMA2, \
	 LL_DMA_CHANNEL_3, LL_DMA_STREAM_0, LL_SPI_DMA_GetRegAddr(SPI1), \
			(uint32_t) &data_buffer[0][0], LL_DMA_DIRECTION_PERIPH_TO_MEMORY, LL_DMA_MODE_CIRCULAR, \
			LL_DMA_PERIPH_NOINCREMENT, LL_DMA_MEMORY_NOINCREMENT, LL_DMA_PDATAALIGN_BYTE, \
			LL_DMA_MDATAALIGN_BYTE, 140, LL_DMA_PRIORITY_VERYHIGH, \
	 LL_DMA_FIFOMODE_ENABLE, LL_DMA_FIFOTHRESHOLD_1_4, LL_DMA_MBURST_SINGLE, \
	 LL_DMA_PBURST_SINGLE);
 
	init_SPI(SPI1, LL_SPI_SIMPLEX_RX, LL_SPI_MODE_SLAVE, LL_SPI_DATAWIDTH_8BIT, \
			LL_SPI_POLARITY_LOW, LL_SPI_PHASE_1EDGE, LL_SPI_NSS_HARD_INPUT, LL_SPI_BAUDRATEPRESCALER_DIV2, \
			LL_SPI_MSB_FIRST, LL_SPI_CRCCALCULATION_DISABLE, 10);
 
	NVIC_EnableIRQ(DMA2_Stream0_IRQn);
 
	while(1)
	{
 ;
	}
}

but every time I check the content of data_buffer it is always all to 0, like nothing has been stored into it.

So what am I doing wrong here ?

Any hint ?

Thanks in advance.

s.

This topic has been closed for replies.

12 replies

simo zzAuthor
Senior
October 7, 2019

Problem solved. It was due to the poor SPI cables quality and length in my prototype.

More precisely, the CS was randomly drop the logic level for a few ns.

I remounted a connector with a better cable and shorter length. Data is correctly received every time, without the need for EXTI interrupt.

Regards,

s.