【2】嵌入式TCP/IP协议——————LWIP无系统移植

  1. 简述
    1. 下载两个文件:lwip-1.4.1 ,contrib-1.4.1
    2. 文件下载地址:http://download-mirror.savannah.gnu.org/releases/lwip/
    3. 没有用MQTT等例程,暂时参照原子教程移植,后续如果用到应用方面再移植lwip2.1.2版本
  2. 说明
    1. LWIP内核中有许多的周期性定时器,如TCP定时器、ARP定时器、DHCP定时器
    2. 将上述定时器封装在一个函数里面,然后周期性调用这个函数
    3. LWIP协议栈要求每250ms处理一次TCP定时器,5S处理一次ARP定时器,500ms处理一次DHCP精细处理,60处理一次DHCP的粗糙处理
    4. 根据上述要求编写lwip_periodic_handle()函数,可以完成对lwip内核的定时处理函数的周期性调用
    5. LWIP的时基由定时器产生,10ms
  3. 移植步骤
    1. 添加网卡驱动stm32f7xx_hal_eth.c
    2. 添加LAN8720驱动:复制原子工程目录里面的lan8720.c和lan8720.h文件
    3. 添加LWIP源文件
    4. 添加中间文件:cc.h、cpu.h、perf.h、sys_arch.h、sys_arch.c、ethernetif.c,这几个文件在contrib目录下,此处直接复制例程中的arch文件夹
    5. 添加LWIP通用文件:lwip_comm.c、lwip_comm.h、lwipopts.h,用于lwip网卡/内核初始化,申请/释放内存、设定IP地址等等,最后一个依据应用裁剪和配置LWIP文件
    6. 复制例程下的ethernetif.h文件到lwip/src/include/netif目录
    7. LWIP源码修改
    8. 替换lwip/lwip1.4.1/src/netif目录下的ethernetif.c文件
    9. 修改mem.c文件
      1. 注释掉ram_heap数组
      2. 定义为指向u8_t的指针
    10. 修改memp.c文件
      1. 注释掉memp_memory数组
      2. 定义为指向u8_t的指针
      3. 添加如下源码
        //得到memp_memory数组大小
        u32_t memp_get_memorysize(void)
        {
        	u32_t length=0;
        	length=(
        			MEM_ALIGNMENT-1 //全局型数组 为所有POOL分配的内存空间
        			//MEMP_SIZE表示需要在每个POOL头部预留的空间  MEMP_SIZE = 0
        			#define LWIP_MEMPOOL(name,num,size,desc)+((num)*(MEMP_SIZE+MEMP_ALIGN_SIZE(size)))
        			#include "lwip/memp_std.h"
        			);
        	return length;
        }

         

      4. lwip动态内存管理技术,有一个内存堆ram_heap和内存池memp_memory,lwip的内存来源
    11. lwip裁剪与配置
      1. 协议栈自带的opt.h文件(内部是条件编译)
      2. 自建一个配置文件lwipopts.h
  4. lan8720.c文件详解:
    1. u8 LAN8720_Init(void);   PHY芯片初始化
    2. HAL_ETH_MspInit(); 以太网底层驱动、时钟、引脚配置
    3. u32 LAN8720_ReadPHY(u16 reg);  读取LAN8720指令寄存器
    4. void LAN8720_WritePHY(u16 reg,u16 value); 向LAN8720指令寄存器写入指定值
    5. u8 LAN8720_Get_Speed(void); 获取当前连接速度和双工状态
    6. u8 ETH_MACDMA_Config(void); 以太网DMA接收中断服务函数
    7. u8 ETH_Mem_Malloc(void); 获取接收到的帧长度
    8. void ETH_Mem_Free(void);   申请内存:Rx_Buff、Tx_Buff、DMARxDscrTab、DMATxDscrTab
    9. u32  ETH_GetRxPktSize(ETH_DMADescTypeDef *DMARxDesc); 释放内存 -----------------------------
  5. ethernetif.c文件详解
    1. low_level_init();
      1. 网卡的复位、协议栈网络接口管理结构体netif中相关字段的初始化、发送和接收DMA描述符链表的初始化,硬件帧校验的开启并且打开以太网
    2. low_level_output();
      1. 发送数据,将lwip协议栈准备好的数据通过网卡发送出去
    3. low_level_input();
      1. 从网卡中提取数据,并将数据封装在pbuf结构体供lwip使用
    4. ethernetif_input();
      1. 主要是对low_level_input()函数做封装,然后将接收到的数据送入指定的网卡结构中
    5. ethernetif_init(); 
      1. 为low_level_init(); 函数的简单封装,并且初始化了netif的相关字段
  6. 软件流程
    1. 外设初始化
    2. LWIP内核初始化
    3. DHCP获取IP地址
    4. 显示在LCD上
    5. 主循环中调用lwip_periodic_handle()函数
    6. 不管DHCP是否完成,都要周期性调用lwip_periodic_handle()函数,
    7. 这个函数是周期性调用协议栈内核的一些定时函数以满足LWIP内核要求
  7. 主函数例程
    1. /**************************************************
       * 函数名:main()
       * 描述  :主函数入口
       * 输入  :无
       * 输出  :无
       * 返回  :无 
       * 调用  :内部调用 
       **************************************************/
      int main(void)
      {	 
       	u16 i=0;	    
          
      	Cache_Enable();                 //打开L1-Cache
          HAL_Init();				        //初始化HAL库
          Stm32_Clock_Init(432,25,2,9);   //设置时钟,216Mhz 
          delay_init(216);                //延时初始化
      	uart_init(115200);		        //串口初始化
          BSP_LED_Init();                     //初始化LED
          BSP_KEY_Init();                     //初始化按键
          BSP_SDRAM_Init();                   //初始化SDRAM
          BSP_LCD_Init();                     //初始化LCD
          PCF8574_Init();                 //初始化PCF8574
          my_mem_init(SRAMIN);		    //初始化内部内存池
      //	my_mem_init(SRAMEX);		    //初始化外部内存池
      	my_mem_init(SRAMDTCM);		    //初始化DTCM内存池
          
          POINT_COLOR = RED; 		
      	BSP_LCD_ShowString(30,30,200,16,16,"Dreamer STM32F4/F7");
      	BSP_LCD_ShowString(30,50,200,16,16,"Ethernet lwIP est");
      	BSP_LCD_ShowString(30,70,200,16,16,"Dreamer Catcher");
      	BSP_LCD_ShowString(30,90,200,16,16,"2020/05/14");   
          TIM3_Init(1000-1,1080-1);       //定时器3初始化,定时器时钟为108M,分频系数为1080-1,
                                          //所以定时器3的频率为108M/1080=100K,自动重装载为1000-1,那么定时器周期就是10ms
      	while(lwip_comm_init())         //lwip初始化
      	{
      		BSP_LCD_ShowString(30,110,200,20,16,"LWIP Init Falied! ");
      		delay_ms(500);
      		BSP_LCD_ShowString(30,110,200,16,16,"Retrying...       ");
              delay_ms(500);
      	}
      	BSP_LCD_ShowString(30,110,200,20,16,"LWIP Init Success!");
       	BSP_LCD_ShowString(30,130,200,16,16,"DHCP IP configing...");  //等待DHCP获取 
      #if LWIP_DHCP   //使用DHCP
      	while((lwipdev.dhcpstatus!=2)&&(lwipdev.dhcpstatus!=0XFF))//等待DHCP获取成功/超时溢出
      	{  
      		lwip_periodic_handle();	//LWIP内核需要定时处理的函数
      	}
      #endif
      	show_address(lwipdev.dhcpstatus);	//显示地址信息
      	while(1)
      	{
      		lwip_periodic_handle();	//LWIP内核需要定时处理的函数
              delay_us(200);
              i++;
              if(i==2000)
              {
                  i=0;
                  LED0_Toggle;
              }
      	}				
      }

       

  8. 下载验证
  9. 总结
    1. 注意, 和 DMARxDscrTab, DMATxDscrTab 一样, 如果使用 F7 芯片的话 Rx_Buff 和 Tx_Buff的内存也一定要放到 DTCM 中,否则的网络也会出问题的。
    2. 深入学习可参考《嵌入式网络那些事:LwIP协议深度剖析与实战演练》
  10. 参考资料:
    1. 正点原子《STM32F767开发指南(HAL库版)》
    2. 正点原子《STM32F767 LWIP手册》
    3. 野火《STM32 HAL库开发实战指南》
    4. 野火《LWIP应用开发实战指南》
    5. 官方源码
  11. 硬件平台:
    1. 正点原子阿波罗F767
  12. 软件平台:
    1. MDK5.2.5
  13. 库版本:
    1. TM32Cube_FW_F7_V1.4.0
  14. LWIP版本
    1. lwip-1.4.1
    2. contrib-1.4.1
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值