cancel
Showing results for 
Search instead for 
Did you mean: 

SPI slave on STM32U535

lFurm.1
Associate II

Hi,

I'm trying to implement SPI slave on STM32U535 ( I have also NUCLEO-U575I). 

I need the SPI slave to have 4 bytes communication, 1st byte is a command byte, that has 2 options of command, the next 3 bytes the slave sends the content of one of 2 arrays (depends on the command byte). It uses hardware NSS.

No matter what I've tried, I have issues. Tried to implement it with inteupt, using LL libary for faster procceing the comand byte. I've set the FIFOThreshold to 1.

And still, at the output I recive the data delayed by 4 sends. I assume the TxFIFO is getting full first, and onlt then starting to send, with a delay, anyone can suggest how to overcome it and what am I missing. I'm attaching relevant code of the last configuration, but I've ttreied many others too.

Init:

static void MX_SPI2_Init(void)
{

  /* USER CODE BEGIN SPI2_Init 0 */

  /* USER CODE END SPI2_Init 0 */

  LL_SPI_InitTypeDef SPI_InitStruct = {0};

  LL_GPIO_InitTypeDef GPIO_InitStruct = {0};
  RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};

  /** Initializes the peripherals clock
  */
  PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_SPI2;
  PeriphClkInit.Spi2ClockSelection = RCC_SPI2CLKSOURCE_SYSCLK;
  if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)
  {
    Error_Handler();
  }

  /* Peripheral clock enable */
  LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_SPI2);

  LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOB);
  LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOA);
  /**SPI2 GPIO Configuration
  PB9   ------> SPI2_NSS
  PA9   ------> SPI2_SCK
  PB14   ------> SPI2_MISO
  PB15   ------> SPI2_MOSI
  */
  GPIO_InitStruct.Pin = LL_GPIO_PIN_9;
  GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE;
  GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_MEDIUM;
  GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
  GPIO_InitStruct.Pull = LL_GPIO_PULL_NO;
  GPIO_InitStruct.Alternate = LL_GPIO_AF_5;
  LL_GPIO_Init(GPIOB, &GPIO_InitStruct);

  GPIO_InitStruct.Pin = LL_GPIO_PIN_9;
  GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE;
  GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_HIGH;
  GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
  GPIO_InitStruct.Pull = LL_GPIO_PULL_NO;
  GPIO_InitStruct.Alternate = LL_GPIO_AF_3;
  LL_GPIO_Init(GPIOA, &GPIO_InitStruct);

  GPIO_InitStruct.Pin = LL_GPIO_PIN_14|LL_GPIO_PIN_15;
  GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE;
  GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_HIGH;
  GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
  GPIO_InitStruct.Pull = LL_GPIO_PULL_NO;
  GPIO_InitStruct.Alternate = LL_GPIO_AF_5;
  LL_GPIO_Init(GPIOB, &GPIO_InitStruct);

  /* SPI2 interrupt Init */
  NVIC_SetPriority(SPI2_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(),0, 0));
  NVIC_EnableIRQ(SPI2_IRQn);

  /* USER CODE BEGIN SPI2_Init 1 */

  /* USER CODE END SPI2_Init 1 */
  /* SPI2 parameter configuration*/
  SPI_InitStruct.TransferDirection = LL_SPI_FULL_DUPLEX;
  SPI_InitStruct.Mode = LL_SPI_MODE_SLAVE;
  SPI_InitStruct.DataWidth = LL_SPI_DATAWIDTH_8BIT;
  SPI_InitStruct.ClockPolarity = LL_SPI_POLARITY_LOW;
  SPI_InitStruct.ClockPhase = LL_SPI_PHASE_2EDGE;
  SPI_InitStruct.NSS = LL_SPI_NSS_HARD_INPUT;
  SPI_InitStruct.BitOrder = LL_SPI_MSB_FIRST;
  SPI_InitStruct.CRCCalculation = LL_SPI_CRCCALCULATION_DISABLE;
  SPI_InitStruct.CRCPoly = 0x7;
  LL_SPI_Init(SPI2, &SPI_InitStruct);
  LL_SPI_SetStandard(SPI2, LL_SPI_PROTOCOL_MOTOROLA);
  LL_SPI_DisableNSSPulseMgt(SPI2);
  /* USER CODE BEGIN SPI2_Init 2 */

  /* USER CODE END SPI2_Init 2 */

}

in main:

 

	LL_SPI_EnableIT_RXP(SPI2);
	LL_SPI_EnableIT_TXP(SPI2);
	LL_SPI_EnableIT_OVR(SPI2);
	LL_SPI_SetTransferSize(SPI2, 0);
	LL_SPI_SetFIFOThreshold(SPI2, LL_SPI_FIFO_TH_01DATA);
	LL_SPI_TransmitData8(SPI2,0x00);
	LL_SPI_Enable(SPI2);

 

Interupt:

  */
void SPI2_IRQHandler(void)
{
  /* USER CODE BEGIN SPI2_IRQn 0 */
	
	if (LL_SPI_IsActiveFlag_RXP(SPI2)) 
	{
		received_byte = LL_SPI_ReceiveData8(SPI2);
		rxind++;
		if (rxind==4){
		rxind=0;}
		if (rxind == 1){
		coman=(received_byte & 0xC0) >>6;
			
					}
	}
	if (LL_SPI_IsActiveFlag_OVR(SPI2)) 
	{
		SPI_FlushRxFifo_Fast(SPI2);  
		LL_SPI_ClearFlag_OVR(SPI2);
	}
	if (LL_SPI_IsActiveFlag_TXP(SPI2)) 
  {
		if (coman==2){
	//		print_hex(spi_tx_data[txind]);
			LL_SPI_TransmitData8(SPI2, spi_tx_data[txind++]); }
		else if (coman==3){
		
	
			
			LL_SPI_TransmitData8(SPI2, spi_tx_temp[txind++]); 
		}
		else
			LL_SPI_TransmitData8(SPI2,0x00);
		
		if (txind==3) {txind=0; coman=8;}
	}
  if (LL_SPI_IsActiveFlag_UDR(SPI2)) 
  {
		LL_SPI_TransmitData8(SPI2, 0x00);   
		LL_SPI_ClearFlag_UDR(SPI2);
	}

  /* USER CODE END SPI2_IRQn 0 */
  /* USER CODE BEGIN SPI2_IRQn 1 */

  /* USER CODE END SPI2_IRQn 1 */
}

 

Thanks if anyone can help, or suggest how to implement what I need.

 

2 REPLIES 2
Saket_Om
ST Employee

@lFurm.1 wrote:

Hi,

And still, at the output I recive the data delayed by 4 sends.:

 


What does it mean delayed by 4 sends? 

Did you try with HAL first and check the behavior before handling the case with LL? 

To give better visibility on the answered topics, please click on "Accept as Solution" on the reply which solved your issue or answered your question.
Saket_Om
bmckenney
Associate II

SPI has no flow control mechanism. The slave must have its response data prepared before the master requests it ("prescience"), and if the master sends (in this case) (1+3) bytes in a burst there's no time. [This is an SPI, not an STM32 thing.] Introducing slave-side processing time probably requires a higher-level protocol.

Possible schemes:

1) Have the master introduce a deliberate delay between the first (command) Tx byte and the dummy bytes for the Rx. This will require some tuning, but at least then the slave has a known deadline for supplying its data.

2) A sort of ping-pong protocol: Each transaction sends a command and receives the result from the Previous command. The slave uses the time between transactions to prepare the FIFO/DMA for the command just received, in time for the next transaction.