简要记录lwip在stm32f4上的移植步骤:
最简单的lwip移植主要是底层数据收发硬件接口的实现以及配置,在此处主要是ethernetif.c ethernetif.h以及配置文件lwipopt.h的修改
1. main函数
struct netif gnetif;
static void SystemClock_Config(void);
static void BSP_Config(void);
static void Netif_Config(void);
int main(void)
{
HAL_Init();
SystemClock_Config();
/* Configure the BSP */
BSP_Config();
/* Initialize the LwIP stack */
lwip_init();
Netif_Config();
/* tcp echo server Init */
tcp_echoserver_init();
/* Notify user about the network interface config */
User_notification(&gnetif);
while (1)
{
ethernetif_input(&gnetif);
sys_check_timeouts();
}
}
其中Netif_Config()是底层的初始化配置; tcp_echoserver_init()是上层(应用层的配置)
1.1 Netif_Config():
其中netif_add(&gnetif, &ipaddr, &netmask, &gw, NULL, ðernetif_init, ðernet_input);这句实现了初始化,并注册了接收驱动接口。
static void Netif_Config(void)
{
ip_addr_t ipaddr;
ip_addr_t netmask;
ip_addr_t gw;
#ifdef USE_DHCP
ip_addr_set_zero_ip4(&ipaddr);
ip_addr_set_zero_ip4(&netmask);
ip_addr_set_zero_ip4(&gw);
#else
IP_ADDR4(&ipaddr,IP_ADDR0,IP_ADDR1,IP_ADDR2,IP_ADDR3);
IP_ADDR4(&netmask,NETMASK_ADDR0,NETMASK_ADDR1,NETMASK_ADDR2,NETMASK_ADDR3);
IP_ADDR4(&gw,GW_ADDR0,GW_ADDR1,GW_ADDR2,GW_ADDR3);
#endif /* USE_DHCP */
/* Add the network interface */
netif_add(&gnetif, &ipaddr, &netmask, &gw, NULL, ðernetif_init, ðernet_input);
/* Registers the default network interface */
netif_set_default(&gnetif);
if (netif_is_link_up(&gnetif))
{
/* When the netif is fully configured this function must be called */
netif_set_up(&gnetif);
}
else
{
/* When the netif link is down this function must be called */
netif_set_down(&gnetif);
}
/* Set the link callback function, this function is called on change of link status*/
netif_set_link_callback(&gnetif, ethernetif_update_config);
}
1.2 tcp_echoserver_init()
体现了tcp server 应用层的基本操作, tcp新建-> 端口绑定->监听->等待数据接收。
void tcp_echoserver_init(void)
{
/* create new tcp pcb */
tcp_echoserver_pcb = tcp_new();
if (tcp_echoserver_pcb != NULL)
{
err_t err;
/* bind echo_pcb to port 7 (ECHO protocol) */
err = tcp_bind(tcp_echoserver_pcb, IP_ADDR_ANY, 7);
if (err == ERR_OK)
{
/* start tcp listening for echo_pcb */
tcp_echoserver_pcb = tcp_listen(tcp_echoserver_pcb);
/* initialize LwIP tcp_accept callback function */
tcp_accept(tcp_echoserver_pcb, tcp_echoserver_accept);
}
else
{
/* deallocate the pcb */
memp_free(MEMP_TCP_PCB, tcp_echoserver_pcb);
}
}
}
2. ethernetif.c中的文件接口,(以下还含有ethernet.c中的函数接口)
主要实现网卡驱动
- low_level_init
该函数实现了硬件网卡设备的初始化,通过调用HAL_ETH_Init(&EthHandle),实现了功能(mac addr,rx mode,speed,media interface(MII)等)和端口(通过调用HAL_ETH_MspInit(heth)实现,当然这个接口需要用户提供,用于初始化与网卡间的GPIO)的初始化
- err_t ethernetif_init(struct netif *netif)
调用low_level_init实现网卡的基本功能初始化,并初始化struct netif部分功能,如netif->output = etharp_output和netif->linkoutput = low_level_output,以及网卡名。
- static struct pbuf * low_level_input(struct netif *netif)
实现将底层收到的数据以链表的形式存放到struct pbuf接口中,返回链表的首地址。 后续需要研究HAL_ETH_GetReceivedFrame(&EthHandle)接收实现。
- void ethernetif_input(struct netif *netif)
该函数调用low_level_input,将收到的底层数据,通过err = netif->input(p, netif); 发送到lwip协议栈中。其中netif->input函数既是 err_t ethernet_input(struct pbuf *p, struct netif *netif);是通过netif_add(&gnetif, &ipaddr, &netmask, &gw, NULL, ðernetif_init, ðernet_input);注册的。
- static err_t low_level_output(struct netif *netif, struct pbuf *p)
该函数通过调用HAL_ETH_TransmitFrame(&EthHandle, framelength);函数将pbuf的数据发送出去。
- err_t ethernet_output(struct netif* netif, struct pbuf* p,const struct eth_addr* src, const struct eth_addr* dst,u16_t eth_type)
该函数通过调用low_level_output函数将pbuf中的数据发送出去,该函数是lwip协议栈底层发送数据的出口。看程序主要被etharp调用,后续需要细看。