2021-06-16 02:22 PM
Hello STM community,
I am currently trying to get my Nucleo STM32H743ZI2 to send data via SPI to a different chip.
Im using CubeMX to generate a lot of the setup code as I´m pretty new to this chip. For the same reason, I use the HAL.
The basic configuration is:
My main loop just tries to send out data repeatedly
status = HAL_SPI_Transmit(&hspi1, &buffer, 8, 1);
HAL_Delay(1);
If I set my prescaler to, lets say 8, I can see the data being transmitted with my logic analyzer without a problem. I can also see the EOT bit getting set in the SPI2S_SR register.
If I set my prescaler any higher though problems occur. I can still see the transmissions on my logic analyzer. The timing is much worse though.
After some investigating, I found the function
SPI_WaitOnFlagUntilTimeout(hspi, SPI_FLAG_EOT, RESET, tickstart, Timeout)
in stm32h7xx_hal_spi.c which is the culprit. The library tries to busy wait for the EOT flag to get set which does no longer happen when i choose any prescaler >=8.
If I use the Interrupt or DMA mode to get around the busy waiting, I can only transmit once. Afterwards the functions returns HAL_BUSY. I think this supports that the EOT bit is not getting set.
What I have done:
I also found the stm32h47s errata sheet where 2.14.2 sounded like it could be related, but the clocks are pretty much the other way around.
What my questions are:
For completeness sake, here are my init functions (CubeMx generated)
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
/** Supply configuration update enable
*/
HAL_PWREx_ConfigSupply(PWR_LDO_SUPPLY);
/** Configure the main internal regulator output voltage
*/
__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
while(!__HAL_PWR_GET_FLAG(PWR_FLAG_VOSRDY)) {}
/** Initializes the RCC Oscillators according to the specified parameters
* in the RCC_OscInitTypeDef structure.
*/
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_BYPASS;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.PLL.PLLM = 4;
RCC_OscInitStruct.PLL.PLLN = 400;
RCC_OscInitStruct.PLL.PLLP = 2;
RCC_OscInitStruct.PLL.PLLQ = 5;
RCC_OscInitStruct.PLL.PLLR = 2;
RCC_OscInitStruct.PLL.PLLRGE = RCC_PLL1VCIRANGE_1;
RCC_OscInitStruct.PLL.PLLVCOSEL = RCC_PLL1VCOWIDE;
RCC_OscInitStruct.PLL.PLLFRACN = 0;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
Error_Handler();
}
/** Initializes the CPU, AHB and APB buses clocks
*/
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2
|RCC_CLOCKTYPE_D3PCLK1|RCC_CLOCKTYPE_D1PCLK1;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.SYSCLKDivider = RCC_SYSCLK_DIV2;
RCC_ClkInitStruct.AHBCLKDivider = RCC_HCLK_DIV1;
RCC_ClkInitStruct.APB3CLKDivider = RCC_APB3_DIV2;
RCC_ClkInitStruct.APB1CLKDivider = RCC_APB1_DIV2;
RCC_ClkInitStruct.APB2CLKDivider = RCC_APB2_DIV2;
RCC_ClkInitStruct.APB4CLKDivider = RCC_APB4_DIV2;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
{
Error_Handler();
}
}
hspi1.Instance = SPI1;
hspi1.Init.Mode = SPI_MODE_MASTER;
hspi1.Init.Direction = SPI_DIRECTION_2LINES_TXONLY;
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_16;
hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB;
hspi1.Init.TIMode = SPI_TIMODE_DISABLE;
hspi1.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
hspi1.Init.CRCPolynomial = 0x0;
hspi1.Init.NSSPMode = SPI_NSS_PULSE_ENABLE;
hspi1.Init.NSSPolarity = SPI_NSS_POLARITY_LOW;
hspi1.Init.FifoThreshold = SPI_FIFO_THRESHOLD_01DATA;
hspi1.Init.TxCRCInitializationPattern = SPI_CRC_INITIALIZATION_ALL_ZERO_PATTERN;
hspi1.Init.RxCRCInitializationPattern = SPI_CRC_INITIALIZATION_ALL_ZERO_PATTERN;
hspi1.Init.MasterSSIdleness = SPI_MASTER_SS_IDLENESS_00CYCLE;
hspi1.Init.MasterInterDataIdleness = SPI_MASTER_INTERDATA_IDLENESS_00CYCLE;
hspi1.Init.MasterReceiverAutoSusp = SPI_MASTER_RX_AUTOSUSP_DISABLE;
hspi1.Init.MasterKeepIOState = SPI_MASTER_KEEP_IO_STATE_DISABLE;
hspi1.Init.IOSwap = SPI_IO_SWAP_DISABLE;
if (HAL_SPI_Init(&hspi1) != HAL_OK)
{
Error_Handler();
}
Thanks for your help
-Vincent
2021-06-16 02:35 PM
Try using a 1000ms timeout. The 1ms min timeout value could be messing with the logic.
Monitor the return value and do something useful about it when it's not HAL_OK to reduce debugging time.
2021-06-16 05:05 PM
There's some errata for the EOT behavior, maybe it applies to your case.
2021-06-17 02:27 AM
Thanks for the reply. I forgot to add that to the list of things i´ve tried.
Due to the EOT flag not being set, the SPI_WaitOnFlagUntilTimeout func actually blocks the CPU for the entire timeout length. If I set it to 1000ms, I am blocked for 1000ms.
The behavior does not change.
2021-06-17 02:29 AM
Hey, thanks.
Are you referring to the stm32h743´s "silicon" errata (especially the 2.14.2) or is there some other sheet I have missed?
2021-06-17 06:17 AM
I can't see anything else wrong with it. The errata is not applicable in this case as I interpret it.
2021-06-17 10:31 AM
Yes, this. I had to use workaround #3, could not get EOT reliably.
2024-07-28 10:30 PM
Came across this post while debugging something very similar today. In my case, I found out that the EOT bit wasn't getting flipped because SCK wasn't toggling, and SCK wasn't toggling because the GPIO "Maximum output speed" on the SPI pins was still set to "Low" and needed to be changed to "Very High".
It'd be a nice feature if STMCubeMX would cross-check the SPI clocks - it already has this in the Baud Rate field - and make sure the GPIO output speeds are configured to match.