Some bugs and caveats observed with STM32CubeMX V6.12.0 for an STM32H7S78-DK board, preparing a STM32CubeIDE project, using STM32Cube_FW_H7RS_V1.1.0 and with ‘Initialise all peripherals with the default Mode’ enabled...
RM0477 Rev 7 and DS14359 Rev 2 descriptions of XSPI; ‘JDES251C’ should be ‘JESD251C‘.
After generating, the STM32CubeIDE’s Project Explorer doesn’t show the include directories or header files of the enabled Middlewares. Without them, they’re not included in file-searches and they’re difficult to find and open in the IDE. The fix is to manually add suitable links in the linkedResources element in the .project.
Re adding source and include directories to a project...
- If directories are manually added to the .project’s linkedResources element, and for C source file directories, to the .cproject’s sourceEntries element:
- A subsequent STM32CubeMX generate will remove them.
- If they’re added via the Project Explorer’s context menu:
- The .project’s linkedResources element is amended, but not the .cproject’s sourceEntries elements, so C source files aren’t compiled.
- A subsequent STM32CubeMX generate will remove them.
- If they’re added via an .extSettings file:
- Only individual files can be added, not directories. An unfortunate oversite.
- A subsequent STM32CubeMX generate will still remove them.
- UM1718 Rev 45’s section describing it contains numerous syntax errors, e.g. lines including whitespace and lines without trailing semicolons.
- The HeaderPath section can only append directories to the tail of the compiler’s include search directories. An unfortunate oversite. Prepending is sometimes essential.
RCC
- Boot SystemCoreClock is 64MHz, whereas APPli SystemCoreClock is 600MHz.
TIMx
- TIM4’s trigger source can’t be assigned ITR3.
XSPI1/2
- NFC1 pin; in the ‘Connectivity’ side-bar, a warning says ‘Partly disabled conflict with: Pin [P00|PN1] is reserved.’ But these must be unlocked and manually configured.
GPDMA1
- Cannot be removed from the Boot context. If GPDMA1 is enabled, the Boot project executes __HAL_RCC_GPDMA1_CLK_ENABLE(). However, this operation should be able to be performed by the Appli context only. A complex application, deployed to the field with firmware upload capability, should be capable of undergoing significant changes, perhaps including enabling GPDMA1, during its lifecycle without modifying its boot code.
- With a timer channel configured as Output Compare to trigger a GPDMA channel, a call of HAL_DMA_Abort() to stop DMA after stopping the timer will time out waiting for SUSPF. This method works on the STM32H7. A workaround is to call HAL_DMA_PollForTransfer() instead, costing some execution cycles.
GPIO
- Adding a GPIO to Application’s context adds it to Boot’s and ExtMemLoader’s main.h too.
ETH
- Drivers/STM32H7RSxx_HAL_Driver/Inc/stm32h7rsxx_hal_eth.h is always generated with ETH_TX_DESC_CNT and ETH_RX_DESC_CNT as 4. The parameters are named ‘Tx/Rx Descriptor Length’, but they’re the number of DMA descriptors.
- LWIP\Target\ethernetif.c ETH_TX_BUFFER_MAX macro is obsolete.
- LWIP\Target\ethernetif.c and Drivers\STM32H7RSxx_HAL_Driver\Src\stm32h7rsxx_hal_eth.c, various errors: (1) high RBU rate, and (2) receive stops unrecoverably if buffers are ever unavailable. The STM32H7’s HAL is possibly affected the same.
- The RBU observations:
Code | Test case | Observation |
ST | ETH_RX_DESC_CNT = 4 ETH_RX_BUFFER_CNT = 41 ETH_RX_BUFFER_SIZE = 1536 | 44 RBU errors in 173 Rx interrupts. |
| ETH_RX_DESC_CNT = 20 ETH_RX_BUFFER_CNT = 41 ETH_RX_BUFFER_SIZE = 1536 | 8 RBU errors in 147 Rx interrupts. |
| ETH_RX_DESC_CNT = 20 ETH_RX_BUFFER_CNT = 41 ETH_RX_BUFFER_SIZE = 1000 | 9 RBU errors in 164 Rx interrupts. |
My fixes (listed below) | ETH_RX_DESC_CNT = 4 ETH_RX_BUFFER_CNT = 87 ETH_RX_BUFFER_SIZE = 1000 | 0 RBU errors in 205 Rx interrupts. |
| ETH_RX_DESC_CNT = 20 ETH_RX_BUFFER_CNT = 41 ETH_RX_BUFFER_SIZE = 1000 | 0 RBU errors in 210 Rx interrupts. |
| ETH_RX_DESC_CNT = 34 ETH_RX_BUFFER_CNT = 87 ETH_RX_BUFFER_SIZE = 1000 | 0 RBU errors in 202 Rx interrupts. |
- The RBU fixes:
- LWIP\Target\ethernetif.c
- In HAL_ETH_ErrorCallback(), remove releasing RxPktSemaphore. The interrupt’s only necessary for testing. With ETH_UpdateDescriptor() always writing ETH_DMACRXDTPR if it’s prepared any descriptor, if the silicon’s good, no RBU should ever be observed.
- In low_level_input(), call HAL_ETH_ReadData() unconditionally.
- RxAllocStatus’s type should be RxAllocStatusTypeDef.
- Drivers\STM32H7RSxx_HAL_Driver\Src\stm32h7rsxx_hal_eth.c
- In HAL_ETH_Start(), HAL_ETH_Start_IT() and HAL_ETH_ReadData()
- Replace ETH_RX_DESC_CNT with (ETH_RX_DESC_CNT – 1). Yes, we’re leaving an empty descriptor slot. Using all rx descriptors would require more execution cycles in ETH_UpdateDescriptor() and/or increased code-complexity and the descriptor memory’s cheap anyway. Perhaps the silicon could be improved by having the Receive Poll Demand command always start receiving even if the head equals the tail.
- In ETH_UpdateDescriptor()
- Remove the incorrectly evaluated tailidx and just write DMACRDTPR as dmarxdesc.
- Remove the apparently unnecessary __DMB() intrinsic and its unhelpful comment. Possibly it’s intended to support not configuring the descriptor memory as Device or Strongly-ordered with a suitable MPU region or for multi-cores. If it’s necessary, Cube should parameterise that and conditionally generate it only if required, and with a helpful comment.
- Remove the unnecessary allocStatus variable. It’s worth violating the ST coding standard prohibiting breaks from loops to simplifying the source code so bugs are more easily spotted during peer review.
- Reduce the execution cycles in the loop by removing checking whether the mode’s interrupt or not. Options include evaluating the necessary RDES3 value in HAL_ETH_Start() or HAL_ETH_Start_IT(), or easier, just always set the IOC bit; understanding it’s don’t care if the receive status interrupt’s disabled.
- LWIP\Target\ethernetif.c function low_level_init() initialises heth.Init.RxBuffLen as ETH_RX_BUFFER_SIZE’s value. For clarity, it should use ETH_RX_BUFFER_SIZE.
- LWIP\Target\ethernetif.c function HAL_ETH_MspInit() various errors:
- HAL_ETH_Init() always times out waiting for ETH_DMAMR_SWR to complete. The en.stm32cubeh7rs-v1-1-0’s ‘Projects\STM32H7S78-DK\Applications\LwIP\LwIP_TFTP_Server’ example doesn’t. Although it executes ok, it’s also incorrect.
It does this:
PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_ETH1REF|RCC_PERIPHCLK_ETH1PHY;
PeriphClkInit.Eth1RefClockSelection = RCC_ETH1REFCLKSOURCE_PHY;
PeriphClkInit.Eth1PhyClockSelection = RCC_ETH1PHYCLKSOURCE_PLL3S;
Cube’s default STM32H7S78-DK configuration incorrectly generates this:
PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_ETH1REF;
PeriphClkInit.Eth1RefClockSelection = RCC_ETH1REFCLKSOURCE_HSE;
They both SHOULD do this:
PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_ETH1REF;
PeriphClkInit.Eth1RefClockSelection = RCC_ETH1REFCLKSOURCE_PHY;
But if Cube’s ETH Clock Mux is corrected to receive 25MHz from ETH_RMII_REF_CLK, it still incorrectly generates this:
PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_ETH1REF;
PeriphClkInit.Eth1RefClockSelection = RCC_ETH1REFCLKSOURCE_ETH;
- There’s an unnecessary user-code block starting ‘/* USER CODE BEGIN MACADDRESS */’ that’s a copy of the MAC-initialisation source code from the low_level_init function.
- PB10’s configured as ETH_MII_RX_ER. But in Cube, it doesn’t appear in the Connectivity/ETH/GPIO list, and in System Core/GPIO, it appears in the ‘Single Mapped Signals’ list and its Pin Context is ‘Application’ and not ‘Appli’. Additionally, its ‘Signal on Pin’ is ‘ETH_MII_RX_ER’ but should be ‘ETH_RMII_RX_ER’.
- LWIP\Target\ethernetif.c function low_level_output() various errors:
- An intermediate ‘Txbuffer’ array used to pass the app’s pbuf-chain to HAL_ETH_Transmit_IT() is dimensioned ‘ETH_TX_DESC_CNT’. But ETH_TX_DESC_CNT may be large, wasting stack and cycles. Instead, it should be dimensioned some maximum less than or equal ETH_TX_DESC_CNT. Given Cube’s other bug about ETH_TX_DESC_CNT always being generated the value 4, that value’s probably a safe maximum dimension.
- The pbuf-chain’s payloads are assumed to be uncached. Cube should parameterise whether cache cleaning’s required and generate that as required.
- LWIP\Target\ethernetif.c function ethernet_link_thread() various errors:
- The linkchanged variable is never cleared.
- ethernet_link_thread’s calls of netif* and dhcp* functions aren’t thread safe and should use netifapi_netif* instead. This bug’s been reported in Community many times. Read the lwIP source code and observe, just one non-thread-safe case, how netif_set_link_up()/netif_set_link_down() call netif_set_flags() and how the flags variable change isn’t atomic.
- netif_is_link_up() should not need calling more than once per loop. NB netif_is_link_up() is thread safe.
- The interface is being incorrectly changed up/down with the link up/down. The fix is to move the netifapi_netif_set_up() call to low_level_init() and to never call netifapi_netif_set_down().
- The HAL_ETH_Stop_IT() and HAL_ETH_Start_IT() are being incorrectly called from a different thread to those calling HAL_ETH_ReadData() and HAL_ETH_Transmit_IT(). This may cause many errors and can't be completely avoided using heth->gState. Possible fixes include the easy option (1) move the HAL_ETH_Start_IT() call to low_level_init() and to never call HAL_ETH_Stop_IT(), or the difficult option (2) split starting/stopping the ETH driver into separate rx/tx functions, and signal the individual rx/tx threads to do their own ETH start/stop.
- Drivers\STM32H7RSxx_HAL_Driver\Src\stm32h7rsxx_hal_eth.c’s heth->RxDescList.RxDescCnt variable doesn't do anything and should be removed.
FreeRTOS
- The attributes of mutexes configured in Cube can’t be configured.
- configUSE_TIMERS is forced enabled.
lwIP
- The LWIP_ALTCP_TLS_MBEDTLS option can’t be configured. It’s mentioned in LWIP_ALTCP_TLS’s information.
- Cube requires enabling LWIP_MULTICAST_TX_OPTIONS before enabling LWIP_IGMP requires. Unnecessary clicks because LwIP’s opt.h already handles that.
- The unit of TCPIP_THREAD_STACKSIZE and any other lwIP tasks is 32-bit word. With FreeRTOS enabled, Cube forces the CMSIS version to v2, which per https://arm-software.github.io/CMSIS_5/RTOS2/html/group__CMSIS__RTOS__ThreadMgmt.html#structosThreadAttr__t, uses a stack size unit of byte. The fix is for sys_thread_new to scale the stack size to byte in the attribute structure it defines, which osThreadNew correctly scales back to 32-bit before calling the pertinent FreeRTOS xTaskCreateXXX function.
MbedTLS
- Can’t see it in the Middlewares list.
Project
- The USE_FULL_ASSERT option should be individually configurable for the Boot and Appli contexts.
Compile warnings:
- “../Core/Src/stm32h7rsxx_it.c:175:3: warning: implicit declaration of function 'xPortSysTickHandler'; did you mean 'SysTick_Handler'? [-Wimplicit-function-declaration]”.