Skip to main content
Associate III
May 6, 2024
Solved

void HardFault_Handler(void) issue during data sent via ethernet through TCP_Client

  • May 6, 2024
  • 1 reply
  • 1291 views

HI team,

I am Using NUCLEO-F439ZI board for Ethernet Interface. I successfully transferred the data in UDP, Now I try to send the data using TCP client method. 

In the .ioc configuration file, I followed the below setup

1. Connectivity -> ETH -> RMII mode.

2. Middleware and Software Packs -> LWIP -> General Setting -> LWIP_DHCP (set own IP -> 192.168.1.10)

 Middleware and Software Packs -> LWIP -> Key Option -> heap memory size = 10*1024 bytes.

 Middleware and Software Packs -> LWIP -> HTTPD -> LWIP_HTTPD - enable

after all this setup I generate the code

In the Main.c file 

1. by using this code I ping the connection, its works fine "extern struct netif gnetif;      

ethernetif_input(&gnetif);

sys_check_timeouts();".

2. from this sub function "tcp_server_init();",

To create a TCP block,

Bind the socket to Server Address

Listen from client

Accept function - connection between client and server

After done all this process it successfully debugs and make the connection successfully

 
Ramachandran1992_1-1714984670193.png

The connection made successfully, whenever I try to send the data, the following error

occurred. The below attachment shows the error.

Ramachandran1992_2-1714984987888.png

In the "static void tcp_server_handle (struct tcp_pcb *tpcb, struct tcp_server_struct *es)" function I changed the code this code " char buf[100]; memset (buf, '\0', 100); strncpy(buf, (char *)es->p->payload, es->p->tot_len);

