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.