凌阳科技大学计划论坛

首页 » eCos技术讨论专区 » 新手玩eCos » 快快乐乐学eCos
lameck - 2008-4-12 10:53:00
最近在学eCos,刚开始还不太熟,不过感觉还挻好玩的。

    以前看过一本学习嵌入式的书叫《快快乐乐跟我学嵌入式系统》,感觉写的很好,对我现在学习eCos有很大的帮助,在这里我也开一个“快快乐乐学eCos”的房间,希望大家能够一起学习,并写下一些学习经验之类的东西,创造一下学习氛围。并为后来者能留下一些可参考的东东~~~

呵呵,开场白就不多说了,大家以后多多努力,好好学习~~~

昨天把那本书的绪言部分找到了,现在和大家分享一下:

引自:《快快乐乐跟我学嵌入式系统》

      众所周知,现代的嵌入式系统开发越来越复杂,性能要求越来越高,开发人员不能再满足于原来只专著于一点不顾其他的开发方式,原来的单打独斗也要改成现在的团队合作,可是面对浩如烟海的知识点,一个开发新手,如何才能尽快入门呢?如何才能在尽可能短的时间内做出象样的产品呢?《快快乐乐跟我学嵌入式系统》就是为这个目的写的。作为多年从事一线研发工作的过来人,自然有很多心得体会,我们希望能用自己的经验教训帮助初学者少走弯路。
   
    本书将涉猎嵌入式开发的常见“热点”,如:bootloader、TCP/IP协议栈、文件系统FS、USB协议、各种总线驱动等。没有空洞的语言,全部用实例说话,不求全面,但求实用,使你能轻轻松松,快快乐乐地入门。现在的用人单位都希望招聘到有工作经验的雇员,而工作经验却要在工作中才能获得,这是一个先有鸡还是先有蛋的二难困境问题,单靠劳资双方是无法解决的,本书的作用就在于使新手不必参加工作就能获得工作经验,进而获得进入公司的敲门砖,同时公司也能招聘到合适人选。
   
    初学者经常问到的问题是:“到底学习ARM7还是ARM9?到底学习ucos、Linux还是WinCE?”其实这些都不重要,最重要的是构造学习环境和学习氛围。不知大家是不是都有这样的体会:当你恰好有个项目和你所学有关或者有个高手带着你学,你就会进步神速!为什么呢?就是因为学习环境和学习氛围在潜移默化中熏陶了你,使你在不知不觉中功力大涨,获益良多。看过西班牙斗牛的人都会有印象,那只猛牛不断追逐斗牛士手中的红布,然而一次次扑空,我时常在想,如果那只牛能看到整幅图景,红布后面除了空气什么也没有,那它还会选择追逐那块红布吗!?同样的,ARM9、FPGA、Linux、DSP、模拟射频、芯片设计等时髦技术又何尝不是那块红布呢,我们不要做那只牛,千万别犯同样的错误。我们知道,使用同样的材料,大厨做出来的菜,色、香、味俱佳,而新手做的菜就难以下咽。同样的,我们有了开发板,有了源码,是不是就可以成为专家呢?答案是否定的,您还缺乏经验,还需要不断实践,最关键的是您还缺乏一个学习环境。这里所说的学习环境泛指技术指导,技术支持,文档和交流氛围。目前,网上开源代码越来越多,一些集成开发环境提供了丰富的范例代码,甚至一些厂商提供保姆式服务,但是,源码不等于软件,很多人落入陷阱,成了搬运工,收藏家,就是用不出来,究其原因,我认为是观念上的错误,以为有了和大厨一样的材料就能和大厨烧出一样好吃的菜,忘记了材料好坏只是表面现象,大厨的手艺才是决定性因素。因此,源码和高档开发板不是最重要的,最重要的是要有学习环境,包括详细的文档,交流氛围,有效的技术支持服务等。本书试图在源码和开发板之外提供一个开发环境,真正解决初学者的入门问题。
   
    那么,该如何学好嵌入式系统呢?这就涉及到学习方法了,好的方法能使你事半功倍,基本原则是:1、学习不变的;2、学习常用的;3、象婴儿那样学习。   
    --------------------------
    一、学习不变的
    --------------------------
    俗话说救火不如预防,很多人每天都很忙,疲于奔命到处救火,却不能抽出一点时间来想想如何预防火灾,忙碌是懒惰的表现---懒得动脑筋思考。事物分成四类,按优先处理次序排列为:重要且紧急;重要不紧急;不重要紧急;不重要不紧急。基本原则是做重要的事,不做不重要的,哪怕很紧急。很多人错就错在先处理紧急的事,到处救火,却忘了重要但不紧急的事---预防火灾。结果就是虽然整天忙碌,事却越干越多。学习嵌入式系统首先要抽象出系统本质,了解自己真正需要什么,磨刀不误砍柴工,做好这一步,后面可以节省大量时间,有效保护自己的前期投资,一劳永逸。例如: 一开始不要从具体的CPU架构和汇编语言学起,这些都是易变的内容,你换一种CPU就要从头学一次,不划算。要学就学那些不容易变化的内容:通用I/O驱动、万能中断处理机制、通用串口驱动、UNIX文件API接口、socket插口、POSIX标准等。当然初学者自己无法事先知道哪些内容是本质,这就要靠过来人总结经验了,本书总结了大量与硬件无关的内容,都是长期积累的经验之谈。建议初学者从上向下地学习嵌入式系统,先了解移植性强的应用程序,再深入到底层细节。   
    --------------------------
    二、学习常用的
    --------------------------
    什么样的知识才能记得牢呢?没错,常用的内容记得牢!有人作过统计,掌握最常用的100单词就能应付日常生活需要,掌握5000单词就能覆盖80%会话内容。因为常用,就会经常得到复习,想忘记也不容易,这样学起来就轻松了。现在的关键问题是如何找到最常用的部分,幸运的是,常用部分一般会反复出现。本书的一大特色是不求面面俱到,而是重点突出常用部分,举一反三。这么做能用最短的时间取得最好的效果,是一条捷径。常用的另一层意思是尽量遵循标准,如果一开始就接受不正规的训练,甚至比不接受训练更有害,一旦养成坏习惯就很难再改了。比如:我们使用UNIX文件系统构造开发平台就比用DOS文件系统经典。何谓经典,经典就是经过了长时间实践考验,BUG少,使用广泛。本书介绍的ecos操作系统就是由计算机专家设计的经典嵌入式系统,越深入细节越能体会到它无处不在的专业性,通过它来学习嵌入式系统,能让你从一开始就养成好习惯,学习到常用的知识点。根据二八定律,20%的知识点覆盖80%的内容,而其余80%的知识点只能得到20%的效果,那么只要我们学习常用的20%知识点就能取得显著成效。   
    ------------------------------
    三、象婴儿那样学习
    ------------------------------
    大脑的工作原理至今仍未搞清楚,为什么婴儿学习能力那么强到了成年反而衰退了?观察婴儿学习母语,就是多听---多模仿---多说,谁也没见过他们拿着字典和语法书学习母语,但是5-6年后基本就能自由表达自己的思想。反观很多成年人,学了十几年英语至今还是“聋子”、“哑巴”,书也未见得少买,为什么差距那么大?似乎人的大脑的最佳学习方法不是有意识地去学,而是多模仿多实践自然就会了。而且最好将以前的知识完全忘干净,象一张白纸一样,象婴儿那样学习。比如我的汉语很好,但我从没买过什么汉语四六级、走遍中国、疯狂汉语、新概念中文等书籍,也没参加过什么汉语培训班,因为我周围就是汉语环境,不知不觉中就能不断学习巩固。而我的英语书就买了不少,音视频资料也下载了很多,虽然英语水平还是老样子,但一看到攒了那么多书,刻了那么多光盘,心里就感到塌实安心,仿佛英语水平真的提高了,尽管大多数时候就是搬来搬去,掸掸土什么的。据我了解,一些初学者买了开发板也没时间用,束之高阁,到现在还是九成新,仅以别人有的我也有聊以自慰。想想也是,劳累了一天谁还有兴趣再埋头苦学呢。还有一些初学者成了收集狂,到处搜集各种技术资料,仿佛搜集得越全自己水平就能越高。印象中,我喜欢搜集整理各种英语资料,水平依旧;从未花太多时间在汉语上,却运用自如,而且越来越炉火纯青。可见,学习环境是多么重要,有了环境,通过多接触---多模仿---多实践,轻轻松松就能掌握嵌入式系统,根本不必专门去搜集各种资料。
   
    本书就是基于以上理念设计的,旨在为用户创造一个开发环境,让使用者在不知不觉中轻轻松松、快快乐乐地入门。不同于其他入门书籍,本书每章都以一个有趣的实验开始,一上来就要求动手操作,没有乏味的概念讲解,而且实验内容很有趣很实用。例如:讲文件系统的部分一开始就要求把一个文本文件写到SD卡里并读出,进而启发设计一个硬盘录像机,然后讲解文件系统概念和各种不同介质上的文件系统实现;在TCP/IP协议栈部分,要求先实验一个静态网页服务器,然后讲解socket使用方法和协议栈设计注意事项,最后指导设计一个CGI大型动态网页服务器,把开发板改造成一个“托管主机”,即有趣又有用,学了就能用出来做些实际的事情;在USB章,首先实验USB收发,抓包分析过程,然后讲解如何设计和测试USB驱动程序,最后指导用CF卡/SD卡/HDD做个大U盘......大部分程序不用或很少修改就能移植到各种CPU体系上,保护用户投资。每学习完一章用户就能做点实际产品,这样就能学进去而且忘不了。总的原则是:有趣、抽象、常用、实用。

