cancel
Showing results for 
Search instead for 
Did you mean: 

Ethernet/LWIP Problems on the STM32H755ZIQ nucleo-board

kyleg4032
Associate II

Hello,

I am currently attempting to get the ethernet set up on my eval board. The project goal is to use a timer on the eval board to trigger the board to call out to a PLC on my network to receive 8 values every 1 second. Those values will then be stored in specific corresponding variables in the main.c file to be used in another function later on. I have attempted to follow several examples and use some AI to help me debug but I have hit a wall. I have zero errors when building out the project and running the debugger. It appears to flash onto the device but then nothing happens.

List of the places that I have tried to debug with a simple toggle GPIO command on one of the user LEDs

-user code section 2 : did toggle successfully on

-main while loop : does not work

-user code section 4 with in my modbus request : does not work

I have had several cases where it appears when the debugger asks me to resume the process it sends me to the hard fault handler in stm32H7xx_it.c, but this leaves me even more confused as to where to begin my debug process as I am so new to this. I at one point could ping the STM32 on my network but now I unfortunately get destination host unreachable. However, all of the hardware lights on the ethernet port do work!

 

The following are the components in the hardware config that I have activated and their settings:

System Core: GPIO / set USER LEDs to GPIO output on the M7 core only, no other changes

Timers: TIM2 activated on M7 / Counter period to 240000000 / TRGO set to Reset / NVIC TIM2 global interrupt checked

Connectivity: ETH activated on M7 only / NVIC global interrupt checked

Connectivity: USART3 Activated for Asynchronous mode

Middleware: FREERTOS_M7 on / API set to CMSIS v1 / USE_NEWLIB_REENTRANT Enabled / Default Task Enabled

Middleware: LWIP Enabled for M7 / DHCP disabled and static IP set / Platform settings to LAN8742

 

The following is the code I have implemented in my main.c ----------------------

 
#include "cmsis_os.h"

#include "lwip.h"

/* USER CODE BEGIN Includes */

#include "lwip/api.h"

#include "lwip/netbuf.h"

#include "lwip/ip_addr.h"

#include "lwip/tcp.h"

#include <string.h>

#include <stdio.h>



/* USER CODE END Includes */

/* USER CODE BEGIN PV */

/* Ethernet Packet Buffer */

uint8_t modbus_tx_buffer[12]; // Modbus Request Frame

uint8_t modbus_rx_buffer[1024];



/* Variables to store received Modbus values */

float phase_set_point, amplitude_set_point;

float phase_p, phase_i, phase_d;

float amp_p, amp_i, amp_d;



/* UART Debug Buffer */

uint8_t uart_msg[100];

extern UART_HandleTypeDef huart3;

/* USER CODE END PV */

/* USER CODE BEGIN 2 */

/* Initialize LWIP and Ethernet */

MX_LWIP_Init();



/* Start TIM2 for Modbus updates */

MX_TIM2_Init();

HAL_TIM_Base_Start_IT(&htim2);

/* USER CODE END 2 */

/* USER CODE BEGIN 4 */

void modbus_send_request(void)

