智手移动中文网's Archiver

sunmoon 发表于 2006-3-26 20:36

初学ucos_ii263

初学ucos_ii263心得
经过几天的摸索,终于调试成功了。我想说几点经验,供参考。
1.我曾想用TC2.0编译,不行,TC不认识其中的汇编语句,BC45与TC20插入汇编语句格式不同。
2.因以前用惯VC60,想用它编译,不行,象FAR、MKFP()等关键词它不认。
3.BC45安装后,在BIN目录下少TASM.EXE,不能对os_cpu_a.asm文件编译,链接不到os_cpu_a.obj。
4.TASM.EXE或MASM.EXE要高版本的(126KB),我曾用TC20下的(20.5KB),不行,而且没有出错信息,就是不出*.obj。
5.使用BC45,也出过错。下面说BC45下的一种做法:
  1)先要新建一个Object文件(*.ide),类型为(.exe, DOS,Large);
  2)加入例子中用到的*.h,*.c,*.asm文件,但要去掉ucos_ii.c,否则重复定义,出错,看其内容就会知道了;
  3)为找#include "os_cpu.h"等,在Option->Project->Source Director中设置*.h的路径,以;号分隔;
  4)同样,配置Source,Output等路径;
  5)编译compile,链接生成make, 运行*.exe文件。
6.根据上面第5.点,你可以配置你的ucos_ii,不必局限原来ucos_ii262的目录结构。我嫌它太散,我只分Source和Work目录。
7.BC45对ucos实例并不能单步执行、调试。
8.例Test3.c中,改os_cfg.h中OS_CPU_HOOKS_EN 为0,因Test3.c中重新定义了钩子函数。
9.例Test4.c中,改用它指定的os_cpu_c.c,因用浮点数命令。
10.在贵网站上下了许多程序。有高版本的ucos28支持VC6。

sunmoon 发表于 2006-3-26 20:38

lwIP(TCP/IP)协议栈移植(不包括网卡驱动)

一、lwIP 概述

lwIP是瑞士计算机科学院(Swedish Institute of Computer Science)的Adam Dunkels等开发的一套用于嵌入式系统的开放源代码TCP/IP协议栈。Lwip既可以移植到操作系统上,又可以在无操作系统的情况下独立运行.                           





LwIP的特性如下:

(1)    支持多网络接口下的IP转发

(2)    支持ICMP协议

(3)    包括实验性扩展的的UDP(用户数据报协议)

(4)    包括阻塞控制,RTT估算和快速恢复和快速转发的TCP(传输控制协议)

(5)    提供专门的内部回调接口(Raw API)用于提高应用程序性能

(6)    可选择的Berkeley接口API(多线程情况下)

(7)    在最新的版本中支持ppp

(8)    新版本中增加了的IP fragment的支持.

(9)    支持DHCP协议,动态分配ip地址.

以上内容摘自网络 关于ucos 上的lwip移植





二、移植介绍

       整个移植过程主要参考网络上关于移植到ucos 的说明和源码。

1.  目录及文件介绍

原版的lwIP1.1.0包含两个目录src 和 doc

移植后增加如下文件和目录

[Arch]

        Lib_arch.c本系统没用,系统中没有实现的C库函数可以写到这里

        Sys_arch.c 移植的主要工作在这里,关于信号量、消息队列、任务创建

        [RX4000] 项目目录

               [Include]

                      [Arch]

                                    cc.h 类型定义 大小端设置 PACK定义等

                                    init.h

                                    lib.h 跟Lib_arch.c对应 函数声明

                                    perf.h 没用

                                    sys_arch.h 跟Sys_arch.c对应的一些类型定义和宏定义

                      [Netif]

                                    Dm9000a.h

                                    Ne2kif.h

               [Netif]

                      Dm_netif.c 网卡驱动与系统关联的抽象层

                      Dm9000a.c网卡的硬件操作函数

                      Ne2kif.c 没用

[Init]

        Lwip.c 协议栈初始化和DHCP初始化

        Lwipopts.h 协议栈相关参数设置

[Dns]

        Dns.c 增加域名解析函数 gethostbyname (非可重入函数)

        Dns.h

2.  移植相关函数介绍

1)      sys_init

这个很简单,就是一些全局量的初始化

2)      sys_thread_new sys_arch_timeouts

相关的三个全局变量如下

struct sys_timeouts lwip_timeouts[LWIP_TASK_MAX];

为每一个由sys_thread_new创建的任务分配一个存放信号量超时信息的列表

struct sys_timeouts null_timeouts;