(完)


希望大家以后积积来贴,最好能把论谈,贴爆了,呵呵~~~
祝大家快快乐乐学习eCos!!!
lameck - 2008-4-12 11:01:00
先来一贴
 
  第一次使用ecos,当然要先编个hello程序啦。那就来个多任务的,恩...
  3个线程任务同时打印信息,A线程每秒打印一次,B线程每3秒打印一次,C线程每6秒打印一次。

  从总体来看,ecos和ucos的应用程序大同小异,都有线程/任务创建、线程/任务函数、堆栈等内容,只是API函数名字不同。
  ecos应用程序没有从main开始,而是从cyg_start启动,在cyg_start中创建test线程,再在test中创建3个实际的工作线程。
  ecos的命名规则很有层次感,比如:cyg_thread_delay(),cyg表示cygnus公司出品,thread表示这个函数是与线程相关的(如:线程创建、延时),delay表示延时。怎么样?是不是很好记忆。所有cygnus公司提供的API函数前面都带cyg前缀,你自己写的函数可以加上你的标识前缀。

  cyg_thread_create(//创建线程
        线程优先级,
        线程函数指针,
        线程函数参数,//对应线程函数的(cyg_addrword_t data)入口参数
        线程名,      //用于调试目的
        堆栈基址,
        堆栈大小,
        线程句柄,
        保存此线程内核数据结构的存储空间
        );
   
    cyg_thread_resume(线程句柄);  //线程恢复
   
    cyg_thread_delay(延时时间);    //以10ms为单位
   
    cyg_scheduler_start();         //启动调度器开始工作。该函数被调用后不会返回

