2024-04-18 05:46 AM - edited 2024-04-18 05:49 AM
Hi 🙂
I have a custom board where I need to use the ethernet interface. Starting with a NUCLEO-H563ZI I ported the NetXDuo TCP Server Echo example to my board.
When I'm using the example as expected with a DHCP server connected (e.g. ethernet connection to a router or switch) then everything works. I can use the board in debug mode or in release mode.
My goal is to connect the board directly to my Mac (or any other laptop) and assign a fixed IP address to the MCU. This works fine when I'm in a debugging session. In release mode I cannot establish a connection as a TCP client.
Does anybody has an idea how to find the problem?
As you can see in the following code of app_netxduo.c I just removed the DHCP things in the CubeMX configuration and added the IP address and net mask.
"app_netxduo.h"
/* USER CODE BEGIN Header */
/**
******************************************************************************
* @file app_netxduo.h
* @author MCD Application Team
* @brief NetXDuo applicative header file
******************************************************************************
* @attention
*
* Copyright (c) 2024 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* USER CODE END Header */
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __APP_NETXDUO_H__
#define __APP_NETXDUO_H__
#ifdef __cplusplus
extern "C" {
#endif
/* Includes ------------------------------------------------------------------*/
#include "nx_api.h"
/* Private includes ----------------------------------------------------------*/
#include "nx_stm32_eth_driver.h"
/* USER CODE BEGIN Includes */
#include "main.h"
/* USER CODE END Includes */
/* Exported types ------------------------------------------------------------*/
/* USER CODE BEGIN ET */
/* USER CODE END ET */
/* Exported constants --------------------------------------------------------*/
/* USER CODE BEGIN EC */
/* USER CODE END EC */
/* The DEFAULT_PAYLOAD_SIZE should match with RxBuffLen configured via MX_ETH_Init */
#ifndef DEFAULT_PAYLOAD_SIZE
#define DEFAULT_PAYLOAD_SIZE 1536
#endif
#ifndef DEFAULT_ARP_CACHE_SIZE
#define DEFAULT_ARP_CACHE_SIZE 1024
#endif
/* Exported macro ------------------------------------------------------------*/
/* USER CODE BEGIN EM */
#define PRINT_IP_ADDRESS(addr) do { \
printf("STM32 %s: %lu.%lu.%lu.%lu \n", #addr, \
(addr >> 24) & 0xff, \
(addr >> 16) & 0xff, \
(addr >> 😎 & 0xff, \
addr& 0xff);\
}while(0)
#define PRINT_DATA(addr, port, data) do { \
printf("[%lu.%lu.%lu.%lu:%u] -> '%s' \n", \
(addr >> 24) & 0xff, \
(addr >> 16) & 0xff, \
(addr >> 😎 & 0xff, \
(addr & 0xff), port, data); \
} while(0)
/* USER CODE END EM */
/* Exported functions prototypes ---------------------------------------------*/
UINT MX_NetXDuo_Init(VOID *memory_ptr);
/* USER CODE BEGIN EFP */
/* USER CODE END EFP */
/* Private defines -----------------------------------------------------------*/
/* USER CODE BEGIN PD */
#define DEFAULT_MEMORY_SIZE 1024
#define DEFAULT_PRIORITY 10
#define WINDOW_SIZE 512
#define LINK_PRIORITY 11
#define NULL_ADDRESS 0
#define DEFAULT_PORT 6000
#define MAX_TCP_CLIENTS 1
/* USER CODE END PD */
#define NX_APP_DEFAULT_TIMEOUT (10 * NX_IP_PERIODIC_RATE)
#define NX_APP_PACKET_POOL_SIZE ((DEFAULT_PAYLOAD_SIZE + sizeof(NX_PACKET)) * 10)
#define NX_APP_THREAD_STACK_SIZE 2*1024
#define Nx_IP_INSTANCE_THREAD_SIZE 2*1024
#define NX_APP_THREAD_PRIORITY 10
#ifndef NX_APP_INSTANCE_PRIORITY
#define NX_APP_INSTANCE_PRIORITY NX_APP_THREAD_PRIORITY
#endif
#define NX_APP_DEFAULT_IP_ADDRESS IP_ADDRESS(192, 168, 1, 32)
#define NX_APP_DEFAULT_NET_MASK IP_ADDRESS(255, 255, 255, 0)
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
#ifdef __cplusplus
}
#endif
#endif /* __APP_NETXDUO_H__ */
"app_netxduo.c"
/* USER CODE BEGIN Header */
/**
******************************************************************************
* @file app_netxduo.c
* @author MCD Application Team
* @brief NetXDuo applicative file
******************************************************************************
* @attention
*
* Copyright (c) 2024 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "app_netxduo.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "nx_stm32_eth_config.h"
/* USER CODE END Includes */
/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
/* Define Threadx global data structures. */
TX_THREAD AppTCPThread;
TX_THREAD AppLinkThread;
/* Define NetX global data structures. */
ULONG IpAddress;
ULONG NetMask;
NX_TCP_SOCKET TCPSocket;
/* App memory pointer. */
CHAR *pointer;
/* USER CODE END PTD */
/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
/* USER CODE END PD */
/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */
/* USER CODE END PM */
/* Private variables ---------------------------------------------------------*/
TX_THREAD NxAppThread;
NX_PACKET_POOL NxAppPool;
NX_IP NetXDuoEthIpInstance;
/* USER CODE BEGIN PV */
/* USER CODE END PV */
/* Private function prototypes -----------------------------------------------*/
static VOID nx_app_thread_entry (ULONG thread_input);
/* USER CODE BEGIN PFP */
/* TCP thread entry */
static VOID App_TCP_Thread_Entry(ULONG thread_input);
/* Link thread entry */
static VOID App_Link_Thread_Entry(ULONG thread_input);
static VOID tcp_listen_callback(NX_TCP_SOCKET *socket_ptr, UINT port);
static void tcp_disconnect_callback(NX_TCP_SOCKET *socket_ptr);
/* USER CODE END PFP */
/**
* @brief Application NetXDuo Initialization.
* memory_ptr: memory pointer
* @retval int
*/
UINT MX_NetXDuo_Init(VOID *memory_ptr)
{
UINT ret = NX_SUCCESS;
TX_BYTE_POOL *byte_pool = (TX_BYTE_POOL*)memory_ptr;
/* USER CODE BEGIN App_NetXDuo_MEM_POOL */
(void)byte_pool;
/* USER CODE END App_NetXDuo_MEM_POOL */
/* USER CODE BEGIN 0 */
/* USER CODE END 0 */
/* Initialize the NetXDuo system. */
CHAR *pointer;
nx_system_initialize();
/* Allocate the memory for packet_pool. */
if (tx_byte_allocate(byte_pool, (VOID **) &pointer, NX_APP_PACKET_POOL_SIZE, TX_NO_WAIT) != TX_SUCCESS)
{
return TX_POOL_ERROR;
}
/* Create the Packet pool to be used for packet allocation,
* If extra NX_PACKET are to be used the NX_APP_PACKET_POOL_SIZE should be increased
*/
ret = nx_packet_pool_create(&NxAppPool, "NetXDuo App Pool", DEFAULT_PAYLOAD_SIZE, pointer, NX_APP_PACKET_POOL_SIZE);
if (ret != NX_SUCCESS)
{
return NX_POOL_ERROR;
}
/* Allocate the memory for Ip_Instance */
if (tx_byte_allocate(byte_pool, (VOID **) &pointer, Nx_IP_INSTANCE_THREAD_SIZE, TX_NO_WAIT) != TX_SUCCESS)
{
return TX_POOL_ERROR;
}
/* Create the main NX_IP instance */
ret = nx_ip_create(&NetXDuoEthIpInstance, "NetX Ip instance", NX_APP_DEFAULT_IP_ADDRESS, NX_APP_DEFAULT_NET_MASK, &NxAppPool, nx_stm32_eth_driver,
pointer, Nx_IP_INSTANCE_THREAD_SIZE, NX_APP_INSTANCE_PRIORITY);
if (ret != NX_SUCCESS)
{
return NX_NOT_SUCCESSFUL;
}
/* Allocate the memory for ARP */
if (tx_byte_allocate(byte_pool, (VOID **) &pointer, DEFAULT_ARP_CACHE_SIZE, TX_NO_WAIT) != TX_SUCCESS)
{
return TX_POOL_ERROR;
}
/* Enable the ARP protocol and provide the ARP cache size for the IP instance */
/* USER CODE BEGIN ARP_Protocol_Initialization */
/* USER CODE END ARP_Protocol_Initialization */
ret = nx_arp_enable(&NetXDuoEthIpInstance, (VOID *)pointer, DEFAULT_ARP_CACHE_SIZE);
if (ret != NX_SUCCESS)
{
return NX_NOT_SUCCESSFUL;
}
/* Enable the ICMP */
/* USER CODE BEGIN ICMP_Protocol_Initialization */
/* USER CODE END ICMP_Protocol_Initialization */
ret = nx_icmp_enable(&NetXDuoEthIpInstance);
if (ret != NX_SUCCESS)
{
return NX_NOT_SUCCESSFUL;
}
/* Enable TCP Protocol */
/* USER CODE BEGIN TCP_Protocol_Initialization */
/* USER CODE END TCP_Protocol_Initialization */
ret = nx_tcp_enable(&NetXDuoEthIpInstance);
if (ret != NX_SUCCESS)
{
return NX_NOT_SUCCESSFUL;
}
/* Allocate the memory for main thread */
if (tx_byte_allocate(byte_pool, (VOID **) &pointer, NX_APP_THREAD_STACK_SIZE, TX_NO_WAIT) != TX_SUCCESS)
{
return TX_POOL_ERROR;
}
/* Create the main thread */
ret = tx_thread_create(&NxAppThread, "NetXDuo App thread", nx_app_thread_entry , 0, pointer, NX_APP_THREAD_STACK_SIZE,
NX_APP_THREAD_PRIORITY, NX_APP_THREAD_PRIORITY, TX_NO_TIME_SLICE, TX_AUTO_START);
if (ret != TX_SUCCESS)
{
return TX_THREAD_ERROR;
}
/* USER CODE BEGIN MX_NetXDuo_Init */
/* Allocate the memory for TCP server thread */
if (tx_byte_allocate(byte_pool, (VOID **) &pointer,2 * DEFAULT_MEMORY_SIZE, TX_NO_WAIT) != TX_SUCCESS)
{
return TX_POOL_ERROR;
}
/* create the TCP server thread */
ret = tx_thread_create(&AppTCPThread, "App TCP Thread", App_TCP_Thread_Entry, 0, pointer, 2 * DEFAULT_MEMORY_SIZE,
DEFAULT_PRIORITY, DEFAULT_PRIORITY, TX_NO_TIME_SLICE, TX_DONT_START);
if (ret != TX_SUCCESS)
{
return TX_THREAD_ERROR;
}
/* Allocate the memory for Link thread */
if (tx_byte_allocate(byte_pool, (VOID **) &pointer,2 * DEFAULT_MEMORY_SIZE, TX_NO_WAIT) != TX_SUCCESS)
{
return TX_POOL_ERROR;
}
/* create the Link thread */
ret = tx_thread_create(&AppLinkThread, "App Link Thread", App_Link_Thread_Entry, 0, pointer, 2 * DEFAULT_MEMORY_SIZE,
LINK_PRIORITY, LINK_PRIORITY, TX_NO_TIME_SLICE, TX_AUTO_START);
if (ret != TX_SUCCESS)
{
return TX_THREAD_ERROR;
}
/* USER CODE END MX_NetXDuo_Init */
return ret;
}
/**
* @brief Main thread entry.
* thread_input: ULONG user argument used by the thread entry
* @retval none
*/
static VOID nx_app_thread_entry (ULONG thread_input)
{
/* USER CODE BEGIN Nx_App_Thread_Entry 0 */
UINT ret = NX_SUCCESS;
ret = nx_ip_address_get(&NetXDuoEthIpInstance, &IpAddress, &NetMask);
/* print the IP address and the net mask */
PRINT_IP_ADDRESS(IpAddress);
if (ret != TX_SUCCESS)
{
Error_Handler();
}
/* the network is correctly initialized, start the TCP server thread */
tx_thread_resume(&AppTCPThread);
/* this thread is not needed any more, we relinquish it */
tx_thread_relinquish();
/* USER CODE END Nx_App_Thread_Entry 0 */
}
/* USER CODE BEGIN 1 */
/**
* @brief TCP listen call back
* socket_ptr: NX_TCP_SOCKET socket registered for the callback
* port: UINT the port on which the socket is listening
* @retval none
*/
static VOID tcp_listen_callback(NX_TCP_SOCKET *socket_ptr, UINT port)
{
/* as soon as the IP address is ready, the semaphore is released */
// tx_semaphore_put(&DHCPSemaphore);
HAL_GPIO_WritePin(LED_USER2_GPIO_Port, LED_USER2_Pin, GPIO_PIN_SET);
printf("--- TCP_LISTEN_CALLBACK ---\n");
}
static void tcp_disconnect_callback(NX_TCP_SOCKET *socket_ptr)
{
HAL_GPIO_WritePin(LED_USER2_GPIO_Port, LED_USER2_Pin, GPIO_PIN_RESET);
printf("--- TCP_DISCONNECT_CALLBACK ---\n");
}
/**
* @brief TCP server thread entry
* thread_input: ULONG thread parameter
* @retval none
*/
static VOID App_TCP_Thread_Entry(ULONG thread_input)
{
UINT ret;
UCHAR data_buffer[512];
ULONG source_ip_address;
NX_PACKET *data_packet;
UINT source_port;
ULONG bytes_read;
/* create the TCP socket */
ret = nx_tcp_socket_create(&NetXDuoEthIpInstance, &TCPSocket, "TCP Server Socket", NX_IP_NORMAL, NX_FRAGMENT_OKAY,
NX_IP_TIME_TO_LIVE, WINDOW_SIZE, tcp_disconnect_callback, NX_NULL);
if (ret)
{
Error_Handler();
}
/*
* listen to new client connections.
* the TCP_listen_callback will release the 'Semaphore' when a new connection is available
*/
ret = nx_tcp_server_socket_listen(&NetXDuoEthIpInstance, DEFAULT_PORT, &TCPSocket, MAX_TCP_CLIENTS, tcp_listen_callback);
if (ret)
{
Error_Handler();
}
else
{
printf("TCP Server listening on PORT %d ..\n", DEFAULT_PORT);
}
/* accept the new client connection before starting data exchange */
ret = nx_tcp_server_socket_accept(&TCPSocket, TX_WAIT_FOREVER);
if (ret)
{
Error_Handler();
}
while(1)
{
ULONG socket_state;
TX_MEMSET(data_buffer, '\0', sizeof(data_buffer));
/* get the socket state */
nx_tcp_socket_info_get(&TCPSocket, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &socket_state, NULL, NULL, NULL);
/* if the connections is not established then accept new ones, otherwise start receiving data */
if(socket_state != NX_TCP_ESTABLISHED)
{
printf("Waiting for TCP client\n");
ret = nx_tcp_server_socket_accept(&TCPSocket, NX_IP_PERIODIC_RATE);
}
if(ret == NX_SUCCESS)
{
printf("Connection established\n");
/* receive the TCP packet send by the client */
ret = nx_tcp_socket_receive(&TCPSocket, &data_packet, NX_WAIT_FOREVER);
if (ret == NX_SUCCESS)
{
HAL_GPIO_TogglePin(LED_USER2_GPIO_Port, LED_USER2_Pin);
/* get the client IP address and port */
nx_udp_source_extract(data_packet, &source_ip_address, &source_port);
/* retrieve the data sent by the client */
nx_packet_data_retrieve(data_packet, data_buffer, &bytes_read);
/* print the received data */
PRINT_DATA(source_ip_address, source_port, data_buffer);
/* immediately resend the same packet */
ret = nx_tcp_socket_send(&TCPSocket, data_packet, NX_IP_PERIODIC_RATE);
if (ret == NX_SUCCESS)
{
HAL_GPIO_TogglePin(LED_USER2_GPIO_Port, LED_USER2_Pin);
}
}
else
{
nx_tcp_socket_disconnect(&TCPSocket, NX_WAIT_FOREVER);
nx_tcp_server_socket_unaccept(&TCPSocket);
nx_tcp_server_socket_relisten(&NetXDuoEthIpInstance, DEFAULT_PORT, &TCPSocket);
}
}
else
{
/*toggle the green led to indicate the idle state */
// HAL_GPIO_TogglePin(LED_USER2_GPIO_Port, LED_USER2_Pin);
}
}
}
/**
* @brief Link thread entry
* thread_input: ULONG thread parameter
* @retval none
*/
static VOID App_Link_Thread_Entry(ULONG thread_input)
{
ULONG actual_status;
UINT linkdown = 0, status;
while(1)
{
/* Get Physical Link stackavailtus. */
status = nx_ip_interface_status_check(&NetXDuoEthIpInstance, 0, NX_IP_LINK_ENABLED,
&actual_status, 10);
if(status == NX_SUCCESS)
{
if(linkdown == 1)
{
linkdown = 0;
status = nx_ip_interface_status_check(&NetXDuoEthIpInstance, 0, NX_IP_ADDRESS_RESOLVED,
&actual_status, 10);
if(status == NX_SUCCESS)
{
/* The network cable is connected again. */
printf("The network cable is connected again.\n");
/* Print TCP Echo Server is available again. */
printf("TCP Echo Server is available again.\n");
}
else
{
/* The network cable is connected. */
printf("The network cable is connected.\n");
/* Send command to Enable Nx driver. */
nx_ip_driver_direct_command(&NetXDuoEthIpInstance, NX_LINK_ENABLE,
&actual_status);
}
}
}
else
{
if(0 == linkdown)
{
linkdown = 1;
/* The network cable is not connected. */
printf("The network cable is not connected.\n");
}
}
tx_thread_sleep(NX_ETH_CABLE_CONNECTION_CHECK_PERIOD);
}
}
/* USER CODE END 1 */
2024-04-19 07:26 AM - edited 2024-04-19 07:28 AM
I figured out that the problem is related to
https://community.st.com/t5/stm32-mcus-embedded-software/h5-1-2-0-and-cube-1-5-break-ethernet/td-p/653320
and
https://community.st.com/t5/stm32-mcus-embedded-software/netxduo-issues-after-power-loss/td-p/661479
With STM32CubeIDE v1.14.0 it works as expected without debugger and also after switching the power supply.
2024-04-23 02:38 AM
Hello @BViet.1 ,
This is indeed related to the threads you mentioned I'll try to keep you in touch with the updates on this case.
BR
2024-05-25 10:16 AM
Hi @BViet.1!
Please take a look at https://community.st.com/t5/stm32-mcus-embedded-software/netxduo-not-working-with-a-static-ip-addresss/td-p/673975. Maybe the issue you are having is the same as there.
Please let me know if that is a solution for you.
BR,
FabioFly