为一个超过任务上限数的任务和不是由sys_thread_new创建的任务取超时列表时返回使用。

MMAC_RTOS_TASK_ID LWIP_TASKS[LWIP_TASK_MAX];

任务id存放顺序与lwip_timeouts相对应

sys_thread_new用来创建一个新的任务,保存任务ID。sys_arch_timeouts

就是通过取得任务ID返回任务对应的timeouts结构,从而可以添加、删除和判断超时的功能

3)      sys_sem_new sys_sem_free  sys_sem_signal sys_arch_sem_wait

sys_sem_new创建一个信号灯并初始化灯的数量返回sys_sem_t 类型的变量,定义是这样的typedef MMAC_RTOS_SEMAPHORE  *sys_sem_t; 由于返回失败要返回NULL值所以就定义了系统信号量的指针为抽象信号量类型。因此在sys_sem_new和 sys_sem_free 分别要进行内存申请和释放的工作。

       sys_sem_signal释放一个灯,sys_arch_sem_wait 等待信号,其中参数timeout是以ms为单位的,若wei零则表示永远等待一直到信号的来临。

       在这个信号系统中本人还存在一个疑问,具体在5”存在的问题”中进行说明

4)      sys_mbox_new sys_mbox_free sys_mbox_post sys_arch_mbox_fetch

同上原因在类型的定义成指针的。那sys_mbox_new 和sys_mbox_free同样要进行内存的申请和释放。在系统中消息队列发送和接收的都是指向数据的指针,因为在发送前所有的数据都已经存放在一个全局的用来管理内存的变量中。所以发送的内容就是四个字节。发送是还要判断发送msg是否为NULL。因为发送的是msg的指针,而不是内容还要取一下地址,NULL明显不能取址,所以有一个专门的static int *msg_null=NULL (这里的=NULL 并不重要可以使任何值 * 也可以不要,因为要的是变量的地址在内存中的唯一性)用来发送“NULL”信息,使msg = &msg_null再发送。接收到后也要进行 *msg ==&msg_null的判断。接收时也要进行msg NULL的判断,若msg为NULL就需要零时申请一个空间进行接收。还要注意发送和接收时msg的类型,发送是void* 的 ,接收是void **,要做好相应的处理。

3.  移植中相关配置的介绍

1)      SYS_LIGHTWEIGHT_PROT

我的理解应该是是否使用系统临界区变量,由于本系统没有单独的临界区变量,所以就设置成 0 ,那就用信号灯来完成该任务。且sys_arch.h中的最后三个宏也要定义成空。

2)      累加和

关闭所有的累加检查,因为硬件已有该功能了

#define CHECKSUM_GEN_IP                 0

#define CHECKSUM_GEN_UDP                0

#define CHECKSUM_GEN_TCP                0

#define CHECKSUM_CHECK_IP               0

#define CHECKSUM_CHECK_UDP              0

#define CHECKSUM_CHECK_TCP              0

3)      LWIP_HAVE_LOOPIF

是否开启回环,在还没有网卡驱动的时候,可以设置为 1 添加loop设备进行调试运行。

4)      内存分配设定

在协议栈中很多内存都是事先申请的,有协议栈自己进行管理。据我了解有三大块内存PBUF MEMP MEM。在lwipopts.h中的Memory options中定义了各块内存的种类及各种类的数量。这部分的设置要仔细斟酌。具体就不再详述了。

5)      TCP_SND_BUF

该设置对网络传输的速度由很大的影响。Ucos+lwIP的源码中的默认设置是256,用socket进行速度测试时却只有区区的1KB/S左右的速度。最后改成8192后速度达到 600KB/S。

6)      LWIP_DHCP  

本系统需要DHCP支持因此需要设置为 1。在他下面有一个DHCP_DOES_ARP_CHECK的宏设置为 0。 开启后出现错误。原因不明。

4.  移植中碰到的问题总结

1)  同时支持UDP及TCP及DHCP的支持

不再详述看出始化代码

void Task_lwip_init(void * pParam)

