Skip to main content
Visitor II
October 18, 2023
Question

modbus tcp/ip with stm32f407 and switch ksz8563rnx of microchip

  • October 18, 2023
  • 3 replies
  • 2119 views

Hi,

I've downloaded the following libraries for the modbus tcp/ip communication:

https://www.st.com/en/embedded-software/stsw-stm32070.html 

the experimental setup is a slave: a board with stm32f407 and a switch:

https://www.microchip.com/en-us/product/ksz8563 

the interface between stm32 and ksz is RMII

Now we can read with the modbus function 03H but when we write with the 16H after some transmissions the bus is in error. Is there anyone with the same configuration and the modbus tcp/ip working?

Best regards, Nicolò

    This topic has been closed for replies.

    3 replies

    Visitor II
    October 18, 2023

    Kindly check if the physical connections are correct and secure, especially between the STM32F407 and the KSZ8563 switch.

    Graduate II
    October 22, 2023

    That code is from the year 2015 and is even more broken than their current code:

    https://community.st.com/t5/stm32-mcus-embedded-software/how-to-make-ethernet-and-lwip-working-on-stm32/m-p/261456

    NMelo.1Author
    Visitor II
    October 24, 2023

    In particular the communication is interrupted when the following code of libraries is executed:

    /**
     * @file
     * Ethernet common functions
     *
     * @defgroup ethernet Ethernet
     * @ingroup callbackstyle_api
     */
    
    /*
     * Copyright (c) 2001-2003 Swedish Institute of Computer Science.
     * Copyright (c) 2003-2004 Leon Woestenberg <leon.woestenberg@axon.tv>
     * Copyright (c) 2003-2004 Axon Digital Design B.V., The Netherlands.
     * All rights reserved.
     *
     * Redistribution and use in source and binary forms, with or without modification,
     * are permitted provided that the following conditions are met:
     *
     * 1. Redistributions of source code must retain the above copyright notice,
     * this list of conditions and the following disclaimer.
     * 2. Redistributions in binary form must reproduce the above copyright notice,
     * this list of conditions and the following disclaimer in the documentation
     * and/or other materials provided with the distribution.
     * 3. The name of the author may not be used to endorse or promote products
     * derived from this software without specific prior written permission.
     *
     * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
     * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
     * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
     * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
     * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
     * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
     * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
     * OF SUCH DAMAGE.
     *
     * This file is part of the lwIP TCP/IP stack.
     *
     */
    
    #include "lwip/opt.h"
    
    #if LWIP_ARP || LWIP_ETHERNET
    
    #include "netif/ethernet.h"
    #include "lwip/def.h"
    #include "lwip/stats.h"
    #include "lwip/etharp.h"
    #include "lwip/ip.h"
    #include "lwip/snmp.h"
    
    #include <string.h>
    
    #include "netif/ppp/ppp_opts.h"
    #if PPPOE_SUPPORT
    #include "netif/ppp/pppoe.h"
    #endif /* PPPOE_SUPPORT */
    
    #ifdef LWIP_HOOK_FILENAME
    #include LWIP_HOOK_FILENAME
    #endif
    
    int8_t buf_sel;
    int8_t bdg_buf_eth_3[90],bdg_buf_eth_4[90],bdg_buf_eth_5[90],bdg_buf_eth_6[90];
    
    int16_t ip4,cnt_ethernet_input;
    const struct eth_addr ethbroadcast = {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff}};
    const struct eth_addr ethzero = {{0, 0, 0, 0, 0, 0}};
    
    /**
     * @ingroup lwip_nosys
     * Process received ethernet frames. Using this function instead of directly
     * calling ip_input and passing ARP frames through etharp in ethernetif_input,
     * the ARP cache is protected from concurrent access.\n
     * Don't call directly, pass to netif_add() and call netif->input().
     *
     * @PAram p the received packet, p->payload pointing to the ethernet header
     * @PAram netif the network interface on which the packet was received
     *
     * @see LWIP_HOOK_UNKNOWN_ETH_PROTOCOL
     * @see ETHARP_SUPPORT_VLAN
     * @see LWIP_HOOK_VLAN_CHECK
     */
    err_t
    ethernet_input(struct pbuf *p, struct netif *netif)
    {
     struct eth_hdr *ethhdr;
     u16_t type;
    #if LWIP_ARP || ETHARP_SUPPORT_VLAN || LWIP_IPV6
     u16_t next_hdr_offset = SIZEOF_ETH_HDR;
    #endif /* LWIP_ARP || ETHARP_SUPPORT_VLAN */
    
     LWIP_ASSERT_CORE_LOCKED();
    
     cnt_ethernet_input++;
     HAL_GPIO_WritePin(GPIOD, GPIO_PIN_14,1);
    
    // X NICOLO': entra qui quando si blocca
     if (p->len <= SIZEOF_ETH_HDR) {
     /* a packet with only an ethernet header (or less) is not valid for us */
     ETHARP_STATS_INC(etharp.proterr);
     ETHARP_STATS_INC(etharp.drop);
     MIB2_STATS_NETIF_INC(netif, ifinerrors);
     goto free_and_return;
     }
    
     if (p->if_idx == NETIF_NO_INDEX) {
     p->if_idx = netif_get_index(netif);
     }
    
     /* points to packet payload, which starts with an Ethernet header */
     ethhdr = (struct eth_hdr *)p->payload;
     LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE,
     ("ethernet_input: dest:%"X8_F":%"X8_F":%"X8_F":%"X8_F":%"X8_F":%"X8_F", src:%"X8_F":%"X8_F":%"X8_F":%"X8_F":%"X8_F":%"X8_F", type:%"X16_F"\n",
     (unsigned char)ethhdr->dest.addr[0], (unsigned char)ethhdr->dest.addr[1], (unsigned char)ethhdr->dest.addr[2],
     (unsigned char)ethhdr->dest.addr[3], (unsigned char)ethhdr->dest.addr[4], (unsigned char)ethhdr->dest.addr[5],
     (unsigned char)ethhdr->src.addr[0], (unsigned char)ethhdr->src.addr[1], (unsigned char)ethhdr->src.addr[2],
     (unsigned char)ethhdr->src.addr[3], (unsigned char)ethhdr->src.addr[4], (unsigned char)ethhdr->src.addr[5],
     lwip_htons(ethhdr->type)));
     HAL_GPIO_WritePin(GPIOD, GPIO_PIN_14,0);
    
     type = ethhdr->type;
    #if ETHARP_SUPPORT_VLAN
     if (type == PP_HTONS(ETHTYPE_VLAN)) {
     struct eth_vlan_hdr *vlan = (struct eth_vlan_hdr *)(((char *)ethhdr) + SIZEOF_ETH_HDR);
     next_hdr_offset = SIZEOF_ETH_HDR + SIZEOF_VLAN_HDR;
     if (p->len <= SIZEOF_ETH_HDR + SIZEOF_VLAN_HDR) {
     /* a packet with only an ethernet/vlan header (or less) is not valid for us */
     ETHARP_STATS_INC(etharp.proterr);
     ETHARP_STATS_INC(etharp.drop);
     MIB2_STATS_NETIF_INC(netif, ifinerrors);
     goto free_and_return;
     }
    #if defined(LWIP_HOOK_VLAN_CHECK) || defined(ETHARP_VLAN_CHECK) || defined(ETHARP_VLAN_CHECK_FN) /* if not, allow all VLANs */
    #ifdef LWIP_HOOK_VLAN_CHECK
     if (!LWIP_HOOK_VLAN_CHECK(netif, ethhdr, vlan)) {
    #elif defined(ETHARP_VLAN_CHECK_FN)
     if (!ETHARP_VLAN_CHECK_FN(ethhdr, vlan)) {
    #elif defined(ETHARP_VLAN_CHECK)
     if (VLAN_ID(vlan) != ETHARP_VLAN_CHECK) {
    #endif
     /* silently ignore this packet: not for our VLAN */
     pbuf_free(p);
     return ERR_OK;
     }
    #endif /* defined(LWIP_HOOK_VLAN_CHECK) || defined(ETHARP_VLAN_CHECK) || defined(ETHARP_VLAN_CHECK_FN) */
     type = vlan->tpid;
     }
    #endif /* ETHARP_SUPPORT_VLAN */
    
    #if LWIP_ARP_FILTER_NETIF
     netif = LWIP_ARP_FILTER_NETIF_FN(p, netif, lwip_htons(type));
    #endif /* LWIP_ARP_FILTER_NETIF*/
    
     if (ethhdr->dest.addr[0] & 1) {
     /* this might be a multicast or broadcast packet */
     if (ethhdr->dest.addr[0] == LL_IP4_MULTICAST_ADDR_0) {
    #if LWIP_IPV4
     if ((ethhdr->dest.addr[1] == LL_IP4_MULTICAST_ADDR_1) &&
     (ethhdr->dest.addr[2] == LL_IP4_MULTICAST_ADDR_2)) {
     /* mark the pbuf as link-layer multicast */
     p->flags |= PBUF_FLAG_LLMCAST;
     }
    #endif /* LWIP_IPV4 */
     }
    #if LWIP_IPV6
     else if ((ethhdr->dest.addr[0] == LL_IP6_MULTICAST_ADDR_0) &&
     (ethhdr->dest.addr[1] == LL_IP6_MULTICAST_ADDR_1)) {
     /* mark the pbuf as link-layer multicast */
     p->flags |= PBUF_FLAG_LLMCAST;
     }
    #endif /* LWIP_IPV6 */
     else if (eth_addr_cmp(&ethhdr->dest, &ethbroadcast)) {
     /* mark the pbuf as link-layer broadcast */
     p->flags |= PBUF_FLAG_LLBCAST;
     }
     }
    
    
     switch (type) {
    #if LWIP_IPV4 && LWIP_ARP
     /* IP packet? */
     case PP_HTONS(ETHTYPE_IP):
     if (!(netif->flags & NETIF_FLAG_ETHARP)) {
     goto free_and_return;
     }
     /* skip Ethernet header (min. size checked above) */
     if (pbuf_remove_header(p, next_hdr_offset)) {
     ip4-=10;
    
     	 LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING,
     ("ethernet_input: IPv4 packet dropped, too short (%"U16_F"/%"U16_F")\n",
     p->tot_len, next_hdr_offset));
     LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("Can't move over header in packet"));
     goto free_and_return;
     } else {
     /* pass to IP layer */
    
     	int8_t *p_raw;
     	int8_t i;
     	p_raw = p->payload;
    
     	switch(buf_sel)
     		{
     		case 0:
     			for(i = 0; i < 64; i++)
     				bdg_buf_eth_3[i] = *p_raw++;
     			buf_sel = 1;
     	break;
     		case 1:
     		for(i = 0; i < 64; i++)
     			bdg_buf_eth_4[i] = *p_raw++;
     		buf_sel = 2;
     break;
     		case 2:
     		for(i = 0; i < 64; i++)
     			bdg_buf_eth_5[i] = *p_raw++;
     		buf_sel = 3;
     break;
     		case 3:
     		for(i = 0; i < 64; i++)
     			bdg_buf_eth_6[i] = *p_raw++;
     		buf_sel = 0;
     break;
    
     		}
    
    
     ip4_input(p, netif);
    
    
    
    
     ip4++;
     }
     break;
    
     case PP_HTONS(ETHTYPE_ARP):
     if (!(netif->flags & NETIF_FLAG_ETHARP)) {
     goto free_and_return;
     }
     /* skip Ethernet header (min. size checked above) */
     if (pbuf_remove_header(p, next_hdr_offset)) {
     LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING,
     ("ethernet_input: ARP response packet dropped, too short (%"U16_F"/%"U16_F")\n",
     p->tot_len, next_hdr_offset));
     LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("Can't move over header in packet"));
     ETHARP_STATS_INC(etharp.lenerr);
     ETHARP_STATS_INC(etharp.drop);
     goto free_and_return;
     } else {
     /* pass p to ARP module */
     etharp_input(p, netif);
     }
     break;
    #endif /* LWIP_IPV4 && LWIP_ARP */
    #if PPPOE_SUPPORT
     case PP_HTONS(ETHTYPE_PPPOEDISC): /* PPP Over Ethernet Discovery Stage */
     pppoe_disc_input(netif, p);
     break;
    
     case PP_HTONS(ETHTYPE_PPPOE): /* PPP Over Ethernet Session Stage */
     pppoe_data_input(netif, p);
     break;
    #endif /* PPPOE_SUPPORT */
    
    #if LWIP_IPV6
     case PP_HTONS(ETHTYPE_IPV6): /* IPv6 */
     /* skip Ethernet header */
     if ((p->len < next_hdr_offset) || pbuf_remove_header(p, next_hdr_offset)) {
     LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING,
     ("ethernet_input: IPv6 packet dropped, too short (%"U16_F"/%"U16_F")\n",
     p->tot_len, next_hdr_offset));
     goto free_and_return;
     } else {
     /* pass to IPv6 layer */
     ip6_input(p, netif);
     }
     break;
    #endif /* LWIP_IPV6 */
    
     default:
    #ifdef LWIP_HOOK_UNKNOWN_ETH_PROTOCOL
     if (LWIP_HOOK_UNKNOWN_ETH_PROTOCOL(p, netif) == ERR_OK) {
     break;
     }
    #endif
     ETHARP_STATS_INC(etharp.proterr);
     ETHARP_STATS_INC(etharp.drop);
     MIB2_STATS_NETIF_INC(netif, ifinunknownprotos);
     goto free_and_return;
     }
    
     /* This means the pbuf is freed or consumed,
     so the caller doesn't have to free it again */
    
     return ERR_OK;
    
    free_and_return:
     pbuf_free(p);
    
     return ERR_OK;
    }
    
    /**
     * @ingroup ethernet
     * Send an ethernet packet on the network using netif->linkoutput().
     * The ethernet header is filled in before sending.
     *
     * @see LWIP_HOOK_VLAN_SET
     *
     * @PAram netif the lwIP network interface on which to send the packet
     * @PAram p the packet to send. pbuf layer must be @ref PBUF_LINK.
     * @PAram src the source MAC address to be copied into the ethernet header
     * @PAram dst the destination MAC address to be copied into the ethernet header
     * @PAram eth_type ethernet type (@ref lwip_ieee_eth_type)
     * @return ERR_OK if the packet was sent, any other err_t on failure
     */
    err_t
    ethernet_output(struct netif * netif, struct pbuf * p,
     const struct eth_addr * src, const struct eth_addr * dst,
     u16_t eth_type) {
     struct eth_hdr *ethhdr;
     u16_t eth_type_be = lwip_htons(eth_type);
    
    #if ETHARP_SUPPORT_VLAN && defined(LWIP_HOOK_VLAN_SET)
     s32_t vlan_prio_vid = LWIP_HOOK_VLAN_SET(netif, p, src, dst, eth_type);
     if (vlan_prio_vid >= 0) {
     struct eth_vlan_hdr *vlanhdr;
    
     LWIP_ASSERT("prio_vid must be <= 0xFFFF", vlan_prio_vid <= 0xFFFF);
    
     if (pbuf_add_header(p, SIZEOF_ETH_HDR + SIZEOF_VLAN_HDR) != 0) {
     goto pbuf_header_failed;
     }
     vlanhdr = (struct eth_vlan_hdr *)(((u8_t *)p->payload) + SIZEOF_ETH_HDR);
     vlanhdr->tpid = eth_type_be;
     vlanhdr->prio_vid = lwip_htons((u16_t)vlan_prio_vid);
    
     eth_type_be = PP_HTONS(ETHTYPE_VLAN);
     } else
    #endif /* ETHARP_SUPPORT_VLAN && defined(LWIP_HOOK_VLAN_SET) */
     {
     if (pbuf_add_header(p, SIZEOF_ETH_HDR) != 0) {
     goto pbuf_header_failed;
     }
     }
    
     LWIP_ASSERT_CORE_LOCKED();
    
     ethhdr = (struct eth_hdr *)p->payload;
     ethhdr->type = eth_type_be;
     SMEMCPY(&ethhdr->dest, dst, ETH_HWADDR_LEN);
     SMEMCPY(&ethhdr->src, src, ETH_HWADDR_LEN);
    
     LWIP_ASSERT("netif->hwaddr_len must be 6 for ethernet_output!",
     (netif->hwaddr_len == ETH_HWADDR_LEN));
     LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE,
     ("ethernet_output: sending packet %p\n", (void *)p));
    
     /* send the packet */
     return netif->linkoutput(netif, p);
    
    pbuf_header_failed:
     LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS,
     ("ethernet_output: could not allocate room for header.\n"));
     LINK_STATS_INC(link.lenerr);
     return ERR_BUF;
    }
    
    #endif /* LWIP_ARP || LWIP_ETHERNET */
    Graduate II
    October 30, 2023

    Why did you posted the whole "ethernet.c" file from lwIP, which everyone can view even online? And, even if you do it, code of that size should be added as an attached file instead of this super-long post.

    And those modifications you did supposedly for debugging... I gave you a link, which reports tons of issues with the current ST's broken bloatware and said that the old SPL based networking code was even more broken. Unless you fix all of those flaws, there is no point in "debugging" the IP stack!