RT-Thread中对lwip初始化的一个bug
所用硬件平台:STM32F107VCT6 + DP83848i 和 STM32F407VET6 + KSZ8041NL编译器:IAR6.10& IAR6.40
RT-Thread版本为:RT-Thread1.1.0正式版
在初始化lwip时,发现了一个很大的问题
1、在N多例程里一直采用的是:
/* LwIP Initialization */
#ifdef RT_USING_LWIP
{
extern void lwip_sys_init(void);
/* register ethernetif device */
eth_system_device_init();
rt_hw_stm32_eth_init();
/* re-init device driver */
rt_device_init_all();
/* init lwip system */
lwip_sys_init();
}
#endif
也一直没出现问题,当在STM32F407VET6偶尔会出现硬件错误,发现以下地方ethernetif.c的eth_rx_thread_entry函数中
/* notify to upper layer */
if( device->netif->input(p, device->netif) != ERR_OK )
这时PC指针为0x00000000进入硬件错误
原因为,rt_device_init_all();执行完已经打开了网络MAC接收中断,而此时lwip_sys_init()还未执行完,底层收到了数据包要往上传,但是此处device->netif->input函数指针还未初始化,其初始化在sys_arch.c中的netif_add()函数中,是调用lwip_sys_init()执行的
这个错误只在407VET6上面发现过,而且有概率出现,本人同时启动12快板子在同一个网络内,基本每次都会出现1~3块板子出错,很小几率全部正常工作
2、自然而然想到,改变初始化顺序为:
/* LwIP Initialization */
#ifdef RT_USING_LWIP
{
extern void lwip_sys_init(void);
/* register ethernetif device */
eth_system_device_init();
rt_hw_stm32_eth_init();
/* init lwip system */
lwip_sys_init();
/* re-init device driver */
rt_device_init_all();
}
#endif
此时还会进入硬件错误,原因为:
在执行函数lwip_sys_init();过程中,在sys_arch.c中的tcpip_init_done_callback函数会调用netif_set_link_up(ethif->netif);从而激活
ethernetif.c中的ethernetif_linkoutput函数,向eth_tx_thread_mb邮箱发送数据使得eth_tx_thread_entry任务去调用if (enetif->eth_tx(&(enetif->parent), msg->buf) != RT_EOK)
进入MAC层发送函数rt_stm32_eth_tx();
而此时DMATxDescToSet还未进行初始化,其指针为0x00000000
在进行
/* Copy the frame to be sent into memory pointed by the current ETHERNET DMA Tx descriptor */
to = (uint8_t*)((DMATxDescToSet->Buffer1Addr) + offset);
memcpy(to, q->payload, q->len);
时,对内存非法操作进入硬件错误
DMATxDescToSet的初始化是在rt_device_init_all();中调用网络设备的初始化函数rt_stm32_eth_init();完成PHY配置后进行了
/* Initialize Tx Descriptors list: Chain Mode */
ETH_DMATxDescChainInit(DMATxDscrTab, &Tx_Buff, ETH_TXBUFNB);
才得以初始化
3、同样在RealTouch中用到了components.c文件,将lwip的初始化进行了分割:
在applicatio.c中初始化
/* initialize eth interface */
rt_hw_stm32_eth_init();
然后调用rt_components_init();函数,在components.c中初始化
/* register ethernetif device */
eth_system_device_init();
/* initialize lwip system */
lwip_system_init();
最后调用rt_platform_init();函数在platform.c文件中调用
rt_device_init_all();
应该就是初始所有注册的devices,包括网络MAC初始化在内
这种方同上面第二种方法一样的,都会出现同样的错误:DMATxDescToSet初始化前就使用
4、最关键的一点,也是最具有戏剧性的一点:2、3种方法在STM32F407系列上不会进入硬件错误,而在STM32F107上会进入硬件错误
以上几种方法都是在硬件平台上测试过的。
本人也是在407系列上修改后用第二种方法,可以正常工作,转而移植107系列的,发现了上面的问题
在407系列上当DMATxDescToSet=0x00000000时,进行下面操作
/* Copy the frame to be sent into memory pointed by the current ETHERNET DMA Tx descriptor */
to = (uint8_t*)((DMATxDescToSet->Buffer1Addr) + offset);
memcpy(to, q->payload, q->len);
可以得到to = 0x08xx具体记不清了,后面看能不能在编辑进来
不知为什么在执行memcpy(to, q->payload, q->len);不会进入硬件错误,而107系列会进入硬件错误
5、关于RT-Thread1.1.0正式版发布公告中有句话:“网络接口可以再 LwIP 初始化以后再进行初始化”
不知应该怎样理解。
6、关于2、3中方法,可以在rt_hw_stm32_eth_init();函数最后调用
/* Initialize Tx Descriptors list: Chain Mode */
ETH_DMATxDescChainInit(DMATxDscrTab, &Tx_Buff, ETH_TXBUFNB);
/* Initialize Rx Descriptors list: Chain Mode*/
ETH_DMARxDescChainInit(DMARxDscrTab, &Rx_Buff, ETH_RXBUFNB);
先初始化一下DMATxDescToSet,当然在rt_stm32_eth_init();中,MAC初始化后还要重新调用
/* Initialize Tx Descriptors list: Chain Mode */
ETH_DMATxDescChainInit(DMATxDscrTab, &Tx_Buff, ETH_TXBUFNB);
/* Initialize Rx Descriptors list: Chain Mode*/
ETH_DMARxDescChainInit(DMARxDscrTab, &Rx_Buff, ETH_RXBUFNB);
进行初始化
当然这是最笨的方法
希望有高手来解决这些问题!
关注RT-Thread,关注Lwip,关注RT-Thread中的Lwip。
坐等高手现身。 rt_device_init_all会慢慢不再使用。
实际项目中需要再加上插拔中断,以及PHY的复位。
所以不会发生一启用就收到了接收中断的现象。 aozima 发表于 2013-1-12 11:45 static/image/common/back.gif
rt_device_init_all会慢慢不再使用。
实际项目中需要再加上插拔中断,以及PHY的复位。
所以不会发生一启用 ...
我只是在找一个合理的初始化流程
1、rt_device_init_all会慢慢不再使用
是不是在用新的设备(网络)初始化方法?
2、插拔中断已经加了,但是这跟初始化的bug没关系的
3、PHY复位也有的,也是在rt_device_init_all中调用设备的init中进行的
但是我觉得这都不能解决上面的问题
4、“加上插拔中断,以及PHY的复位。不会发生一启用就收到了接收中断的现象"
能否说明一下怎么加?在什么地方加?插拔中断和PHY复位,不会发生一启用就收到了接收中断的现象? 合理的初始化流程就是把:rt_device_init_all()函数拿掉。
这个函数实际上早就没有用了,只是为了兼容的原因所以存在。
页:
[1]