步骤:
1. 编写hello_ecos.c程序代码(参考最下边的实验代码);
2. 把1中所编写的hello_ecos.c拷贝在eCos源码下的examples目录下.
3. 修改makefiles文件;
4. 编译hello_ecos.c,生成hello_ecos.elf文件;
5. 将4中生成的hello_ecos.elf文件下载到实验仪;
6. 运行程序,通过串口调试助手观察程序运行结果.

输出结果:
      *******************************
      *    Hello! The world.      *
      *******************************


    AAAAAA111111 is active.thread data is 1.
    BBBBBB333333 is active.thread data is 2.
    CCCCCC666666 is active.thread data is 3.
    AAAAAA111111 is active.thread data is 1.
    AAAAAA111111 is active.thread data is 1.
    AAAAAA111111 is active.thread data is 1.
    BBBBBB333333 is active.thread data is 2.
    AAAAAA111111 is active.thread data is 1.
    AAAAAA111111 is active.thread data is 1.
    AAAAAA111111 is active.thread data is 1.
    CCCCCC666666 is active.thread data is 3.
    BBBBBB333333 is active.thread data is 2.
    AAAAAA111111 is active.thread data is 1.
    AAAAAA111111 is active.thread data is 1.
    AAAAAA111111 is active.thread data is 1.
    BBBBBB333333 is active.thread data is 2.
    AAAAAA111111 is active.thread data is 1.
    AAAAAA111111 is active.thread data is 1.
    AAAAAA111111 is active.thread data is 1.
    CCCCCC666666 is active.thread data is 3.
    BBBBBB333333 is active.thread data is 2.
                .......

