LWIP learning notes-stm32 enc28j60 porting and getting started

Source: Internet
Author: User
0. Preface LWIP-related code was compiled last year (2013) and "streaking" on stm32 was successful. I have never had time to sort it out in depth. Here I will use a blog to sort out the summary. The LWIP porting process involves a lot of details, and it is impossible for a blog post to explain the specific parts only to the end. [Key Points] [1] LWIP porting without the operating system. The LWIP version is 1.4.1. [2] The MCU is stm32f103ve, And the NIC is enc28j60. [3] The porting process focuses on ethernetif. C and LWIP macro configuration. [4] A simple TCP echo example. [5] strives for simplicity, no DHCP function, or even no Nic interruption. [Code repository] The code repository is located in csdn coder. Download the zip package or use tortoisegit to clone it. Each detail cannot be clearly described in the blog. For more information, see the specific code in the code repository. [Hardware description] The test platform uses the struggling version. For the schematic diagram, see the doc directory in the code repository. [Refer to blog] Learning embedded networks is a step-by-step process, from simple to complex. [1] enc28j60 study notes -- Use of learning NICs [2] Using javasnet study notes -- indexing -- Understanding the TCPIP protocol stack [3] UIP study notes -- Use of the first application protocol stack [4] yeelink Platform -- remote control of RT thread + LWIP + stm32 -- more practical practices
1. Modifications to ethernetif. C. Although the LWIP porting process is complicated, you only need to combine the specific functions of the network card and patiently modify ethernetif. C. Ethernetif. c focuses on three functions of the NIC, namely initialization, sending, and receiving. To better work with LWIP, some driver functions in the enc28j60 learning notes were modified. (In other words, to port LWIP from 0, you must be familiar with the network test operation.) [1] Initialization
static voidlow_level_init(struct netif *netif){  struct ethernetif *ethernetif = netif->state;   /* set MAC hardware address length */  netif->hwaddr_len = ETHARP_HWADDR_LEN;  /* set MAC hardware address */  netif->hwaddr[0] = 'A';  netif->hwaddr[1] = 'R';  netif->hwaddr[2] = 'M';  netif->hwaddr[3] = 'N';  netif->hwaddr[4] = 'E';  netif->hwaddr[5] = 'T';   /* maximum transfer unit */  netif->mtu = 1500;   /* device capabilities */  /* don't set NETIF_FLAG_ETHARP if this device is not an ethernet one */  netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_LINK_UP;   /* Do whatever else is needed to initialize interface. */  enc28j60_init(netif->hwaddr); // 【1】}
[Description] [1] enc28j60_init (netif-> hwaddr); low_level_init specifies the NIC address in enc28j60.
[2] Send
static err_tlow_level_output(struct netif *netif, struct pbuf *p){  struct ethernetif *ethernetif = netif->state;  struct pbuf *q;  enc28j60_init_send(p->tot_len); //【1】initiate transfer(); #if ETH_PAD_SIZE  pbuf_header(p, -ETH_PAD_SIZE); /* drop the padding word */#endif  for(q = p; q != NULL; q = q->next) {    /* Send the data from the pbuf to the interface, one pbuf at a       time. The size of the data in each pbuf is kept in the ->len       variable. */    enc28j60_writebuf( q->payload, q->len ); //【2】send data from(q->payload, q->len);  }  enc28j60_start_send(); //【3】signal that packet should be sent();#if ETH_PAD_SIZE  pbuf_header(p, ETH_PAD_SIZE); /* reclaim the padding word */#endif   LINK_STATS_INC(link.xmit);  return ERR_OK;}
[Description] [1] enc28j60_init_send (p-> tot_len); initialize the sending buffer size. The pbuf structure is a linked list, and the tot_len field in the first pbuf structure represents the size of the entire Ethernet packet. [2] enc28j60_writebuf (Q-> payload, Q-> Len); fill in the content in the buffer zone of enc28j60 through the traversal chain table. [3] enc28j60_start_send (); Enable Nic sending.
[3] receive
static struct pbuf *low_level_input(struct netif *netif){  struct ethernetif *ethernetif = netif->state;  struct pbuf *p, *q;  u16_t len;  /* Obtain the size of the packet and put it into the "len"     variable. */  len = enc28j60_packet_getlen(); // 【1】#if ETH_PAD_SIZE  len += ETH_PAD_SIZE; /* allow room for Ethernet padding */#endif  /* We allocate a pbuf chain of pbufs from the pool. */  p = pbuf_alloc(PBUF_RAW, len, PBUF_POOL);   if (p != NULL) {#if ETH_PAD_SIZE    pbuf_header(p, -ETH_PAD_SIZE); /* drop the padding word */#endif    /* We iterate over the pbuf chain until we have read the entire     * packet into the pbuf. */    for(q = p; q != NULL; q = q->next) {      /* Read enough bytes to fill this pbuf in the chain. The       * available data in the pbuf is given by the q->len       * variable.       * This does not necessarily have to be a memcpy, you can also preallocate       * pbufs for a DMA-enabled MAC and after receiving truncate it to the       * actually received size. In this case, ensure the tot_len member of the       * pbuf is the sum of the chained pbuf len members.       */      enc28j60_readbuf (q->payload, q->len ); //【2】read data into(q->payload, q->len);    }    enc28j60_finish_receive(); //【3】acknowledge that packet has been read();#if ETH_PAD_SIZE    pbuf_header(p, ETH_PAD_SIZE); /* reclaim the padding word */#endif    LINK_STATS_INC(link.recv);  } else {    enc28j60_finish_receive(); //【4】drop packet();    LINK_STATS_INC(link.memerr);    LINK_STATS_INC(link.drop);  }  return p;}
[Description] [1] Len = enc28j60_packet_getlen (); obtain the length of the data packet in the NIC. [2] enc28j60_readbuf (Q-> payload, Q-> Len); copy the content in the NIC to the memory pool. [3] enc28j60_finish_receive (); after receiving is completed, move the buffer pointer in the NIC.
[4] application [1] LWIP Nic hardware initialization call ethernetif_init. This function calls low_level_init and specifies the NIC output function low_level_output. [2] The ethernetif_input function should be substituted immediately once the NIC has data entering. You can use the interrupt method or query method.
2. lwipopt. h configuration description There are many configuration options in LWIP, and it is not easy to understand all the configurations. In this blog, We will summarize the two official examples of stm32.
#ifndef __LWIPOPTS_H__#define __LWIPOPTS_H__/** * SYS_LIGHTWEIGHT_PROT==1: if you want inter-task protection for certain * critical regions during buffer allocation, deallocation and memory * allocation and deallocation. */#define SYS_LIGHTWEIGHT_PROT 0/** * NO_SYS==1: Provides VERY minimal functionality. Otherwise, * use lwIP facilities. */#define NO_SYS 1/** * NO_SYS_NO_TIMERS==1: Drop support for sys_timeout when NO_SYS==1 * Mainly for compatibility to old versions. */#define NO_SYS_NO_TIMERS 1/* ---------- Memory options ---------- *//* MEM_ALIGNMENT: should be set to the alignment of the CPU for which   lwIP is compiled. 4 byte alignment -> define MEM_ALIGNMENT to 4, 2   byte alignment -> define MEM_ALIGNMENT to 2. */#define MEM_ALIGNMENT 4/* MEM_SIZE: the size of the heap memory. If the application will senda lot of data that needs to be copied, this should be set high. */#define MEM_SIZE (5*1024)/* MEMP_NUM_PBUF: the number of memp struct pbufs. If the application   sends a lot of data out of ROM (or other static memory), this   should be set high. */#define MEMP_NUM_PBUF 10/* MEMP_NUM_UDP_PCB: the number of UDP protocol control blocks. One   per active UDP "connection". */#define MEMP_NUM_UDP_PCB 6/* MEMP_NUM_TCP_PCB: the number of simulatenously active TCP   connections. */#define MEMP_NUM_TCP_PCB 10/* MEMP_NUM_TCP_PCB_LISTEN: the number of listening TCP   connections. */#define MEMP_NUM_TCP_PCB_LISTEN 6/* MEMP_NUM_TCP_SEG: the number of simultaneously queued TCP   segments. */#define MEMP_NUM_TCP_SEG 12/* MEMP_NUM_SYS_TIMEOUT: the number of simulateously active   timeouts. */#define MEMP_NUM_SYS_TIMEOUT 3/* ---------- Pbuf options ---------- *//* PBUF_POOL_SIZE: the number of buffers in the pbuf pool. */#define PBUF_POOL_SIZE 10/* PBUF_POOL_BUFSIZE: the size of each pbuf in the pbuf pool. */#define PBUF_POOL_BUFSIZE 1500/* ---------- TCP options ---------- */#define LWIP_TCP 1#define TCP_TTL 255/* Controls if TCP should queue segments that arrive out of   order. Define to 0 if your device is low on memory. */#define TCP_QUEUE_OOSEQ 0/* TCP Maximum segment size. */#define TCP_MSS (1500 - 40) /* TCP_MSS = (Ethernet MTU - IP header size - TCP header size) *//* TCP sender buffer space (bytes). */#define TCP_SND_BUF (2*TCP_MSS)/* TCP sender buffer space (pbufs). This must be at least = 2 *   TCP_SND_BUF/TCP_MSS for things to work. */#define TCP_SND_QUEUELEN (6 * TCP_SND_BUF)/TCP_MSS/* TCP receive window. */#define TCP_WND (2*TCP_MSS)/* ---------- ICMP options ---------- */#define LWIP_ICMP 1/* ---------- DHCP options ---------- *//* Define LWIP_DHCP to 1 if you want DHCP configuration of   interfaces. DHCP is not implemented in lwIP 0.5.1, however, so   turning this on does currently not work. */#define LWIP_DHCP 0/* ---------- UDP options ---------- */#define LWIP_UDP 1#define UDP_TTL 255/* ---------- Statistics options ---------- */#define LWIP_STATS 0#define LWIP_PROVIDE_ERRNO 1/*   --------------------------------------   ---------- Checksum options ----------   --------------------------------------*//*   ----------------------------------------------   ---------- Sequential layer options ----------   ----------------------------------------------*//** * LWIP_NETCONN==1: Enable Netconn API (require to use api_lib.c) */#define LWIP_NETCONN 0/*   ------------------------------------   ---------- Socket options ----------   ------------------------------------*//** * LWIP_SOCKET==1: Enable Socket API (require to use sockets.c) */#define LWIP_SOCKET 0#endif /* __LWIPOPTS_H__ */
[Description and modification] [1] The operating system is not used. All no_sys are defined as 1, lwip_netconn is defined as 0 (indicating no use), and lwip_socket is defined as 0 (indicating no use ). [2] no_sys_no_timers is defined as 1, which is added in lwip1.4.0 or later versions. For details, refer to the LWIP modification document. [3] lwip_dhcp is defined as 0. The DHCP function is disabled to simplify the code. [4] compared with the official stm32 example, all configurations related to the verification code are verified using software. Stm32 uses the code emac mcu in the official case. This family of MCU includes the hardware verification function, but enc28j60 does not. Therefore, you can only enable the software verification function in LWIP. 3. LWIP Initialization
Void lwip_config (void) {struct ip_addr ipaddr; struct ip_addr netmask; struct ip_addr GW; // call the LWIP initialization function lwip_init (); terminate (& ipaddr, 192,168, 1, 16 ); // set the IP address of the network interface ip4_addr (& netmask, 255,255,255, 0); // The subnet mask ip4_addr (& GW, 192,168, 1, 1 ); // gateway // initialize the interface between enc28j60 and LWIP, the parameters are network interface struct, IP address, // subnet mask, gateway, Nic information pointer, initialization function, and input function netif_add (& enc28j60, & ipaddr, & netmask, & GW, null, assumernetif _ init, assumernet _ INPUT); // set enc28j60 to the default Nic netif_set_default (& enc28j60); netif_set_up (& enc28j60 );}
[Description] [1] Use netif_add to initialize the nic ip address, subnet mask, and gateway address. Static IP addresses are used here. [2] netif_add requires two function pointers, namely the NIC initialization function and the receiving content processing function. Ethernetif_init is located in ethernetif. c. ethernet_input is not located in ethernetif. c. ethernetif_input cannot be used here. In fact, ethernet_input is called in the ethernetif_input function, but ethernet_input is changed to the following: netif-> input (p, netif )! = Err_ OK [3] in the port with the operating system, the last parameter uses tcpip_input.
4. While (1)
Timer_typedef tcp_timer, arp_timer;/* sets the query timer ARP timer */timer_set (& tcp_timer, clock_second/10); // TCP processing timer 100 ms timer_set (& arp_timer, clock_second * 5); // ARP processing timer while (1) {If (enc28j60_packet_getcount ()! = 0) {ethernetif_input (& enc28j60) ;}// if (when (& tcp_timer) {timer_set (& tcp_timer, clock_second/4); tcp_tmr ();} // ARP timed processing if (timer_expired (& arp_timer) {timer_set (& arp_timer, clock_second * 5); etharp_tmr ();}}
[Note] the while (1) loop includes three main functions. [1] Once a packet is received, ethernetif_input is called immediately. Here, the query method is used instead of the interrupt method (the interrupt method has similar effects). [2] the TCP link is regularly processed. The scheduled time is 100 ms. The time interval can be reduced as needed. [3] update the ARP buffer regularly. The interval can be extended as appropriate. [4] Here, timer is implemented through javasick. For specific implementation, see code repository.
4. basic test [1] In the ping experiment, the static IP address of the NIC is 192.168.1.16, send 16 packets through ping command Ping 192.168.1.16-N 16 Fig 1 Ping experiment [2] TCP echo example LWIP provides many examples, the TCP echo example is located in the apps folder of the contrib-1.4.1, folder name: tcpecho_raw ). Modify the TCP listening port to 10086. Err = tcp_bind (echo_pcb, ip_addr_any, 10086 );
Figure 2 TCP echo example
5. Conclusion [1] porting and applying LWIP must be patient and meticulous. [2] Once the network adapter receives data, it should call the ethernetif_input function to bring the data into the LWIP protocol stack. [3] netif_add (& enc28j60, & ipaddr, & netmask, & GW, null, & ethernetif_init, & ethernet_input); the last parameter is ethernet_input, which must be written into ethernetif_input.
6. for more information, see [1] Embedded Network System Design-Atmel-based ARM7 series [2] stm32 Embedded System Development Practice Guide-joint transplantation of freertos and LWIP"

LWIP learning notes-stm32 enc28j60 porting and getting started

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.