接上回书。' v& v& k! _. q9 b 上次介绍了使用stm32f407和phy芯片DP83848进行网络通信的硬件组成和注意事项。软件方面移植uC/OS-III过程中可能发生的问题。lwip的特点和组成,移植多线程lwip所需要处理的文件。下面就开始将uC/OS-III和lwip1.4.0揉在一起了。。。。真担心写不好。。。为了F429Discovery,拼了吧。 本文假设uC/OS-III已经移植到stm32f407上了,并且可以完成简单的任务。在移植的过程中将会修改已经移植好的uC/OS-III工程,同时参考st官网lwip单线程的例程。那么只需要修改下lwip相关的port文件就可以了。其中ethernetif.c文件基本不用修改(需要修改的地方是这次使用stm32F407的以太网接收中断,需要在NVIC中使能这个中断,并且在stm32f4xx_int.c文件中添加对中断的处理)。需要处理的文件有sys_arch.c/.h文件;main.c或者叫app.c文件;lwip文件,用于处理lwip的初始化(与单线程的lwip初始化稍有区别);lwipopts.h文件的修改;httpserver_conn.c文件。 ethernetif.c文件的修改。主要是添加stm32F407的以太网接收中断的配置,如果dp83848连接了F407的io,则可以在程序初始化时,根据dp83848状态寄存器的连接状态位来决定是否启用mac和phy的自动协商功能。等连接之后再重新初始化一下即可。8 |6 r( V! |+ T- ?0 A1 l% L 修改stm32f4xx_it.c。添加对两个中断的响应函数,一是以太网接收中断,判断接收到了数据就调用ethernet_input来处理,请中断标志退出。二是处理dp过来的中断,修改连接状态的标志变量。 lwip文件的修改。可以参照官网lwip例程来修改,将初始化函数中的lwip_init用tcpip_init(NULL,NULL)来代替,将netif_add(&main_net, &ipaddr, &netmask, &gw, NULL, ðernetif_init, ðernetif_input);最后一个参数用LWIP的api函数tcpip_input来代替。即netif_add(&main_net, &ipaddr, &netmask, &gw, NULL, ðernetif_init, &tcpip_input); main.c或者叫app.c文件。修改appstarttask,添加刚刚修改的lwip的初始化函数。添加http_server_netconn_init();初始化http处理线程(这个函数在httpserver_conn.c函数中)。然后删除任务,或者循环delay,你懂的。5 \# p/ M& |' s e$ s8 Z 最后修改sys_arch.c/.h。先修改sys_arch.h文件,添加在lwip中对信号量和邮箱的定义。接着是修改sys_arch.c文件,具体内容为: 1.信号量的封装。主要是对sys_sem_new(),sys_arch_sem_wait(),sys_sem_signal(),sys_sem_free(),sys_sem_valid(),sys_sem_set_invalid()。通过对uCOS的信号量进行简单封装就可以了,成功返回0,失败返回-1,超时返回SYS_ARCH_TIMEOUT。这里不再详述。 2.互斥对象的实现。这个并不是很重要,可以简单的用信号量函数代替,也可以用uCOS的互斥对象实现。如果用信号量函数代替,需要定义宏LWIP_COMPAT_MUTEX。 3.消息邮箱的封装。sys_mbox_new(),sys_mbox_free(),sys_mbox_post(),sys_mbox_trypost()相对比较简单,sys_mbox_free的实现需要在删除邮箱之前,用OSQFlush清空消息队列的内容。sys_mbox_post和sys_mbox_trypost的区别是post的次数,一个是尝试发送一次,一个是尝试发送十次左右。 3 I/ p' H! e- Q. y Y, Z9 s4.sys_arch_mbox_fetch的实现,这是一个比较重要的函数,用来阻塞一个线程,知道接收到消息。阻塞的时间视参数timeout而定,返回超时的时间。所以这个函数就是对 OSQPend的简单封装,填充传入的消息指针,返回超时时间即可。 % p6 ]2 X+ c7 Q* R5.sys_arch_mbox_tryfetch的实现。根据lwip作者的解释,This is similar to sys_arch_mbox_fetch, however if a message is not present in the mailbox, it immediately returns with the code. To allow for efficient implementations, this can be defined as a 5 n2 X' G# q4 U; B& V4 i$ k) B6 g0 S function-like macro in sys_arch.h instead of a normal function. For example, a naive implementation could be: # T/ H+ ?7 D, k8 Z! e$ e #define sys_arch_mbox_tryfetch(mbox,msg) \ " a6 Z: l4 @0 D; F9 l& V sys_arch_mbox_fetch(mbox,msg,1) * G. x) I c) O' s; {) F, v although this would introduce unnecessary delays. " H4 i4 _# J$ Q3 |就这样一个宏kill了一个函数。 6.sys_init() 这个函数用来实现分配LWIP的任务栈空间。 7.sys_thread_new()。这个函数是帮助LWIP创建线程的。对uCOS来说就是任务的创建。创建的时候要判断是否已经超过了LWIP的最大任务数。 8.sys_arch_protect和sys_arch_unprotect是为了帮助lwip进出关键代码区,用来开关中断的。直接返回即可。 % A$ ~8 [( a" {1 A8 M4 u, z lwipopts.h文件的修改。lwipopts.h文件要改的首先要修改 #define NO_SYS 0,告诉lwip要使用信号量和线程了。定义与创建邮箱相关的宏,TCPIP_MBOX_SIZE和DEFAULT_TCP_RECVMBOX_SIZE,DEFAULT_RAW_RECVMBOX_SIZE。在默认定义下这两个是0,会导致信号量创建失败,大小视实际情况而定。 ( o3 N# Y, \( l( o8 T+ Ghttpserver-netconn.c的移植主要是实现创建http的线程,在线程中根据HTTP的请求做出相应的响应,返回响应的网页或者图片或者对板子的指令等,具体为修改http_server_serve函数,根据http的请求行作出相应的处理。 5 |5 I4 c$ E+ c 如果要用DHCP,软件上,需要在lwipopts.h文件中定义LWIP_DHCP和USE_DHCP,在初始化的时候把ip地址,掩码和网关地址全部设为0,硬件上需要连接一个带DHCP服务器的网络。 5 ?0 ^, I" C/ c* ?* W: U% }针对LWIP1.4.0,需要处理一下icmp.c文件,内容如下: ' j& G) v9 N4 w0 E#if CHECKSUM_GEN_ICMP' i" c( t! a2 n 7 `6 t+ t' ~, _) e' n! j& Z/* adjust the checksum */ if (iecho->chksum >= PP_HTONS(0xffffU - (ICMP_ECHO chksum += PP_HTONS(ICMP_ECHO chksum += PP_HTONS(ICMP_ECHO chksum = 0;, p b1 ~/ x6 C3 p #endif 并且在lwipopts.h中定义CHECKSUM_GEN_ICMP为0 再添一句,MAC地址不可以随意设置,特别是在使用DHCP的情况下。MAC的前三个字节是OUI,OUI是“组织唯一标示符”(和USB的VID相似,提供网卡或是设备供应商的ID),签发给各类组织的唯一标识符,后三个字节由供应商自己支配,和PID相似。其中MAC的第48bit(即MAC_ADDR0的最低位)是单播/组播位,如果为0表示这是一个单播地址,如果为1表示这是一个组播地址,网卡的MAC地址是单播的,因此需要将这一位设置为0,即MAC_ADDR0必须为偶数,否则,无法获得动态IP地址。 u2 r4 f' {2 i- e4 B v( c# {最后再说一下,调试的问题。对于有192KB SRAM的F407VG来说,我一直用的是ram调试。但这次的网页data比较大,所以想到了F407的CCM,这个模块只通过D-Bus和内核连接。所以DMA和外设是无法访问的,这样的设计一来会提高芯片的性能,二来不会被非法访问破坏数据。存放RW数据还是可以的(代码是肯定不行的,会进硬fault,但是在F3里是可以的),改了一下sct文件,发现可以用。如果以后遇到频繁处理的数据或者堆栈什么的可以放在这个内存区了,64KB 不用太可惜了。呵呵7 d# q1 P; l3 e- V P * \0 Z. }- x$ t1 e9 k . U0 a3 z2 J4 Y/ E7 `8 r$ c; [) O 剩下的就是一堆未定义,重复定义,头文件找不到等等问题了,应该难不倒各位。先写这么多了,相关的附件都贴在上一篇了,各位移步吧。 如果你已经移植好了,不妨考虑一下,用它玩点什么东西,比如这个。。。 ) c0 @6 L! M0 ^0 q6 z还是最后一句,求板子F429Discovery * p' J: X. F( m7 r0 v |
RE:【MCU实战经验】+stm32f4 + uCOS-III(V3.0.3) + LWIP(V1.4.0) 续
回复:【MCU实战经验】+stm32f4 + uCOS-III(V3.0.3) + LWIP(V1.4.0) 续
RE:【MCU实战经验】+stm32f4 + uCOS-III(V3.0.3) + LWIP(V1.4.0) 续
RE:【MCU实战经验】+stm32f4 + uCOS-III(V3.0.3) + LWIP(V1.4.0) 续
RE:【MCU实战经验】+stm32f4 + uCOS-III(V3.0.3) + LWIP(V1.4.0) 续
RE:【MCU实战经验】+stm32f4 + uCOS-III(V3.0.3) + LWIP(V1.4.0) 续
你是用杜邦线么?我的是10cm的杜邦线,有时候也会丢包。一直ping试下,命令ping -t ip地址。ping的时候动动杜邦线,看能不能ping通,我的情况是有时候接触不良。如果还不行,就用示波器看下各个杜邦线上的信号有没有失真,失真是不是太过分了。
不知道具体情况现在如何?有问题再讨论。
回复:【MCU实战经验】+stm32f4 + uCOS-III(V3.0.3) + LWIP(V1.4.0) 续
RE:【MCU实战经验】+stm32f4 + uCOS-III(V3.0.3) + LWIP(V1.4.0) 续
RE:【MCU实战经验】+stm32f4 + uCOS-III(V3.0.3) + LWIP(V1.4.0) 续