好了,这个程序就是这么简单,跟ucos很像,其实,所有的RTOS都差不多的,只是函数名字不同罢了。
ecos和ucos一样都是直接使用平板内存,没有特权概念,不过,ecos比ucos更高级,包含了TCP/IP栈、文件系统、GUI,
功能也更强大,可以用C++开发。

这个演示应用程序可以不加修改地用在任何支持ecos的平台上,例如:ARM,NIOS等)上的运行效果是一样的,这就是OS的好处,不用再关心定时器初始化,串口编程,抹平了硬件差异,令编程如此简单,EASY。


//参考程序代码:
#include <cyg/kernel/kapi.h>

#define STACK_SIZE 4096

char stack[4][STACK_SIZE];
static cyg_thread thread_data[4];
static cyg_handle_t thread_handle[4];

void taska(cyg_addrword_t data)        //线程A
{
    int message = (int) data;
   
    for(;;)
    {
        printf("\tAAAAAA111111 is active.thread data is %d.\n",message);
        cyg_thread_delay(100);
    }
}

void taskb(cyg_addrword_t data)        //线程B
{
    int message = (int) data;
   
    for(;;)
    {
        printf("\tBBBBBB333333 is active.thread data is %d.\n",message);
        cyg_thread_delay(300);
    }
}

void taskc(cyg_addrword_t data)        //线程C
{
    int message = (int) data;
   
    for(;;)
    {
        printf("\tCCCCCC666666 is active.thread data is %d.\n",message);
        cyg_thread_delay(600);
    }
}

void test(cyg_addrword_t data)        //主线程
{
    printf("\n\n\n");
    printf("\t    *******************************\n");
    printf("\t    *    Hello! The world.      *\n");
    printf("\t    *******************************\n\n\n");

    // Create a main thread, so we can run the scheduler and have time 'pass'
    cyg_thread_create(10,                        // Priority - just a number
                              taska,                      // entry
                              1,                          // entry parameter
                            "taska",                    // Name
                              &stack[1],                // Stack
                              STACK_SIZE,            // Size
                              &thread_handle[1],  // Handle
                              &thread_data[1]      // Thread data structure
                            );
    cyg_thread_resume(thread_handle[1]); // Start it
   
    // Create a main thread, so we can run the scheduler and have time 'pass'
    cyg_thread_create(10,                          // Priority - just a number
                              taskb,                      // entry
                              2,                            // entry parameter
                              "taskb",                    // Name
                              &stack[2],                // Stack
                              STACK_SIZE,            // Size
                              &thread_handle[2],  // Handle
                              &thread_data[2]      // Thread data structure
                              );
    cyg_thread_resume(thread_handle[2]);  // Start it
   
    // Create a main thread, so we can run the scheduler and have time 'pass'
    cyg_thread_create(10,                        // Priority - just a number
                              taskc,                      // entry
                              3,                          // entry parameter
                              "taskc",                  // Name
                              &stack[3],              // Stack
                              STACK_SIZE,          // Size
                              &thread_handle[3],  // Handle
                              &thread_data[3]      // Thread data structure
                              );
    cyg_thread_resume(thread_handle[3]); // Start it
}

