搜索
bottom↓
回复: 4

RT-Thread中对lwip初始化的一个bug

[复制链接]

出0入0汤圆

发表于 2013-1-11 17:49:30 | 显示全部楼层 |阅读模式
所用硬件平台: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[0][0], 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[0][0], ETH_TXBUFNB);
  /* Initialize Rx Descriptors list: Chain Mode  */
  ETH_DMARxDescChainInit(DMARxDscrTab, &Rx_Buff[0][0], ETH_RXBUFNB);
先初始化一下DMATxDescToSet,当然在rt_stm32_eth_init();中,MAC初始化后还要重新调用
/* Initialize Tx Descriptors list: Chain Mode */
  ETH_DMATxDescChainInit(DMATxDscrTab, &Tx_Buff[0][0], ETH_TXBUFNB);
  /* Initialize Rx Descriptors list: Chain Mode  */
  ETH_DMARxDescChainInit(DMARxDscrTab, &Rx_Buff[0][0], ETH_RXBUFNB);
进行初始化
当然这是最笨的方法

希望有高手来解决这些问题!


阿莫论坛20周年了!感谢大家的支持与爱护!!

曾经有一段真挚的爱情摆在我的面前,我没有珍惜,现在想起来,还好我没有珍惜……

出0入0汤圆

发表于 2013-1-11 20:54:47 | 显示全部楼层
关注RT-Thread,关注Lwip,关注RT-Thread中的Lwip。
坐等高手现身。

出0入0汤圆

发表于 2013-1-12 11:45:07 | 显示全部楼层
rt_device_init_all会慢慢不再使用。
实际项目中需要再加上插拔中断,以及PHY的复位。
所以不会发生一启用就收到了接收中断的现象。

出0入0汤圆

 楼主| 发表于 2013-1-12 15:53:10 | 显示全部楼层
aozima 发表于 2013-1-12 11:45
rt_device_init_all会慢慢不再使用。
实际项目中需要再加上插拔中断,以及PHY的复位。
所以不会发生一启用 ...


我只是在找一个合理的初始化流程

1、rt_device_init_all会慢慢不再使用
是不是在用新的设备(网络)初始化方法?

2、插拔中断已经加了,但是这跟初始化的bug没关系的

3、PHY复位也有的,也是在rt_device_init_all中调用设备的init中进行的
但是我觉得这都不能解决上面的问题

4、“加上插拔中断,以及PHY的复位。不会发生一启用就收到了接收中断的现象"
能否说明一下怎么加?在什么地方加?插拔中断和PHY复位,不会发生一启用就收到了接收中断的现象?

出0入0汤圆

发表于 2013-1-15 17:11:21 | 显示全部楼层
合理的初始化流程就是把:rt_device_init_all()函数拿掉。

这个函数实际上早就没有用了,只是为了兼容的原因所以存在。
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片。注意:要连续压缩2次才能满足要求!!】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-8-25 21:20

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表