{

struct netconn *conn;

struct netbuf *buf;

ip_addr_t server_ip;



IP4_ADDR(&server_ip, 000, 000, 000, 000);

conn = netconn_new(NETCONN_TCP);



if (conn != NULL)

{

if (netconn_connect(conn, &server_ip, 502) == ERR_OK)

{

modbus_tx_buffer[0] = 0x00;

modbus_tx_buffer[1] = 0x01;

modbus_tx_buffer[2] = 0x00;

modbus_tx_buffer[3] = 0x00;

modbus_tx_buffer[4] = 0x00;

modbus_tx_buffer[5] = 0x06;

modbus_tx_buffer[6] = 0x01;

modbus_tx_buffer[7] = 0x03;

modbus_tx_buffer[8] = 0xD4;

modbus_tx_buffer[9] = 0xDC;

modbus_tx_buffer[10] = 0x00;

modbus_tx_buffer[11] = 0x10;



netconn_write(conn, modbus_tx_buffer, 12, NETCONN_NOCOPY);



if (netconn_recv(conn, &buf) == ERR_OK && buf != NULL)

{

memcpy(modbus_rx_buffer, buf->p->payload, buf->p->len);

netbuf_delete(buf);



phase_set_point = (modbus_rx_buffer[9] << ‌‌ | modbus_rx_buffer[10];

amplitude_set_point = (modbus_rx_buffer[11] << ‌‌ | modbus_rx_buffer[12];

phase_p = (modbus_rx_buffer[13] << ‌‌ | modbus_rx_buffer[14];

phase_i = (modbus_rx_buffer[15] << ‌‌ | modbus_rx_buffer[16];

phase_d = (modbus_rx_buffer[17] << ‌‌ | modbus_rx_buffer[18];

amp_p = (modbus_rx_buffer[19] << ‌‌ | modbus_rx_buffer[20];

amp_i = (modbus_rx_buffer[21] << ‌‌ | modbus_rx_buffer[22];

amp_d = (modbus_rx_buffer[23] << ‌‌ | modbus_rx_buffer[24];



sprintf((char*)uart_msg, "Modbus Data: PSet=%.2f, ASet=%.2f\n", phase_set_point, amplitude_set_point);

HAL_UART_Transmit(&huart3, uart_msg, strlen((char*)uart_msg), HAL_MAX_DELAY);

}



netconn_close(conn);

netconn_delete(conn);

}

}

}



void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)

{

if (htim->Instance == TIM2)

{

modbus_send_request();

HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_14);

}

}

/* USER CODE END 4 */

I have left the IP address blank on purpose

I will also say that I have tried to click through every line and over things in the main.c file, it appeared that it was breaking after osKernelStart but I am unsure at this time.

/* Create the thread(s) */

/* definition and creation of defaultTask */

osThreadDef(defaultTask, StartDefaultTask, osPriorityNormal, 0, 128);

defaultTaskHandle = osThreadCreate(osThread(defaultTask), NULL);



/* USER CODE BEGIN RTOS_THREADS */

/* add threads, ... */

/* USER CODE END RTOS_THREADS */



/* Start scheduler */

osKernelStart();



/* We should never get here as control is now taken by the scheduler */

 

Any help or ideas of where to go from here would be greatly appreciated or tutorials that you might know of, thank you!

 

9 REPLIES 9
mƎALLEm
ST Employee

Hello,

Sorry, the code is not clear. Especially, nothing tells where main program starts!

"-main while loop : does not work" -> where that "main while loop" is located?

How to debug a HardFault on an Arm® Cortex®-M STM32

To give better visibility on the answered topics, please click on "Accept as Solution" on the reply which solved your issue or answered your question.

I apologize for the confusion! I will attach the main.c file in its entirety with this message.

Thank you!

1- "user code section 2 : did toggle successfully on"

-> what line are you referring to in the attached main.c?

2- "main while loop : does not work"

-> which line? 

3- Are you reaching HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_14) in HAL_TIM_PeriodElapsedCallback()?

 

To give better visibility on the answered topics, please click on "Accept as Solution" on the reply which solved your issue or answered your question.

Since I last replied, I have done some debugging with the toggle pins and breakpoints up to line 200 in the main.c file. I would specify the locations of those but I have been able to determine at what point the code is failing. I placed a GPIO toggle for PB14 at line 187, before the osKernalStart line at 193 and then placed a GPIO toggle for PB14 at line 199 to turn it off. It never reached the turn off point location at 199. I placed a breakpoint at osKernStart and then singled lined through until I reached the file ethernetif.c - the code stopped working at line 482. I have included the snippet of that section below, the line highlighted in blue is my error point.

kyleg4032_0-1749662079225.png

 

 

 

STackPointer64
ST Employee

Hello @kyleg4032

In addition to what @mƎALLEm suggested, and after reviewing the code you shared, I believe that LWIP and FreeRTOS might be misconfigured.

Firstly, the stack size you’re using (128 words) appears to be smaller than the recommended size mentioned in our knowledge base article and other similar projects. Additionally, it looks like LWIP is being initialized twice—once in main and again in a FreeRTOS task. Finally, in the default task, the initialization task hasn’t been deleted after completing the setup.

I suggest reviewing your project configuration and cross-checking it with this KB article:

Once you’ve made the necessary adjustments, we can return to debugging and work towards resolving your issue.

 

Best regards,

Hi @STackPointer64,

So after reading through that KB article you linked, I decided to start again from scratch. I saved my user code in visual studio for later once I can get the ethernet actually up and running. I therefore created a new CubeIDE project and followed along exactly with the article. I then added breakpoints and a GPIO toggle just before the osKernalStart and after. Unfortunately, my code still does not leave the osKernalStart. However, this time it is getting stuck in a different place, specifically memp.c. I will provide a screenshot of the location and code:

/* create a linked list of memp elements */

for (i = 0; i < desc->num; ++i) {

memp->next = *desc->tab;

*desc->tab = memp;

#if MEMP_OVERFLOW_CHECK

memp_overflow_init_element(memp, desc);

#endif /* MEMP_OVERFLOW_CHECK */

/* cast through void* to get rid of alignment warnings */

memp = (struct memp *)(void *)((u8_t *)memp + MEMP_SIZE + desc->size

#if MEMP_OVERFLOW_CHECK

+ MEM_SANITY_REGION_AFTER_ALIGNED

#endif

);

}

#if MEMP_STATS

desc->stats->avail = desc->num;

#endif /* MEMP_STATS */

#endif /* !MEMP_MEM_MALLOC */



#if MEMP_STATS && (defined(LWIP_DEBUG) || LWIP_STATS_DISPLAY)

desc->stats->name = desc->desc;

#endif /* MEMP_STATS && (defined(LWIP_DEBUG) || LWIP_STATS_DISPLAY) */

}



/**

* Initializes lwIP built-in pools.

* Related functions: memp_malloc, memp_free

*

* Carves out memp_memory into linked lists for each pool-type.

*/

void

memp_init(void)

{

u16_t i;



/* for every pool: */

for (i = 0; i < LWIP_ARRAYSIZE(memp_pools); i++) {

memp_init_pool(memp_pools[i]);



#if LWIP_STATS && MEMP_STATS

lwip_stats.memp[i] = memp_pools[i]->stats;

#endif

}

If you were to open memp.c, this would be lines 193-235. I am almost positive I followed the article to a T.

 

I appreciate the help!

I realize I should have specified, it creates an endless loop and never leaves!

I will also include this, so if I press F8 once the osKernalStart() breakpoint is reach, this is what comes up in the debug perspective/stack:

kyleg4032_0-1749751710116.png

 

STackPointer64
ST Employee

Hello @kyleg4032,

You are currently working in a Real-Time Operating System (RTOS) environment, which operates differently from a traditional bare-metal or non-RTOS environment. In an RTOS, tasks are managed and scheduled by the operating system, ensuring that each task gets the CPU time it needs based on priority and timing requirements. This means you cannot rely on traditional infinite while loops to handle your application's logic, as this would block the CPU and prevent other tasks from running.

Instead, you should create a thread (or task) in the RTOS in STM32CubeMX, to define your application's behavior. Each thread runs independently and cooperatively with other threads, allowing the RTOS to manage task scheduling efficiently. This approach ensures that your application remains responsive and adheres to real-time constraints.

Thread creation and configuration can be done in STM32CubeMX FreeRTOS settings under Tasks and Queues. Leave the default task as it is, and create a new task that will handle the execution of your Modbus program flow.

To better understand these concepts, I highly recommend exploring the following:

  1. FreeRTOS Documentation: Learn how to create and manage tasks, use synchronization primitives (e.g., semaphores, queues), and understand task priorities.

  2. RTOS Tutorials: Look for beginner-friendly guides or video tutorials on RTOS concepts to grasp task scheduling, preemption, and inter-task communication.

  3. LwIP Documentation: Familiarize yourself with how LwIP works in an RTOS environment. This will help you understand how to integrate networking into your application.

By studying these resources, you’ll gain a solid understanding of how to design and implement applications in an RTOS environment effectively.

Best regards,