void cyg_start(void)            //ecos程序的起始,相当于main(),在cyg_start中创建主test线程
{
    // Create a main thread, so we can run the scheduler and have time 'pass'
    cyg_thread_create(10,                        // Priority - just a number
                              test,                      // entry
                              0,                          // entry parameter
                              "test",                    // Name
                              &stack[0],              // Stack
                              STACK_SIZE,            // Size
                              &thread_handle[0],  // Handle
                            &thread_data[0]        // Thread data structure
                            );
    cyg_thread_resume(thread_handle[0]); // Start it
    cyg_scheduler_start();
}
lameck - 2008-4-12 11:43:00
关于开发环境和makefiles的修改请参考:

《跟我学嵌入式操作系统在SPCE3200上的应用——环境配置篇V1.0》

[url]http://www.unsp.com/download/softdown/sjhzl32/200812411544.pdf[/url]
lameck - 2008-4-13 17:01:00
呵呵,没人跟啊~~~那我再来一贴~~~~

ecos下的LED驱动:

下面来我们来通过分析ecos下LED驱动程序来学习一下ecos下的驱动程序:

用户函数中,一般不直接调驱动程序接口函数,而是通过调用I/O子系统API函数来实现对设备的lookup、读、写和配置等操作。而这些文件系统API函数也会通过指针调用设备驱动程序函数。

这个程序中我们通过调I/O子系统API来实现对设备的访问,I/O子系统API在cyg/io/io.h中声明。

先让我们通过例子来了解一下,应用程序是如果访问设备的:

本实验通过实验仪上的3个按键(IOB3~5)来分别控制3个LED(IOB0~2)的亮与灭.

//参考程序:

#include <cyg/hal/hal_arch.h>                        // CYGNUM_HAL_STACK_SIZE_TYPICAL
#include <cyg/kernel/kapi.h>
#include <cyg/io/io.h>                                  //将I/O子系统API包含于此文件中
#include <cyg/io/spce3200_iob.h>

cyg_uint8 MainThread_Stack[4096];                // 线程用到的堆栈
cyg_handle_t hMainThread;                          // 线程句柄
cyg_thread infohMainThread;                        // 线程信息结构体

//====================================================
// 语法格式:void MainThread(cyg_addrword_t data)
// 功能描述: 主线程
// 入口参数: data    -    由OS传递
// 出口参数: 无
//====================================================
void MainThread(cyg_addrword_t data)
{
    /************************************************/
    /*  TODO: add your init code here              */
    /************************************************/
    cyg_io_handle_t fd_LED;                              //设备句柄
    cyg_uint32 Key;
    cyg_uint32 len;
    printf("RunLED thread strat\n");
    Key = 0x38380700;               
                                                                      //对IOB口的配置信息,IOB0~IOB2为输出,IOB3~IOB5下拉输入
    len = 4;
    cyg_io_lookup("/dev/iob",fd_LED);                  //通过cyg_io_looup()查找设备"/dev/iob"
    cyg_io_set_config(fd_LED,CYGNUM_DEVS_IOB_SPCE3200_ATTRIB,Key,len);
                                                                      //配置IOB口       
    Key = 0x0;                     
    len = 1;                   
    while(1)
        {
            cyg_io_read(fd_LED,Key,len);                  //通过cyg_io_read()对IOB口进行读(读键值)
            printf("Key = %d\n",Key);
            Key= Key >>3;                                      //IOB3~5(key)-->IOB0~2(LED) 
            cyg_io_write(fd_LED,Key,len);                //对IOB口进行写操作
        }   
}

