cancel
Showing results for 
Search instead for 
Did you mean: 

Problem with SPI Slave DMA Circular and CS Synchronization

bmsape
Associate

 

 

Hi all,

I am trying to implement the SPI Slave Mode using a circular DMA. I am using the STM32U5A5 as my slave device. The SPI master is sending packets of unknown length at 2 MBit/s over SPI which I want to receive and process. Additionally, I want the packets to be synchronized to the Chip Select. Basically, I want each CS phase to be one packet.

My concept is to have my CS signal on an external interrupt, which triggers both on the falling and rising edge. This way I can store the start index and the end index of the DMA buffer to my chips select packet. When chip select is de-asserted (i.e. chip select goes high) I then raise a flag that my data is ready. In my Process task loop I then process only this chunk of data from the start index to the end index of the DMA.

This is my EXTI function:

 

void EXTI8_IRQHandler(void)
{
  /* USER CODE BEGIN EXTI8_IRQn 0 */
  HAL_GPIO_WritePin(DEBUG_1_GPIO_Port, DEBUG_1_Pin, 1);
  if(HAL_GPIO_ReadPin(CS_EXTI8_GPIO_Port, CS_EXTI8_Pin) == 0){ //falling edge
	  __HAL_RCC_GPDMA1_CLK_ENABLE();
	  packet_start_index = BUFFER_SIZE - __HAL_DMA_GET_COUNTER(hspi1.hdmarx);
  }
  else{ //rising edge
	  packet_end_index = BUFFER_SIZE - __HAL_DMA_GET_COUNTER(hspi1.hdmarx);
	  __HAL_RCC_GPDMA1_CLK_DISABLE();
	  memcpy(process_buffer_spi1, rx_buffer_spi1, BUFFER_SIZE);
	  data_ready = true;
  }
  HAL_GPIO_WritePin(DEBUG_1_GPIO_Port, DEBUG_1_Pin, 0);

  /* USER CODE END EXTI8_IRQn 0 */
  HAL_GPIO_EXTI_IRQHandler(CS_EXTI8_Pin);
  /* USER CODE BEGIN EXTI8_IRQn 1 */

  /* USER CODE END EXTI8_IRQn 1 */
}

 

And this my process task. Here I just print the first two words of the packet to UART.

 

void process_func(void *argument)
{
  /* USER CODE BEGIN task1 */
  /* Infinite loop */
  for(;;)
  {
	  if(data_ready){
		  HAL_GPIO_TogglePin(DEBUG_2_GPIO_Port, DEBUG_2_Pin);
		  uint16_t packet_start_index_local = packet_start_index;
		  uint16_t packet_end_index_local = packet_end_index;

		  if(packet_end_index_local < packet_start_index_local){ //buffer overflow

		  }
		  else{
			  for(int i = packet_start_index_local; i < packet_start_index_local + 8 && i < BUFFER_SIZE; i++){
				  uint8_t processing_byte = process_buffer_spi1[i];
				  if(processing_byte == 0x80 && i == packet_start_index_local){
					  HAL_GPIO_WritePin(DEBUG_3_GPIO_Port, DEBUG_3_Pin, 1);
				  }

				  printf("%02X", processing_byte);
				  if((i-packet_start_index_local)%4 == 3){
					  printf(" ");
				  }
			  }
			  printf("; %d, %d\n", packet_start_index_local, packet_end_index_local);
		  }


//		  printf("%d, %d, %d \n", packet_start_ptr, packet_end_ptr, rx_buffer_spi1[packet_start_ptr]);


		  data_ready = false;
		  HAL_GPIO_TogglePin(DEBUG_2_GPIO_Port, DEBUG_2_Pin);
	  }
  }
  /* USER CODE END task1 */
}

 

However, this only works for the first two packets. After those the DMA seems to get corrupted and is filled with random data. This doesn't seem to have anything to with the buffer overflow as the second packet only fills up the DMA up to the index 120. The DMA is 256 bytes long.

This is my DMA Setup:

bmsape_0-1709054632551.png

And this my SPI setup:

bmsape_1-1709054658255.png

 

First of all, can you guys tell me whether my concept is valid? And if yes, do you guys have any idea why it doesn't work after two packets? I also attached the project files reduced to the bare minimum. The EXTI can be found in the _it.c file and the processing function in app_freertos.c.

Thanks alot!

1 REPLY 1
Christian N
ST Employee
Hello bmsape, Thank you for contacting STMicroelectronics. Your post was escalated to ST Online Support Team for additional assistance. Kind Regards, Christian ST Support