strcat (buf, "+ Hello from TCP SERVER\n"); " to " int len = sprintf(buf, ""%s + Hello from TCPServer\n",(char *)es->p->payload);" the above error was cleared. but my data was not transfer to client, I don't know where I do the mistake. notify my error and mistake.  

The detailed "tcp_server_init()" program was attached below for your reference

Thank you

regards

RAMACHANDRAN.S

Best answer by STea

Hello @Ramachandran1992 ,

After an examination of the attached file, it seems  tcp_server_handle you are implementing is unable to properly allocate a buffer this should be done with the Pbuf_alloc function.
my recommendation is to take the example we give in the cube Firmware which can be obtained from Github or from the ST website as a reference so the revised version of your tcp_server_raw.c will be as follows :

/**
 ******************************************************************************
 * @file LwIP/LwIP_TCP_Echo_Client/Src/tcp_echoclient.c
 * @author MCD Application Team
 * @brief tcp echoclient application using LwIP RAW API
 ******************************************************************************
 * @attention
 *
 * Copyright (c) 2017 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.
 *
 ******************************************************************************
 */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "lwip/debug.h"
#include "lwip/stats.h"
#include "lwip/tcp.h"
#include "lwip/memp.h"
#include <stdio.h>
#include <string.h>

#if LWIP_TCP
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
u8_t recev_buf[50];
__IO uint32_t message_count=0;

u8_t data[100];

struct tcp_pcb *echoclient_pcb;

/* ECHO protocol states */
enum echoclient_states
{
 ES_NOT_CONNECTED = 0,
 ES_CONNECTED,
 ES_RECEIVED,
 ES_CLOSING,
};

/* structure to be passed as argument to the tcp callbacks */
struct echoclient
{
 enum echoclient_states state; /* connection status */
 struct tcp_pcb *pcb; /* pointer on the current tcp_pcb */
 struct pbuf *p_tx; /* pointer on pbuf to be transmitted */
};

/* Private function prototypes -----------------------------------------------*/
static err_t tcp_echoclient_recv(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err);
static void tcp_echoclient_connection_close(struct tcp_pcb *tpcb, struct echoclient * es);
static err_t tcp_echoclient_poll(void *arg, struct tcp_pcb *tpcb);
static err_t tcp_echoclient_sent(void *arg, struct tcp_pcb *tpcb, u16_t len);
static void tcp_echoclient_send(struct tcp_pcb *tpcb, struct echoclient * es);
static err_t tcp_echoclient_connected(void *arg, struct tcp_pcb *tpcb, err_t err);

/* Private functions ---------------------------------------------------------*/


/**
 * @brief Connects to the TCP echo server
 * @param None
 * @retval None
 */
void tcp_echoclient_connect(void)
{
 ip_addr_t DestIPaddr;
 
 /* create new tcp pcb */
 echoclient_pcb = tcp_new();
 
 if (echoclient_pcb != NULL)
 {
 IP4_ADDR( &DestIPaddr, DEST_IP_ADDR0, DEST_IP_ADDR1, DEST_IP_ADDR2, DEST_IP_ADDR3 );
 
 /* connect to destination address/port */
 tcp_connect(echoclient_pcb,&DestIPaddr,DEST_PORT,tcp_echoclient_connected);
 }
}

/**
 * @brief Function called when TCP connection established
 * @param tpcb: pointer on the connection control block
 * @param err: when connection correctly established err should be ERR_OK 
 * @retval err_t: returned error 
 */
static err_t tcp_echoclient_connected(void *arg, struct tcp_pcb *tpcb, err_t err)
{
 struct echoclient *es = NULL;
 
 if (err == ERR_OK) 
 {
 /* allocate structure es to maintain tcp connection information */
 es = (struct echoclient *)mem_malloc(sizeof(struct echoclient));
 
 if (es != NULL)
 {
 es->state = ES_CONNECTED;
 es->pcb = tpcb;
 
 sprintf((char*)data, "sending tcp client message %d", (int)message_count);
 
 /* allocate pbuf */
 es->p_tx = pbuf_alloc(PBUF_TRANSPORT, strlen((char*)data) , PBUF_POOL);
 
 if (es->p_tx)
 { 
 /* copy data to pbuf */
 pbuf_take(es->p_tx, (char*)data, strlen((char*)data));
 
 /* pass newly allocated es structure as argument to tpcb */
 tcp_arg(tpcb, es);
 
 /* initialize LwIP tcp_recv callback function */ 
 tcp_recv(tpcb, tcp_echoclient_recv);
 
 /* initialize LwIP tcp_sent callback function */
 tcp_sent(tpcb, tcp_echoclient_sent);
 
 /* initialize LwIP tcp_poll callback function */
 tcp_poll(tpcb, tcp_echoclient_poll, 1);
 
 /* send data */
 tcp_echoclient_send(tpcb,es);
 
 return ERR_OK;
 }
 }
 else
 {
 /* close connection */
 tcp_echoclient_connection_close(tpcb, es);
 
 /* return memory allocation error */
 return ERR_MEM; 
 }
 }
 else
 {
 /* close connection */
 tcp_echoclient_connection_close(tpcb, es);
 }
 return err;
}
 
/**
 * @brief tcp_receiv callback
 * @param arg: argument to be passed to receive callback 
 * @param tpcb: tcp connection control block 
 * @param err: receive error code 
 * @retval err_t: returned error 
 */
static err_t tcp_echoclient_recv(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err)
{ 
 struct echoclient *es;
 err_t ret_err; 

 LWIP_ASSERT("arg != NULL",arg != NULL);
 
 es = (struct echoclient *)arg;
 
 /* if we receive an empty tcp frame from server => close connection */
 if (p == NULL)
 {
 /* remote host closed connection */
 es->state = ES_CLOSING;
 if(es->p_tx == NULL)
 {
 /* we're done sending, close connection */
 tcp_echoclient_connection_close(tpcb, es);
 }
 else
 { 
 /* send remaining data*/
 tcp_echoclient_send(tpcb, es);
 }
 ret_err = ERR_OK;
 } 
 /* else : a non empty frame was received from echo server but for some reason err != ERR_OK */
 else if(err != ERR_OK)
 {
 /* free received pbuf*/
 if (p != NULL)
 {
 pbuf_free(p);
 }
 ret_err = err;
 }
 else if(es->state == ES_CONNECTED)
 {
 /* increment message count */
 message_count++;
 
 /* Acknowledge data reception */
 tcp_recved(tpcb, p->tot_len); 
 
 pbuf_free(p);
 tcp_echoclient_connection_close(tpcb, es);
 ret_err = ERR_OK;
 }

 /* data received when connection already closed */
 else
 {
 /* Acknowledge data reception */
 tcp_recved(tpcb, p->tot_len);
 
 /* free pbuf and do nothing */
 pbuf_free(p);
 ret_err = ERR_OK;
 }
 return ret_err;
}

/**
 * @brief function used to send data
 * @param tpcb: tcp control block
 * @param es: pointer on structure of type echoclient containing info on data 
 * to be sent
 * @retval None 
 */
static void tcp_echoclient_send(struct tcp_pcb *tpcb, struct echoclient * es)
{
 struct pbuf *ptr;
 err_t wr_err = ERR_OK;
 
 while ((wr_err == ERR_OK) &&
 (es->p_tx != NULL) && 
 (es->p_tx->len <= tcp_sndbuf(tpcb)))
 {
 
 /* get pointer on pbuf from es structure */
 ptr = es->p_tx;

 /* enqueue data for transmission */
 wr_err = tcp_write(tpcb, ptr->payload, ptr->len, 1);
 
 if (wr_err == ERR_OK)
 { 
 /* continue with next pbuf in chain (if any) */
 es->p_tx = ptr->next;
 
 if(es->p_tx != NULL)
 {
 /* increment reference count for es->p */
 pbuf_ref(es->p_tx);
 }
 
 /* free pbuf: will free pbufs up to es->p (because es->p has a reference count > 0) */
 pbuf_free(ptr);
 }
 else if(wr_err == ERR_MEM)
 {
 /* we are low on memory, try later, defer to poll */
 es->p_tx = ptr;
 }
 else
 {
 /* other problem ?? */
 }
 }
}

/**
 * @brief This function implements the tcp_poll callback function
 * @param arg: pointer on argument passed to callback
 * @param tpcb: tcp connection control block
 * @retval err_t: error code
 */
static err_t tcp_echoclient_poll(void *arg, struct tcp_pcb *tpcb)
{
 err_t ret_err;
 struct echoclient *es;

 es = (struct echoclient*)arg;
 if (es != NULL)
 {
 if (es->p_tx != NULL)
 {
 /* there is a remaining pbuf (chain) , try to send data */
 tcp_echoclient_send(tpcb, es);
 }
 else
 {
 /* no remaining pbuf (chain) */
 if(es->state == ES_CLOSING)
 {
 /* close tcp connection */
 tcp_echoclient_connection_close(tpcb, es);
 }
 }
 ret_err = ERR_OK;
 }
 else
 {
 /* nothing to be done */
 tcp_abort(tpcb);
 ret_err = ERR_ABRT;
 }
 return ret_err;
}

/**
 * @brief This function implements the tcp_sent LwIP callback (called when ACK
 * is received from remote host for sent data) 
 * @param arg: pointer on argument passed to callback
 * @param tcp_pcb: tcp connection control block
 * @param len: length of data sent 
 * @retval err_t: returned error code
 */
static err_t tcp_echoclient_sent(void *arg, struct tcp_pcb *tpcb, u16_t len)
{
 struct echoclient *es;

 LWIP_UNUSED_ARG(len);

 es = (struct echoclient *)arg;
 
 if(es->p_tx != NULL)
 {
 /* still got pbufs to send */
 tcp_echoclient_send(tpcb, es);
 }

 return ERR_OK;
}

/**
 * @brief This function is used to close the tcp connection with server
 * @param tpcb: tcp connection control block
 * @param es: pointer on echoclient structure
 * @retval None
 */
static void tcp_echoclient_connection_close(struct tcp_pcb *tpcb, struct echoclient * es )
{
 /* remove callbacks */
 tcp_recv(tpcb, NULL);
 tcp_sent(tpcb, NULL);
 tcp_poll(tpcb, NULL,0);

 if (es != NULL)
 {
 mem_free(es);
 }

 /* close tcp connection */
 tcp_close(tpcb); 
}

#endif /* LWIP_TCP */

 
Regards 

1 reply

STeaBest answer
ST Employee
May 31, 2024

Hello @Ramachandran1992 ,

After an examination of the attached file, it seems  tcp_server_handle you are implementing is unable to properly allocate a buffer this should be done with the Pbuf_alloc function.
my recommendation is to take the example we give in the cube Firmware which can be obtained from Github or from the ST website as a reference so the revised version of your tcp_server_raw.c will be as follows :

/**
 ******************************************************************************
 * @file LwIP/LwIP_TCP_Echo_Client/Src/tcp_echoclient.c
 * @author MCD Application Team
 * @brief tcp echoclient application using LwIP RAW API
 ******************************************************************************
 * @attention
 *
 * Copyright (c) 2017 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.
 *
 ******************************************************************************
 */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "lwip/debug.h"
#include "lwip/stats.h"
#include "lwip/tcp.h"
#include "lwip/memp.h"
#include <stdio.h>
#include <string.h>

#if LWIP_TCP
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
u8_t recev_buf[50];
__IO uint32_t message_count=0;

u8_t data[100];

struct tcp_pcb *echoclient_pcb;

/* ECHO protocol states */
enum echoclient_states
{
 ES_NOT_CONNECTED = 0,
 ES_CONNECTED,
 ES_RECEIVED,
 ES_CLOSING,
};

/* structure to be passed as argument to the tcp callbacks */
struct echoclient
{
 enum echoclient_states state; /* connection status */
 struct tcp_pcb *pcb; /* pointer on the current tcp_pcb */
 struct pbuf *p_tx; /* pointer on pbuf to be transmitted */
};

/* Private function prototypes -----------------------------------------------*/
static err_t tcp_echoclient_recv(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err);
static void tcp_echoclient_connection_close(struct tcp_pcb *tpcb, struct echoclient * es);
static err_t tcp_echoclient_poll(void *arg, struct tcp_pcb *tpcb);
static err_t tcp_echoclient_sent(void *arg, struct tcp_pcb *tpcb, u16_t len);
static void tcp_echoclient_send(struct tcp_pcb *tpcb, struct echoclient * es);
static err_t tcp_echoclient_connected(void *arg, struct tcp_pcb *tpcb, err_t err);

/* Private functions ---------------------------------------------------------*/


/**
 * @brief Connects to the TCP echo server
 * @param None
 * @retval None
 */
void tcp_echoclient_connect(void)
{
 ip_addr_t DestIPaddr;
 
 /* create new tcp pcb */
 echoclient_pcb = tcp_new();
 
 if (echoclient_pcb != NULL)
 {
 IP4_ADDR( &DestIPaddr, DEST_IP_ADDR0, DEST_IP_ADDR1, DEST_IP_ADDR2, DEST_IP_ADDR3 );
 
 /* connect to destination address/port */
 tcp_connect(echoclient_pcb,&DestIPaddr,DEST_PORT,tcp_echoclient_connected);
 }
}

/**
 * @brief Function called when TCP connection established
 * @param tpcb: pointer on the connection control block
 * @param err: when connection correctly established err should be ERR_OK 
 * @retval err_t: returned error 
 */
static err_t tcp_echoclient_connected(void *arg, struct tcp_pcb *tpcb, err_t err)
{
 struct echoclient *es = NULL;
 
 if (err == ERR_OK) 
 {
 /* allocate structure es to maintain tcp connection information */
 es = (struct echoclient *)mem_malloc(sizeof(struct echoclient));
 
 if (es != NULL)
 {
 es->state = ES_CONNECTED;
 es->pcb = tpcb;
 
 sprintf((char*)data, "sending tcp client message %d", (int)message_count);
 
 /* allocate pbuf */
 es->p_tx = pbuf_alloc(PBUF_TRANSPORT, strlen((char*)data) , PBUF_POOL);
 
 if (es->p_tx)
 { 
 /* copy data to pbuf */
 pbuf_take(es->p_tx, (char*)data, strlen((char*)data));
 
 /* pass newly allocated es structure as argument to tpcb */
 tcp_arg(tpcb, es);
 
 /* initialize LwIP tcp_recv callback function */ 
 tcp_recv(tpcb, tcp_echoclient_recv);
 
 /* initialize LwIP tcp_sent callback function */
 tcp_sent(tpcb, tcp_echoclient_sent);
 
 /* initialize LwIP tcp_poll callback function */
 tcp_poll(tpcb, tcp_echoclient_poll, 1);
 
 /* send data */
 tcp_echoclient_send(tpcb,es);
 
 return ERR_OK;
 }
 }
 else
 {
 /* close connection */
 tcp_echoclient_connection_close(tpcb, es);
 
 /* return memory allocation error */
 return ERR_MEM; 
 }
 }
 else
 {
 /* close connection */
 tcp_echoclient_connection_close(tpcb, es);
 }
 return err;
}
 
/**
 * @brief tcp_receiv callback
 * @param arg: argument to be passed to receive callback 
 * @param tpcb: tcp connection control block 
 * @param err: receive error code 
 * @retval err_t: returned error 
 */
static err_t tcp_echoclient_recv(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err)
{ 
 struct echoclient *es;
 err_t ret_err; 

 LWIP_ASSERT("arg != NULL",arg != NULL);
 
 es = (struct echoclient *)arg;
 
 /* if we receive an empty tcp frame from server => close connection */
 if (p == NULL)
 {
 /* remote host closed connection */
 es->state = ES_CLOSING;
 if(es->p_tx == NULL)
 {
 /* we're done sending, close connection */
 tcp_echoclient_connection_close(tpcb, es);
 }
 else
 { 
 /* send remaining data*/
 tcp_echoclient_send(tpcb, es);
 }
 ret_err = ERR_OK;
 } 
 /* else : a non empty frame was received from echo server but for some reason err != ERR_OK */
 else if(err != ERR_OK)
 {
 /* free received pbuf*/
 if (p != NULL)
 {
 pbuf_free(p);
 }
 ret_err = err;
 }
 else if(es->state == ES_CONNECTED)
 {
 /* increment message count */
 message_count++;
 
 /* Acknowledge data reception */
 tcp_recved(tpcb, p->tot_len); 
 
 pbuf_free(p);
 tcp_echoclient_connection_close(tpcb, es);
 ret_err = ERR_OK;
 }

 /* data received when connection already closed */
 else
 {
 /* Acknowledge data reception */
 tcp_recved(tpcb, p->tot_len);
 
 /* free pbuf and do nothing */
 pbuf_free(p);
 ret_err = ERR_OK;
 }
 return ret_err;
}

/**
 * @brief function used to send data
 * @param tpcb: tcp control block
 * @param es: pointer on structure of type echoclient containing info on data 
 * to be sent
 * @retval None 
 */
static void tcp_echoclient_send(struct tcp_pcb *tpcb, struct echoclient * es)
{
 struct pbuf *ptr;
 err_t wr_err = ERR_OK;
 
 while ((wr_err == ERR_OK) &&
 (es->p_tx != NULL) && 
 (es->p_tx->len <= tcp_sndbuf(tpcb)))
 {
 
 /* get pointer on pbuf from es structure */
 ptr = es->p_tx;

 /* enqueue data for transmission */
 wr_err = tcp_write(tpcb, ptr->payload, ptr->len, 1);
 
 if (wr_err == ERR_OK)
 { 
 /* continue with next pbuf in chain (if any) */
 es->p_tx = ptr->next;
 
 if(es->p_tx != NULL)
 {
 /* increment reference count for es->p */
 pbuf_ref(es->p_tx);
 }
 
 /* free pbuf: will free pbufs up to es->p (because es->p has a reference count > 0) */
 pbuf_free(ptr);
 }
 else if(wr_err == ERR_MEM)
 {
 /* we are low on memory, try later, defer to poll */
 es->p_tx = ptr;
 }
 else
 {
 /* other problem ?? */
 }
 }
}

/**
 * @brief This function implements the tcp_poll callback function
 * @param arg: pointer on argument passed to callback
 * @param tpcb: tcp connection control block
 * @retval err_t: error code
 */
static err_t tcp_echoclient_poll(void *arg, struct tcp_pcb *tpcb)
{
 err_t ret_err;
 struct echoclient *es;

 es = (struct echoclient*)arg;
 if (es != NULL)
 {
 if (es->p_tx != NULL)
 {
 /* there is a remaining pbuf (chain) , try to send data */
 tcp_echoclient_send(tpcb, es);
 }
 else
 {
 /* no remaining pbuf (chain) */
 if(es->state == ES_CLOSING)
 {
 /* close tcp connection */
 tcp_echoclient_connection_close(tpcb, es);
 }
 }
 ret_err = ERR_OK;
 }
 else
 {
 /* nothing to be done */
 tcp_abort(tpcb);
 ret_err = ERR_ABRT;
 }
 return ret_err;
}

/**
 * @brief This function implements the tcp_sent LwIP callback (called when ACK
 * is received from remote host for sent data) 
 * @param arg: pointer on argument passed to callback
 * @param tcp_pcb: tcp connection control block
 * @param len: length of data sent 
 * @retval err_t: returned error code
 */
static err_t tcp_echoclient_sent(void *arg, struct tcp_pcb *tpcb, u16_t len)
{
 struct echoclient *es;

 LWIP_UNUSED_ARG(len);

 es = (struct echoclient *)arg;
 
 if(es->p_tx != NULL)
 {
 /* still got pbufs to send */
 tcp_echoclient_send(tpcb, es);
 }

 return ERR_OK;
}

/**
 * @brief This function is used to close the tcp connection with server
 * @param tpcb: tcp connection control block
 * @param es: pointer on echoclient structure
 * @retval None
 */
static void tcp_echoclient_connection_close(struct tcp_pcb *tpcb, struct echoclient * es )
{
 /* remove callbacks */
 tcp_recv(tpcb, NULL);
 tcp_sent(tpcb, NULL);
 tcp_poll(tpcb, NULL,0);

 if (es != NULL)
 {
 mem_free(es);
 }

 /* close tcp connection */
 tcp_close(tpcb); 
}

#endif /* LWIP_TCP */

 
Regards 

In order 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.