//====================================================
// 语法格式:void cyg_user_start(void)
// 功能描述: 主函数
// 入口参数: 无
// 出口参数: 无
//====================================================
void cyg_user_start(void)
{
    /************************************************/
    /*  TODO: add your init code here              */
    /************************************************/   
    cyg_thread_create(20,                              // 线程优先级
            MainThread,            // 线程函数
            0,                // 线程参数
            "Main Thread",    // 线程名称
            (void *)MainThread_Stack,                  // 线程堆栈基址
            4096,                // 线程堆栈大小
            &hMainThread,        // 返回线程句柄
            &infohMainThread        // 返回线程信息结构体
            );       
    cyg_thread_resume(hMainThread);            // 启动线程
}

//(程序完)

从程序中可以看出用户程序对设备的访问只需调用这些I/O子系统API函数即可,这就使得不管多么复杂的驱动程序,使用只需要掌握几个简单的I/O子系统API函数即可。

另外还可以通过调用文件系统(devfs)API函数(open(),write(),read()等)实现对设备的打开、读、写等操作,这时候设备相当于一个文件;

I/O子系统API:

1.I/O 子系统设备查找函数cyg_io_lookup();

当应用程序使用I/O 子系统设备查找函数cyg_io_lookup()查找设备时,内核将调用设备驱动程序的设备查找函数。
I/O 子系统设备查找函数的完整形式为:
    Cyg_ErrNo cyg_io_lookup(const char *name,cyg_io_handle_t *handle);
其中:
a. name:应用程序希望查找的设备名,如“/dev/dev1”,在cyg_io_lookup 调用字符设备驱动程序中的查找设备函数(如dev1_lookup)时,内核会将此设备名传递给xxx_lookup 函数作为第一个参数。
b. handle:应用程序操作设备的设备句柄。在调用cyg_io_lookup 时就会建立设备的句柄handle,在调用其它设备操作函数时,直接可以通过该句柄找到设备。

2. I/O 子系统写函数cyg_io_write()
当应用程序使用I/O 子系统写函数cyg_io_write()对设备进行写操作时,内核将调用设备驱动程序的写函数。
I/O 子系统写函数的完整形式为:
    Cyg_ErrNo cyg_io_write(cyg_io_handle_t handle,void *buffer,cyg_uint32 *len);
其中:
a. handle:cyg_io_lookup 传递过来的参数,应用程序操作设备的设备句柄
b. buf:缓冲区指针,用户需要从该指针指向的缓冲区内读取数据并写入到设备
c. len:写入到设备的数据长度。函数返回时该参数包含实际写入的数据大小
调用cyg_io_write时,cyg_io_write会根据cyg_io_lookup传递过来的设备句柄调用设备驱动写函数,并把三个参数原封不动地传递给设备驱动写函数。

3. I/O 子系统读函数cyg_io_read()
当应用程序使用I/O 子系统读函数cyg_io_read()对设备进行读操作时,内核将调用设备驱动程序的读函数。
I/O 子系统读函数的完整形式为:
    Cyg_ErrNo cyg_io_read(cyg_io_handle_t handle, void *buf, cyg_uint32 *len);
其中:
a. handle:cyg_io_lookup 传递过来的参数,应用程序操作设备的设备句柄
b. buf:缓冲区指针,用户需要从设备中读取数据并将数据写入该指针指向的缓冲区内
c. len:从设备读取的数据长度。函数返回时该参数包含实际读取的数据大小
调用cyg_io_read时,cyg_io_read 会根据cyg_io_lookup 传递过来的设备句柄调用设备驱动读函数,并把三个参数原封不动地传递给设备驱动读函数。

4. I/O 子系统配置函数cyg_io_set_config()
当应用程序使用I/O 子系统配置函数cyg_io_set_config()时,内核将调用设备驱动程序的设备配置函数。
I/O 子系统配置函数的完整形式为:
        Cyg_ErrNo cyg_io_set_config (
                cyg_io_handle_t handle,
                cyg_uint32 key,
                const void *buf,
                cyg_uint32 *len
                );
