cancel
Showing results for 
Search instead for 
Did you mean: 

Get corrupted Data from SPI when using DMA on STM32G071 Controller

Moritz1
Associate III

I want to receive SPI Data from an external Chip (which is running my software too).

So I configured my SPI2 into Slave Mode, Receive only

The first thing what I did (to check if everything is working fine): I used the RXNE Interrupt and copied the received Data from DR to my Array in memory and incremented my Pointer, so that all data is written into the array.

For first test I have sent from the other chip the Data 0, 1, 2, 3, 4, 5, ... , 239

Thereafter, I looked into my Array and everything is fine: 0, 1, 2, 3, 4, 5, .... , 239 ist received into the Array.

So everything is fine. Now I changed my Programm:

  • disabling RXNIE of the SPI
  • configuring DMA1, Channel 2 to transfer 240 Bytes from SPI_DR (no increment, 8 Bit) to memory (increment, 8 Bit)

Than I let run my program again. The Transfre complete Interrupt is generated after receiving the 240 Bytes. But if I look into my array, the content is always:

0,0,0,2,4,2,4,6,8,6,8,10,12,10,12,14,16,14,16,18,20,18,20,22,........

I can try multiple times, it is always the same. I also tryed to reduce bitrate of the SPI, set a delay between eacht Byte on transmitter side. But this changes nothing. Data in the Array is always the same.... So I'm 100% sure that this is no timing problem or something else.

The Array is initialized with other data, so I'm also 100% sure that this data was written by the DMA.

If you look carefully in the Array, each 4th Byte is correct (Byte 0, Byte 4, Byte 8, ....), the other data is wrong. All odd values are missing...

I have absolutly no idea how this can happen :(

Here is my configuration of SPI2:

static void MX_SPI2_Init(void)
{
 
  /* USER CODE BEGIN SPI2_Init 0 */
 
  /* USER CODE END SPI2_Init 0 */
 
  /* USER CODE BEGIN SPI2_Init 1 */
 
  /* USER CODE END SPI2_Init 1 */
  /* SPI2 parameter configuration*/
  hspi2.Instance = SPI2;
  hspi2.Init.Mode = SPI_MODE_SLAVE;
  hspi2.Init.Direction = SPI_DIRECTION_2LINES_RXONLY;
  hspi2.Init.DataSize = SPI_DATASIZE_8BIT;
  hspi2.Init.CLKPolarity = SPI_POLARITY_LOW;
  hspi2.Init.CLKPhase = SPI_PHASE_1EDGE;
  hspi2.Init.NSS = SPI_NSS_SOFT;
  hspi2.Init.FirstBit = SPI_FIRSTBIT_MSB;
  hspi2.Init.TIMode = SPI_TIMODE_DISABLE;
  hspi2.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
  hspi2.Init.CRCPolynomial = 7;
  hspi2.Init.CRCLength = SPI_CRC_LENGTH_DATASIZE;
  hspi2.Init.NSSPMode = SPI_NSS_PULSE_DISABLE;
  if (HAL_SPI_Init(&hspi2) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN SPI2_Init 2 */
 
  /* USER CODE END SPI2_Init 2 */
 
}

and the DMA (Channel 1 is normally used to send data via SPI1, but I have disabled it due to the problem described above):

static void MX_DMA_Init(void) 
{
 
  /* DMA controller clock enable */
  __HAL_RCC_DMA1_CLK_ENABLE();
 
  /* DMA interrupt init */
  /* DMA1_Channel1_IRQn interrupt configuration */
  //HAL_NVIC_SetPriority(DMA1_Channel1_IRQn, 0, 0);
  //HAL_NVIC_EnableIRQ(DMA1_Channel1_IRQn);
  /* DMA1_Channel2_3_IRQn interrupt configuration */
  HAL_NVIC_SetPriority(DMA1_Channel2_3_IRQn, 1, 0);
  HAL_NVIC_EnableIRQ(DMA1_Channel2_3_IRQn);
 
}

To start the DMA I use this code:

void spi2DmaStart(uint8_t *pData, uint16_t size)
{
	SPI2->CR2 |= SPI_CR2_RXDMAEN;			//SPI Receive to DMA enable
 
	DMA1_Channel2->CCR &= ~DMA_CCR_EN;
 
	DMA1_Channel2->CNDTR = size;
	DMA1_Channel2->CPAR = &SPI2->DR;		//peripheral address
	DMA1_Channel2->CMAR = pData;		//memory Address
	DMA1_Channel2->CCR |= DMA_CCR_TCIE;		//Transfer complete interrupt enable
 
	DMA1_Channel2->CCR |= (DMA_MINC_ENABLE | DMA_CCR_EN);	//memory increment enable
 
	SPI2->CR1 |= SPI_CR1_SPE;		//enable SPI
 
}

Hopefully someone has an idea what I do wrong.

2 REPLIES 2

I don't use the 'G0, but this sounds like data packing + FIFO problem in SPI.

Read out and check content of SPI (mainly the Rx FIFO setting), DMAMUX and DMA registers.

JW

rromano001
Senior

Hello, some new about this?

I incurred in similar issue so I started searching for a solution.

Some hint:

https://vivonomicon.com/2019/07/05/bare-metal-stm32-programming-part-9-dma-megamix/

Here I learnt G0 has a new DMA peripheral scheme, DMA type 3 with DMA multiplexer.

Original poster has no DMAMux selection so stream can exercise some form of dangling reference on source/destination channel.

Code has no data sizing on DMA, default is 32bit so it can produce that strange behavior.