cancel
Showing results for 
Search instead for 
Did you mean: 

Correct way to deactivate SPI in half-duplex/simplex mode

FDomi.1
Associate

I am trying to change a STM32F4 from slave to master after certain amount of time, send a message as master, and go back to slave. I found out that configuring the SPI as slave_rxonly and enabling the SPI will cause the clock to unexpectedly sent a clock as soon as I configure the device back to master. Without me sending any data.

This is my main loop.

while (1)
  {
    /* USER CODE END WHILE */
 
    /* USER CODE BEGIN 3 */
	  MX_SPI1_Init(); /* This configures master */
	  HAL_Delay(10);
 
	  sendHelloWorld();
	  configSlave(); /* Configures slave mode */
	  __HAL_SPI_ENABLE(&hspi1); /* Enabling the device in this mode generates a continous clock during master init */
 
	  HAL_Delay(100);
 
	  HAL_SPI_DeInit(&hspi1);	/* Disables SPI and de-initializes the peripheral */
  }

My master config:

hspi1.Instance = SPI1;
  hspi1.Init.Mode = SPI_MODE_MASTER;
  hspi1.Init.Direction = SPI_DIRECTION_2LINES;
  hspi1.Init.DataSize = SPI_DATASIZE_8BIT;
  hspi1.Init.CLKPolarity = SPI_POLARITY_LOW;
  hspi1.Init.CLKPhase = SPI_PHASE_1EDGE;
  hspi1.Init.NSS = SPI_NSS_SOFT;
  hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_256;
  hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB;
  hspi1.Init.TIMode = SPI_TIMODE_DISABLE;
  hspi1.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
  hspi1.Init.CRCPolynomial = 10;
  if (HAL_SPI_Init(&hspi1) != HAL_OK)
  {
    Error_Handler();
  }

My slave config:

if(HAL_SPI_DeInit(&hspi1) != HAL_ERROR)
{
       /* SPI1 parameter configuration*/
	hspi1.Instance = SPI1;
	hspi1.Init.Mode = SPI_MODE_SLAVE;
	hspi1.Init.Direction = SPI_DIRECTION_2LINES_RXONLY;
	hspi1.Init.DataSize = SPI_DATASIZE_8BIT;
	hspi1.Init.CLKPolarity = SPI_POLARITY_LOW;
	hspi1.Init.CLKPhase = SPI_PHASE_1EDGE;
	hspi1.Init.NSS = SPI_NSS_SOFT;
	hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB;
	hspi1.Init.TIMode = SPI_TIMODE_DISABLE;
	hspi1.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
	hspi1.Init.CRCPolynomial = 10;
 
	if (HAL_SPI_Init(&hspi1) != HAL_OK)
	{
		Error_Handler();
	}
 
}

and this is the waveform from my logic analyzer. As soon as I run the function MX_SPI1_Init() after enabling the SPI as a Slave the clock is generated. Orange is the clock and as you can see - from the 10ms delay -it gets enabled right after the initialization as master.

 0693W00000AMIV1QAP.pngAny thoughts? I've been fighting with this issue for over a week, and tried many things

5 REPLIES 5

Hello

>> HAL_SPI_DeInit(&hspi1); /* Disables SPI and de-initializes the peripheral *

but in function definition, HAL_SPI_DeInit put device to slave mode and never deactivate it.

if sendHelloWorld is not a blocking function , such behavior may expected.

That solved it! The clock issue is solved, but I am getting inconsistent data at a slave node I have. My analyzer detects the data correctly but my slave node does not. I'll have to check that more.

Right now my sendHelloWorld() is a blocking function, however, the goal is to make it Interrupt based. Would this cause any issue?

Thank yo very much for the help

Petr Sladecek
ST Employee

Let me to comment with some delay the problem with target just to bring some notes for other readers here.

Above all, when perform whatever significant change of the SPI configuration, be sure the previous SPI mode is well terminated and SPI is disabled in according the RM prior any new configuration starts. This is even strongly required when change the data direction exclusively at half duplex mode!

As SPI slave can never produce any SCK signal, the observed long SCK pulse session confirms, that the configuration change was not successful evidently because such a permanent SCK clock flow is typical just for master Rx-only mode configuration (not for any slave one) .

Anyway, to better understand the SPI problematic, I suggest to read AN5543 focusing typical problems frequently reported by our customers.

Best regards,

Petr, the IP owner, STMicroelectronics

Hi @Petr Sladecek​ 

Great that you've chimed in.

So, in context of Cube/HAL, what's the proper way to disable SPI? Shouldn't HAL_SPI_DeInit() - as used above - accomplish exactly this? And what exactly is the root cause of problem there?

I've also read the Disabling the SPI subchapter of SPI chapter in RM0090 rev.19 as you've suggested. However, I fail to understand the procedures described - they all end with "enter the Halt mode"; however, there's no explanation, what is "Halt mode" and how to enter it.

So, can you please give an unambiguous and universally good method how to disable SPI before enabling any other transaction? Ideally, in terms of RM, i.e. no "library" such as Cube/HAL. The "libraries" then ought to follow that method.

Thanks,

JW

Petr Sladecek
ST Employee

Hi Jan,

I believe the HAL_***_DeInit function is useful rather at case when application has no plan to use the peripheral any more or maybe after recovery from a fatal HAL error. The reason is that besides the IP disable this procedure calls HAL_***_MspDeInit, too, which remove all the associated GPIOs, CLOCKs and NVIC setting. This is not required at all when just making the peripheral itself ready for any next transaction session.

To assure each next communication session passes well from whatever previous state on the bus (e.g. typically problematic is re-start after interrupted and so not fully completed data frame process), it is always better to reset internal state machine (like internal counters, crc calculation, ss detection unit, pointers to FIFOs at some later SPI design etc.) to re-initialize the IP properly prior a new session starts. This initialization process is raised automatically when SPE bit becomes set and the process depends and follows configuration currently applied at the IP registers. That is why it is suggested not to touch crucial HW configuration at least when SPE=1 and perform SPE setting as a last configuration step.

At this specific case, I see no attempt to separate master session and following significant HW configuration change into slave mode at main loop demonstrated at firstly posted input there.

Note any initialization of the IP together with DMA is even a bit more tricky as there are two internal initialization processes ongoing in parallel and it depends on many next factors of both the SPI and DMA designs and its interface at concrete product system level (e.g. if FIFOs are accessible or if SPI propagates its data handling requests to DMA at time the SPE=0) which can be different at different products what makes a bit different requirements for handling.

Concerning SPI disable process the critical point is to prevent any action into the peripheral HW at time the transaction is still ongoing on the bus else it could be corrupted and so not fully completed (e.g. if clock are removed prematurely from the IP kernel due to fast entry of the system into a power down mode).

I believe the document describing the SPI specific handling techniques I've mentioned (AN5543) gives answer to many questions.

Best regards,

Petr