其中:
a. handle:cyg_io_lookup 传递过来的参数,应用程序操作设备的设备句柄
b. key:设置信息的类型。每个驱动程序的key 值可能不同,在源码io/common/include 路径下的config_keys.h 文件中定义了一些常用的key 值;用户也可以在头文件中自定义key 值
c. buf:放置配置数据的缓冲区指针
d. len:配置信息的长度。函数返回时,该参数应该包含实际设置的数据大小

调用cyg_io_set_config 时,cyg_io_set_config 会根据cyg_io_lookup 传递过来的设备句柄调用设备驱动配置函数,并把四个参数原封不动地传递给设备驱动配置函数。

5. I/O 子系统读配置状态函数cyg_io_get_config()
当应用程序使用I/O 子系统读配置状态函数cyg_io_get_config()时,内核将调用设备驱动程序中
的读设备配置状态函数。I/O 子系统读配置状态函数的完整形式为:
        Cyg_ErrNo cyg_io_get_config(
                cyg_io_handle_t handle,
                cyg_uint32 key,
                void *buf,
                cyg_uint32 *len
                );
其中:
a. handle:应用程序操作设备的设备句柄
b. key:得到信息的类型。每个驱动程序的key 值可能不同,在源码io/common/include 路径下的config_keys.h 文件中定义了一些常用的key 值;用户也可以在头文件中自定义key 值
c. buf:放置配置数据的缓冲区指针
d. len:得到的配置信息的长度。函数返回时,该参数应该包含实际得到的数据大小

调用cyg_io_set_config 时,cyg_io_set_config 会根据cyg_io_lookup 传递过来的设备句柄调用设备驱动读配置状态函数,并把四个参数原封不动地传递给设备驱动读配置状态函数。
lameck - 2008-4-13 17:45:00
(续楼上)

设备驱动程序一般可分为三个部分,分别为设备表入口DEVTAB_ENTRY、设备I/O函数表DEVIO_TAB和设备I/O函数。设备驱动程序的主要组成模块全部定义在头文件cyg/io/devtab.h中。(具体内容请参考"http://bbs.unsp.com/showtopic-30777.aspx")

I/O子系统API中的几个函数(如楼上所介绍的)分别调用设备驱动程序API来实现对硬件的访问:
      cyg_io_lookup()调用设备表入口DEVTAB_ENTRY()中的lookup()函数,lookup()函数将使设备处于"在线"状态,处于在线状态下的设备对所有针对该项设备的I/O请求进行处理;
      cyg_io_write()调用设备I/O函数表DEVIO_TABLE()中的io_write()函数;
      cyg_io_read()调用设备I/O函数表DEVIO_TABLE()中的io_read()函数;
      cyg_io_set_config()调用设备I/O函数表DEVIO_TABLE()中的io_set_config()函数;
      cyg_io_get_config()调用设备I/O函数表DEVIO_TABLE()中的io_get_config()函数;

下边我们ecos中IOB的驱动:

在/devs/gpio/score/spce3200/iob/iob_spce3200.c文件中定义了IOB的设备表入口DEVTAB_ENTRY、设备I/O函数表DEVIO_TAB和设备I/O函数等信息。

如下:

//设备I/O函数表DEVIO_TAB
CHAR_DEVIO_TABLE(spce3200_iob_handlers,        // IOB函数表的句柄
    iob_write,                              // IOB设备写函数
    iob_read,                // IOB设备读函数 
    NULL,                                  // IOB设备选择函数,这里没有指定指针入口
    iob_get_config,                   // IOB读设备设置函数,
    iob_set_config                   // IOB写设备设置函数
);

//设备表入口DEVTAB_ENTRY
CHAR_DEVTAB_ENTRY(spce3200_iob_device,           // 设备入口表的句柄
    CYGDAT_DEVS_IOB_SPCE3200_NAME,        // 设备名,在cdl文件中进行宏定义
    NULL,                     
    &amp;amp;spce3200_iob_handlers,               // IOB函数表的句柄指针
    iob_init,                   // IOB设备初始化函数
    iob_lookup,                       // IOB设备查找函数
    NULL                       //
);