{

  struct ip_addr ipaddr, netmask, gw;

  sys_sem_t sem;

  err_t result ;

  int icount = 0;

  int idhcpre=0;

  

  #if LWIP_STATS

  stats_init();

  #endif

  // initial lwIP stack

  sys_init();

  mem_init();

  memp_init();

  pbuf_init();

  netif_init();





  printf("LWIP:TCP/IP initializing...\n");  

  sem = sys_sem_new(0);

  tcpip_init(tcpip_init_done_ok, &sem);

  sys_sem_wait(sem);

  sys_sem_free(sem);

  printf("LWIP:TCP/IP initialized.\n");





   /*

  //add loop interface //set local loop-interface 127.0.0.1

  IP4_ADDR(&gw, 127,0,0,1);

  IP4_ADDR(&ipaddr, 127,0,0,1);

  IP4_ADDR(&netmask, 255,0,0,0);

  netif_add(&loop_if, &ipaddr, &netmask, &gw, NULL, loopif_init, tcpip_input);



  netif_set_default(&loop_if);

  netif_set_up(&loop_if);

  //*/

#if 0   

  IP4_ADDR(&gw, 192,168,0,2);

  IP4_ADDR(&ipaddr, 192,168,0,186);

  IP4_ADDR(&netmask, 255,255,255,0);

  netif_add(&dm9if_if, &ipaddr, &netmask, &gw, NULL, dm9_netif_init, tcpip_input);

  netif_set_default(&dm9if_if);

  netif_set_up(&dm9if_if);

#else

  IP4_ADDR(&gw, 0,0,0,0);

  IP4_ADDR(&ipaddr, 0,0,0,0);

  IP4_ADDR(&netmask, 0,0,0,0);

  netif_add(&dm9if_if, &ipaddr, &netmask, &gw, NULL, dm9_netif_init, udp_input);//添加udp支持

  printf("LWIP:waiting for neif init \n");

  MMAC_RTOS_Sleep( 3500);





  for(idhcpre = 0; idhcpre<4;  idhcpre++ )//dhcp最多重试4遍

  {

      printf("LWIP:start dhcp request \n");

      result  = dhcp_start(&dm9if_if);//广播dhcp请求





      IP4_ADDR(&ipaddr, 0,0,0,0);

      for(icount = 0; (icount < 10) && (ipaddr.addr == 0); icount ++ )

      {

          ipaddr.addr = dm9if_if.ip_addr.addr;

            MMAC_RTOS_Sleep( 1000);

      } // if failed ipaddr = 0.0.0.0 ;timeout = 10 * 1000 ms

           //等待dhcp是否接受到IP了

      // add dns server ip

      dns_add(0,&dm9if_if.dhcp->offered_dns_addr[0]);

      dns_add(1,&dm9if_if.dhcp->offered_dns_addr[1]);

       //不需要dns的去掉上面两句

      dhcp_stop(&dm9if_if); //一次dhcp结束





      if (ipaddr.addr != 0)

          break;

  }

  

  gw.addr = dm9if_if.gw.addr;

  ipaddr.addr = dm9if_if.ip_addr.addr;

  netmask.addr = dm9if_if.netmask.addr;

  //netif_remove(&dm9if_if);

  netif_add(&dm9if_if_tcp, &ipaddr, &netmask, &gw, NULL, dm9_netif_init, tcpip_input);//添加tcp支持





  netif_set_up(&dm9if_if_tcp);

  netif_set_up(&dm9if_if);

  netif_set_default(&dm9if_if_tcp);





#endif

  sprintf(STRIPADDR,"%d.%d.%d.%d",ip4_addr1(&ipaddr), ip4_addr2(&ipaddr),ip4_addr3(&ipaddr),ip4_addr4(&ipaddr));

  printf("LWIP:IPADDR = %s\n",STRIPADDR);









  if (ipaddr.addr != 0)

  {

  //------------------------------------------------------------

  //

  

  // http thread, a web page can be browsed

// sys_thread_new(httpd_init, (void*)"httpd",TCPIP_THREAD_PRIO);

  

  //------------------------------------------------------------

      sys_thread_new(test_net, NULL, TCPIP_THREAD_PRIO);

  }

  /* Block for ever. */

  sem = sys_sem_new(0);

  sys_sem_wait(sem);

}

2)对齐问题

PBUF_LINK_HLEN 16

static u8_t ip_reassbitmap[MEM_ALIGN_SIZE(IP_REASS_BUFSIZE / (8 * 8))];

在调试的时候经常碰到内存访问错误的异常,最后查得原因是内存的起始地址不再4的倍数上,导致不能访问。因为内存申请时有字节数来的,有时要强制转换为某种结构。为了保证地址不错,PBUF_LINK_HLEN 定义为16,ip_reassbitmap的大小也变成4的倍数。因为它的大小不是4的倍数,就导致附近的内存分配起始不是4的倍数。这个解决办法由点不好,但是没有办法,我用 align 等声明没有作用。

3)大包ping问题

原因是以太网络中,最大允许的包大小为1514字节,若用pc机ping

页: [1]

Powered by Discuz! Archiver 6.1.0  © 2001-2007 Comsenz Inc.