2026-02-04 4:08 AM
Heyho,
I had some really strange error, which went away when turning optimization from "fast" to "off".
The function EthPhyInit() always returned 166 = 0xA6 - it should return "HAL_StatusTypeDef", something between 0 .. 3.
So I changed all the return values to some integer between 1..8 to find out where things go wrong, then added the last line:
uart_printf("EthPhyInit() good ->return 0\n\r");
before returning 0 when all went well.
Still, always got 166 back, even when I got "EthPhyInit() good ->return 0\n\r" on the terminal.
Until I turned optimization OFF, now all is good.
WTF is happening there? Can optimization be that bad?
/* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
/**
* @brief all PHY, ETH MAC & DMA reset and init:
* 1) EthBaseInit() GPIO, clocks, basic stuff
* 2) EthPhyInit() PHY
* 3) EthMacInit() MAC registers
* 4) EthDmaInit() DMA registers
* @PAram -
* @retval HAL status
*/
uint8_t EthAllInit(uint8_t u8SkipBase)
{
static uint32_t u32CallCount = 0;
uint8_t u8RetInit = 0xFF;
u32CallCount++;
/* ++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
/* base init */
if( 0 == u8SkipBase )
{
u8RetInit = EthBaseInit();
if( u8RetInit != HAL_OK )
{
#if( 1 ) // DEBUG_ETHNETIF
uart_printf(SZC_TEXT_ERR "EthBaseInit() = %u\n\r", u8RetInit);
#endif /* DEBUG_ETHNETIF */
return u8RetInit;
}
}
/* ++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
/* PHY initialization and configuration */
u8RetInit = EthPhyInit();
if( u8RetInit != HAL_OK )
{
#if( 1 ) // DEBUG_ETHNETIF
uart_printf(SZC_TEXT_ERR "EthPhyInit() = %u\n\r", u8RetInit); // ##### <- always 166 = 0xA6
uart_printf("u32CallCount = %lu\n\r", u32CallCount);
#endif /* DEBUG_ETHNETIF */
/* do NOT return error
* -> to NOT block other inits
*/
//return u8RetInit;
}
/* ++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
/* MACCR: more MAC registers */
u8RetInit = EthMacInit();
...
return u8RetInit;
}
/* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
/**
* @brief ETH PHY initialization and configuration
* @PAram none
* @retval HAL status
*/
uint8_t EthPhyInit(void)
{
/* KSZ8863RLL dual port PHY */
/* wait after reset */
HAL_Delay(50);
/* ++++++++++++++++++++++++++++++++++++++++++++++++ */
if( EthPhyKszAlive() != HAL_OK )
{
uart_printf(SZC_TEXT_ERR "EthPhyInit() 1\n\r");
return 1U; //HAL_ERROR;
}
/* ++++++++++++++++++++++++++++++++++++++++++++++++ */
#if DEBUG_ETHNETIF
uart_printf("PHY KSZ set RMII clock to internal...\n\r");
#endif /* DEBUG_ETHNETIF */
if( EthPhyKszClockSource(1) != HAL_OK )
{
uart_printf(SZC_TEXT_ERR "EthPhyInit() 2\n\r");
return 2U; //HAL_ERROR;
}
/* PHY needs a little time after clock change */
HAL_Delay(50);
/* ++++++++++++++++++++++++++++++++++++++++++++++++ */
/* check LINK status of BOTH PHY ports */
#if DEBUG_ETHNETIF
uart_printf("PHY link check...\n\r");
#endif /* DEBUG_ETHNETIF */
u8PhyPortActive = PHY_PORT_NONE;
/* ETH */
if( EthPhyLinkStatus((uint8_t)PHY_PORT_ETH, ETH_LINK_CHECK_LONG) == HAL_OK )
{
u8PhyPortActive = PHY_PORT_ETH;
}
/* USB if ETH not LINKed */
if( PHY_PORT_NONE == u8PhyPortActive )
{
if( EthPhyLinkStatus((uint8_t)PHY_PORT_USB, ETH_LINK_CHECK_LONG) == HAL_OK )
{
u8PhyPortActive = PHY_PORT_USB;
}
}
#if( 1 ) // DEBUG_ETHNETIF
uart_printf("u8PhyPortActive = %u\n\r", u8PhyPortActive);
#endif /* DEBUG_ETHNETIF */
/* ++++++++++++++++++++++++++++++++++++++++++++++++ */
/* power down unused port */
if( PHY_PORT_NONE != u8PhyPortActive )
{
uint32_t u32PhyRegVal = 0;
volatile uint8_t u8PhyPortUnused = PHY_PORT_NONE;
uint8_t u8RetVal = 0;
UNUSED(u8RetVal);
if( PHY_PORT_ETH == u8PhyPortActive ) u8PhyPortUnused = PHY_PORT_USB;
else u8PhyPortUnused = PHY_PORT_ETH;
u8RetVal = EthPhyPowerDown(u8PhyPortUnused);
#if DEBUG_ETHNETIF
if( u8RetVal != HAL_OK ) uart_printf(SZC_TEXT_ERR "EthPhyPowerDown()\n\r");
else uart_printf("PWRDWN unused port set\n\r");
#endif /* DEBUG_ETHNETIF */
/* check */
HAL_Delay(10);
u8RetVal = EthPhyReadReg(PHY_REG_PWR_DOWN, &u32PhyRegVal, u8PhyPortUnused);
#if DEBUG_ETHNETIF
if( u8RetVal != HAL_OK ) uart_printf(SZC_TEXT_ERR "EthPhyReadReg(PHY_REG_PWR_DOWN)\n\r");
else
{
uart_printf("PHY_REG_PWR_DOWN = %04lX of unused port\n\r", u32PhyRegVal);
if( (u32PhyRegVal & (uint32_t)PHY_REG_BIT_PWR_DOWN) == 0 ) uart_printf(SZC_TEXT_ERR "EthPhyPowerDown() failed\n\r");
}
#endif /* DEBUG_ETHNETIF */
}
/* ++++++++++++++++++++++++++++++++++++++++++++++++ */
/* wait for auto-negotiation complete */
if( PHY_PORT_NONE != u8PhyPortActive )
{
if( EthPhyAutoNegStatus(u8PhyPortActive) == HAL_OK )
{
#if DEBUG_ETHNETIF
uart_printf("AUTO-NEGOTIATION 0 complete\n\r");
#endif /* DEBUG_ETHNETIF */
}
else
{
/* re-start Auto-Negotiation */
if( EthPhyAutoNegRestart(u8PhyPortActive) != HAL_OK )
{
#if( 1 ) // DEBUG_ETHNETIF
uart_printf(SZC_TEXT_ERR "EthPhyAutoNegRestart()\n\r");
#endif /* DEBUG_ETHNETIF */
return 6U; //HAL_ERROR;
}
/* wait for auto-negotiation complete */
if( EthPhyAutoNegStatus(u8PhyPortActive) == HAL_OK )
{
#if DEBUG_ETHNETIF
uart_printf("AUTO-NEGOTIATION 1 complete\n\r");
#endif /* DEBUG_ETHNETIF */
}
else
{
#if( 1 ) // DEBUG_ETHNETIF
uart_printf(SZC_TEXT_ERR "EthPhyAutoNegStatus() TIMEOUT\n\r");
#endif /* DEBUG_ETHNETIF */
return 7U; //HAL_TIMEOUT;
}
}
}
else
{
#if( 1 ) // DEBUG_ETHNETIF
uart_printf(SZC_TEXT_ERR "u8PhyPortActive = PHY_PORT_NONE\n\r");
#endif /* DEBUG_ETHNETIF */
return 8U; //HAL_ERROR;
}
uart_printf("EthPhyInit() good ->return 0\n\r");
return 0U; //HAL_OK;
}
PS:
- STM32H733 on a custom board
- working with that for > 1 year now, with lots of printf for debugging (UART DMA), never had something like this
- same on other boards
- still using STM32CubeIDE 1.10.1
2026-02-04 5:08 AM
> Until I turned optimization OFF, now all is good.
> WTF is happening there? Can optimization be that bad?
Rarely.
But code can be that "bad".
Just drop e.g. a few "volatile" specifiers for peripheral registers or variables in interrupt code, and any optimisation level > 0 will "break" it.