//  设备I/O函数部分框架,分别实现了iob_write(),iob_read(),iob_get_config(),iob_set_config(),iob_init()和iob_lookup()函数,具体实现这里不细说。
static Cyg_ErrNo iob_write(cyg_io_handle_t handle, void *buffer, cyg_uint32 *len)
{
  ...
}
static Cyg_ErrNo iob_read(cyg_io_handle_t handle, void *buffer, cyg_uint32 *len)
{
  ....
}
static Cyg_ErrNo iob_set_config(cyg_io_handle_t handle,cyg_uint32 key,const void *buffer,cyg_uint32 *len)
{
....
}
static Cyg_ErrNo iob_get_config(cyg_io_handle_t handle,cyg_uint32 key,const void *buffer, cyg_uint32 *len)
{
....
}
static bool iob_init(struct cyg_devtab_entry *tab)
{
...
}
static Cyg_ErrNo iob_lookup (struct cyg_devtab_entry **tab, struct cyg_devtab_entry *st,const char *name)
{
....
}
完成这些函数之后就可以方便的使用I/O子系统API来实现对设备的访问了。

呵呵,现在我对ecos有一些了解了,差不多开始入门了。如果你想和我一起学习ecos,那就请您快快顶贴~~~

也欢迎提问~~~当然也希望有多高手来这里帮大家解决问题,发表意见之贴~~~~

ecos学习进行中...........





clinging - 2008-4-13 18:22:00
好,不错的帖子,看帖再学容易多了。继续贴下去啊..........:)
lameck - 2008-4-14 12:41:00
顶....
继续努力~~~
ouyangping - 2008-4-16 10:55:00
ok,HAHAHAHAHHAHAHA
leajian - 2008-4-17 10:42:00
有关设备操作,还是建议使用POSIX标准函数,cyg_io_xxx类的函数毕竟是Cygnus公司制定的API,不具备通用性~~
比如同样是需要打开/dev/iob这个设备,用POSIX标准的函数可以这样:

int fp_LED = open("/dev/iob", O_RDWR);

int Key = 0x38380700;               
                                                                      //对IOB口的配置信息,IOB0~IOB2为输出,IOB3~IOB5下拉输入
int len = 4;
    cyg_fs_fsetinfo(fp_LED,CYGNUM_DEVS_IOB_SPCE3200_ATTRIB,&Key,len);
                                                                      //配置IOB口       
    Key = 0x0;                     
    len = 1;                   
    while(1)
        {
            read(fp_LED,&Key,len);                  //通过cyg_io_read()对IOB口进行读(读键值)
            printf("Key = %d\n",Key);
            Key= Key >>3;                                      //IOB3~5(key)-->IOB0~2(LED) 
            write(fp_LED,Key,len);                //对IOB口进行写操作
        }   

这样的程序的移植性就比使用cyg_io_xxx的函数要好的多了 :-)
云里雾里 - 2008-4-17 11:55:00
请问一下:
你说的关于I/O子系统函数(cyg_io_XXX())的不通用性指~~~ ?
哦~, 指与linux程序的不通用吗 ? 还是指别的什么?
寂寞歌唱 - 2008-5-3 18:36:00
楼主  我没有实验板应该怎样在pc 上实现你的那个 hello ecos world 这个例子  可以给知道吗?
云里雾里 - 2008-5-5 8:56:00
去看看,我在Vmware上跑redboot:
http://bbs.unsp.com/showtopic-30884.aspx  下边几贴.
woodstar123 - 2008-5-5 9:24:00
ecos本身可以配置成X86平台的,可以在PC上运行,
woodstar123 - 2008-5-5 9:27:00
不通用性是指程序只能在特定平台上跑,可移植性差
比如 open在windows上linux上都有对应函数而且功能参数都一样
但cyg_io_open()只有在ecos上才有
云里雾里 - 2008-5-5 11:18:00
哦,晓得了~~
 1 
查看完整版本: 快快乐乐学eCos