很久之前看过LwIP的一些内容,感觉好复杂。这次一个项目用到了网口,打算结合RT-Thread,移植一下LwIP。鉴于MDK中Compiler 5已经不再更新,此次移植直接基于Compiler 6。因为公司之前有一个很简单的UDP的协议,基本可以直接跑通的,要移植一个自己不太熟的协议栈,心里还是做了很多斗争的。
先确定技术路线吧。RT-Thread有官方移植好LwIP,但是公司现在还没有使用RT的那一套环境开发,一直以来用的是CubeMX。CubeMX里RT-Thread和LwIP能单独配置,但是不能生成驱动代码。那么只能用CubeMX,配置FreeRTOS和LwIP生成工程模板,供后面参考。
- 用CubeMX配置RT-Thead,并将RT-Thead跑通。此步非常简单。
- 在工程中添加LwIP。
- 将模板里的代码,并结合RT-Thread官方包里的arch内容,将工程编译通过。
- 将工程跑起来。
将工程跑起来,没那么容易。首先工程运行起来两三秒的时候就进入Hardfault。根据RT-Thread给出的LR寄存器的值,结合汇编代码找到导致Hardfault的大致位置。最后发现问题出在LwIP的以下代码处:
/* Copy struct ip4_addr_wordaligned to aligned ip4_addr, to support compilers without
* structure packing (not using structure copy which breaks strict-aliasing rules). */
IPADDR_WORDALIGNED_COPY_TO_IP4_ADDR_T(&sipaddr, &hdr->sipaddr);
IPADDR_WORDALIGNED_COPY_TO_IP4_ADDR_T(&dipaddr, &hdr->dipaddr);
展开宏定义如下:
#define IPADDR_WORDALIGNED_COPY_TO_IP4_ADDR_T(dest, src) SMEMCPY(dest, src, sizeof(ip4_addr_t))
#define SMEMCPY(dst,src,len) memcpy(dst,(char*)src,len)
打眼一看,不能够啊,memcpy都能跑进Hardfault?调试进去,发现 &hdr->sipaddr的值不是4字节对齐,问题应该就是出现在这里。上网查资料,找到一篇不错的介绍非对齐访问的文章。内存类型分为Strongly-ordered,Device,Normal三种。其中Cortex M7只有Normal这种内存类型支持非对齐访问。查询上述地址,对上述地址设置MPU,将内存类型设置成Normal类型,再运行,没有进入HardFault了。
用网络调试助手给板子发消息,可以正常产生中断,也可以接收到数据,但是数据就是发不出来。用wireshark捕获,发现PC端一直是发的arp数据包,没有接收到回复。自己检查heth和gnetif的内容,发现他们的mac地址并不一致。发现是由于初始化的时候,传给heth的mac地址是一个局部变量,改成全局变量就一致了。
测试网络还是不通,把网络的GPIO速率设置到HIGH以上,收发就可以了。此处的设置也是参考的ST的示例工程的设置。奈何用CubeMX自动生成的代码默认是LOW速率。
STM32H743的MPU确实是个大坑。