cancel
Showing results for 
Search instead for 
Did you mean: 

Bug with code generation when using HAL and Ethernet (+ workaround)

wmmcmj
Associate II

I've created a new project using HAL for the NUCLEO-F207ZG with CubeMX that ships within CubeIDE (1.5.0). After implementing a minimal network stack from scratch that supported the bare minimum of ARP, IP and ICMP to ping my board, I was wondering why I was only ever receiving broadcast Ethernet frames, but never frames designated at my board.

Turns out the generated code in eth.c by CubeMX has an obvious bug when it comes to initializing pointers with array values:

  heth.Init.MACAddr[0] =   0x00;
  heth.Init.MACAddr[1] =   0x80;
  heth.Init.MACAddr[2] =   0xE1;
  heth.Init.MACAddr[3] =   0x00;
  heth.Init.MACAddr[4] =   0x00;
  heth.Init.MACAddr[5] =   0x00;

MACAddr of ETH_InitTypeDef is not defined as uint8_t[6] but simply as a pointer to uint8_t.

typedef struct
{
  // ...
  uint8_t             *MACAddr;                   /*!< MAC Address of used Hardware: must be pointer on an array of 6 bytes */
  // ...
} ETH_InitTypeDef;

Nowhere in the code this pointer gets allocated, so the values end up pretty much nowhere.

My quick workaround now is to just set an allocated array to MACAddr in eth.c:

// ...
 
/* USER CODE BEGIN 0 */
uint8_t mac_addr[6] = { 0x00, 0x80, 0xE1, 0x00, 0x00, 0x00 };
/* USER CODE END 0 */
 
ETH_HandleTypeDef heth;
 
/* ETH init function */
void MX_ETH_Init(void)
{
  // ...
  heth.Init.MACAddr = mac_addr;
  // ...
}
 
// ...

This works but is annoying as it gets overwritten with every code generation. Weirdly enough, sample code that comes for LwIP and the like do not suffer this problem and pretty much do what I have done as a workaround. So I suppose this is something that came along with a new release or something.

6 REPLIES 6
Houssem CHAABANI
Senior II

Hi @wmmcmj​ ,

Thank you for your feedback,

Could you please share your .ioc file ?

Many thanks !

wmmcmj
Associate II

Sure. It happens with any newly created project that utilizes Ethernet anyway.

Also note that there were no compile errors given. The problem really is just wrong initialization of the init-struct (assign values to non-allocated array fields) or its definition (uint8_t* instead of uint8_t[6]) depending from which way you look at it.

Houssem CHAABANI
Senior II

Hi @wmmcmj​ ,

Thank you for your feedback.

@Imen DAHMEN​ could you please check this Ethernet MACAddr initialization issue .

Thanks!

Houssem

Hello,

Thanks @wmmcmj​  for your contribution and reported this issue.

I tracked this internally for review and treat accordingly to the priority. I will keep you informed about the taken actions/explanation if needed.

Thanks @Houssem CHAABANI​  for bringing this to my attention.

Imen

When your question is answered, please close this topic by clicking "Accept as Solution".
Thanks
Imen
Imen.D
ST Employee

Hi @wmmcmj​ ,

Sorry for the delayed reply on this.

It seems the issue is with your code generation.

The generated code should allocate the array beforehand, and make sure that it is always available (global variable, static variable or a variable declared in main()).

Imen

When your question is answered, please close this topic by clicking "Accept as Solution".
Thanks
Imen

Hi @Imen DAHMEN​ ,

I tested again with the latest CubeIDE 1.6.1 and STM32Cube FW_F2 1.9.2. Same board, all default presets, peripherals initialized in their default mode as offered by Cube. I only changed the MAC address in Cube's "Parameter Settings" for Ethernet to check if changes are actually visible in the generated code. (They were not when I last tested this.) Code generation is apparently still not working correctly:

static void MX_ETH_Init(void)
{
 
  /* USER CODE BEGIN ETH_Init 0 */
 
  /* USER CODE END ETH_Init 0 */
 
  /* USER CODE BEGIN ETH_Init 1 */
 
  /* USER CODE END ETH_Init 1 */
  heth.Instance = ETH;
  heth.Init.AutoNegotiation = ETH_AUTONEGOTIATION_ENABLE;
  heth.Init.Speed = ETH_SPEED_100M;
  heth.Init.DuplexMode = ETH_MODE_FULLDUPLEX;
  heth.Init.PhyAddress = LAN8742A_PHY_ADDRESS;
  heth.Init.MACAddr[0] =   0x00;
  heth.Init.MACAddr[1] =   0x15;
  heth.Init.MACAddr[2] =   0x7E;
  heth.Init.MACAddr[3] =   0x00;
  heth.Init.MACAddr[4] =   0x00;
  heth.Init.MACAddr[5] =   0x00;
  heth.Init.RxMode = ETH_RXPOLLING_MODE;
  heth.Init.ChecksumMode = ETH_CHECKSUM_BY_HARDWARE;
  heth.Init.MediaInterface = ETH_MEDIA_INTERFACE_RMII;
 
  /* USER CODE BEGIN MACADDRESS */
 
  /* USER CODE END MACADDRESS */
 
  if (HAL_ETH_Init(&heth) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN ETH_Init 2 */
 
  /* USER CODE END ETH_Init 2 */
 
}

MACAddr in ETH_InitTypeDef still is only a pointer to uint8_t and not an array nor does it get allocated anywhere, so the values from the generated code still end up nowhere:

typedef struct
{
  uint32_t             AutoNegotiation;           /*!< Selects or not the AutoNegotiation mode for the external PHY
                                                           The AutoNegotiation allows an automatic setting of the Speed (10/100Mbps)
                                                           and the mode (half/full-duplex).
                                                           This parameter can be a value of @ref ETH_AutoNegotiation */
 
  uint32_t             Speed;                     /*!< Sets the Ethernet speed: 10/100 Mbps.
                                                           This parameter can be a value of @ref ETH_Speed */
 
  uint32_t             DuplexMode;                /*!< Selects the MAC duplex mode: Half-Duplex or Full-Duplex mode
                                                           This parameter can be a value of @ref ETH_Duplex_Mode */
 
  uint16_t             PhyAddress;                /*!< Ethernet PHY address.
                                                           This parameter must be a number between Min_Data = 0 and Max_Data = 32 */
 
  uint8_t             *MACAddr;                   /*!< MAC Address of used Hardware: must be pointer on an array of 6 bytes */
 
  uint32_t             RxMode;                    /*!< Selects the Ethernet Rx mode: Polling mode, Interrupt mode.
                                                           This parameter can be a value of @ref ETH_Rx_Mode */
 
  uint32_t             ChecksumMode;              /*!< Selects if the checksum is check by hardware or by software.
                                                         This parameter can be a value of @ref ETH_Checksum_Mode */
 
  uint32_t             MediaInterface    ;               /*!< Selects the media-independent interface or the reduced media-independent interface.
                                                         This parameter can be a value of @ref ETH_Media_Interface */
 
} ETH_InitTypeDef;

The array does not get allocated anywhere in the generated code. I've attached my new .ioc-file again.