Andrew Huang
一.关于FreeRTOS
FreeRTOS的一个开源实时操作系统,类似于uCOS/VxWorks.但是有几个特点是,uCOS是开源但是商用要收费。而FreeRTOS不但开源,商用也完全不受限制。另外一个是整个操作系统的核心只有四个C源代码和一些头文件,实在是出出乎人的意料.因此可以在更为简单的硬件环境下运行FreeRTOS,象ARM7之类没有MMU的CPU,还包括大部分OS不能运行的单片机环境。因此很多人开始用这个OS.
另有人提到,freertos 支持任务优先调度,并且同一优先级任务支持时间片轮番调度, ucos不支持时间片轮番调度。 freertos 任务数不受限制,最小RAM<400 byte ,rom < 4 kbyte, 优点:简单,轻小,简明,免费,升级快。
接触这个OS的原因是在一家大公司的做嵌入式C实时编程,对方提到自己原来一直是在单片机用FreeRTOS,因此想结合一下这个OS讲一下。了解FreeRTOS发现也相当简单,但是我手头都是S3C2440的板,但官方在ARM9下只有AT91的版本。而且是针对RVDS的。因此动了念头在用ADS移植FreeRTOS到S3C2440的念头。
二.FreeRTOS框架
FreeRTOS的官方网站是 ,我使用是目前最新一个版本 6.0.5
国内也有网站将其文档翻译成中文
用source insight 简单的查看各个源码和代码,以及demo的代码,基本上可以分析出如下结果。
2.1 内核代码
FreeRTOS的内核代码是croutine.c list.c queue.c tasks.c,头文件在include下.其中list.c,queue.c是实际上两种数据结构链表和队列的操作代码。这样内核代码实际上tasks.c和croutine.c. 其中tasks.c是用实时操作系统常见的Task的概念,或者是一般大型OS中的线程概念。每个Task的堆栈是独立的。而croutine.c描述是一种更为节约的任务模型,共享堆栈的任务模式。这样跟task.c是并行的代码。这样一个OS内核实际上只有一个C源代码实现的!!,tasks.c也不大,只有2300多行。croutine.c更小了,只有 360多行。
2.2 OS操作硬件代码
操作系统操作具体的CPU的硬件代码在portable目录,是按编译器类型来划分的,如GCC,RVDS(即ADS的升级版)
在某一个编译器下,又有具体CPU的控制代码。比如像这个 E:\FreeRTOS\Source\portable\GCC\ARM7_AT91SAM7S。每个CPU操作代码必须要实现 portmacro.h 和port.c 两个代码。这就是大部分的OS所说的BSP代码了。
2.3 完整target源码
有底层开发经验的工程师都知道,一个程序想在CPU上运行起来。还有一个最重要代码,就是汇编写的引导代码,以及操作系统的调用代码。FreeRTOS是把这一部分代码放在Demo目录,你可以看不同开发板的代码。引导代码就写在这里,象LPC2106代码就写在Demo/ARM7_LPC2106_GCC,在这个目录下我们能清楚看到boot.s.
从这一些源码来分析,FreeRTOS对这一些代码没有什么规定,前提只求在这个一些代码要有一个名为 main()的函数把操作系统调起来。一般调用象上例中的调用OS的代码是main.c中的main().从代码可以看到,都在创建一些Task(),最后进行OS的调度循环。
int main( void ) { /* Setup the hardware for use with the Olimex demo board. */ prvSetupHardware();
/* Start the demo/test application tasks. */ vStartIntegerMathTasks( tskIDLE_PRIORITY ); vAltStartComTestTasks( mainCOM_TEST_PRIORITY, mainCOM_TEST_BAUD_RATE, mainCOM_TEST_LED ); vStartLEDFlashTasks( mainLED_TASK_PRIORITY ); vStartPolledQueueTasks( mainQUEUE_POLL_PRIORITY ); vStartMathTasks( tskIDLE_PRIORITY ); vStartSemaphoreTasks( mainSEM_TEST_PRIORITY ); vStartDynamicPriorityTasks(); vStartBlockingQueueTasks( mainBLOCK_Q_PRIORITY );
/* Start the check task - which is defined in this file. */ xTaskCreate( vErrorChecks, ( signed char * ) "Check", configMINIMAL_STACK_SIZE, NULL, mainCHECK_TASK_PRIORITY, NULL );
/* Now all the tasks have been started - start the scheduler.
NOTE : Tasks run in system mode and the scheduler runs in Supervisor mode. The processor MUST be in supervisor mode when vTaskStartScheduler is called. The demo applications included in the FreeRTOS.org download switch to supervisor mode prior to main being called. If you are not using one of these demo application projects then ensure Supervisor mode is used here. */ vTaskStartScheduler();
/* Should never reach here! */ return 0; }
|
从它的Makefile中,我们可以看到,完整的代码还要链接2.1 /2.2 的相关代码。
这里是ARM9用IAR编译器的目录结构
从上述分析的我们得出两个结论。
一个在确定target运行的完整代码需要三大块源码 2.1 /2.2/2.3
在一个新的target移植FreeRTOS需要增加两块代码,一是在Portable目录下增加相应的OS操作硬件代码。第一个是在demo目录下增加相应引导代码。
2.4 第三方项目源码
在demo/common 目录下,放着FreeRTOS已经成功移植第3方项目,象uIP/lwIP/FatFs 等,在你的项目里可以考虑引入这一些源码。在很多项目还移植httpd来作为嵌入式服务器。这一些在未来都可以用来参考的。
关于移植FreeRTOS,动手前最好阅读一下官方网站这一篇文章
三.移植到S3C2440设备上
下一步我着手在我手里的S3C2440板上移植了 FreeRTOS,相对于ARM新的 RealView,更习惯用ADS.而且我机器上只有安装ADS。因此准备用这个编译器来编译了。
按照其规范,我首先在Source\portable目录下建立了 ADS\ARM9_S3C2440目录。
然后在Demo目录下建立 ARM9_S3C2440_ADS目录.
3.1 创建自己的portable代码。
FreeRTOS主要实现 portmacro.h/port.c,可以参考一个ARM7的类似代码。最好从RVDS目录下选一个,因这两个工具很多基本是一样的,包括汇编语法。我选用的ARM7_LPC21xx作为模板.
经过检查,这一份代码基本是ADS类似的语法。象关中断,开中断都是用ARMCC的内部函数,__disable_irq(),__enable_irq();但是寄存器宏名字有较大的调整。
3.2 创建自己的Demo代码.
这个因FreeRTOS对于相互的格式并无太多要求。把S3C2440的测试代码的引导代码拿过来即可。但是需要调整对于内存分区的相应代码,因为FreeRTOS也要用这一部分。
可以参考DEMO/ARM7_LPC2129_Keil_RVDS这一部分代码来调整。
我是把原来上课测试的LED测试代码直接搬过来的.
一编译有大量错误。因为我LED代码是测试工作正常。因此我觉得变换一下移植策略.即在已经运行成功的代码上没断调整变成符合RTOS API的代码。这样好处是我不断看到成功的结果,并能滚动开发。
3.3 第一次移植,调整LED控制代码
在很多demo项目下有ParTest.c 用于GPIO口的一些应用测试,包括LED测试。这一些代码跟内核并无太多关联,但是为了方便以后的开发者。可以在没有移植内核前先把这一些API函数移植了,作为第一步。
参见Demo/common/ParTest.h,主要实现如下三个函数
void vParTestInitialise( void ); //初始化
//
void vParTestSetLED( unsigned portBASE_TYPE uxLED, signed portBASE_TYPE xValue );
void vParTestToggleLED( unsigned portBASE_TYPE uxLED );
3.3 时间频率及时间中断处理
这里有一些宏的值是要根据target来设置的.主要在FreeRtosConfig.h当中。
#define configCPU_CLOCK_HZ ( ( unsigned long ) BOARD_MCK )
#define configTICK_RATE_HZ ( ( portTickType ) 1000 )
时间中断在实时的OS起核心的调度作用,必须一启动OS时就要配置时间中断,相应代码在 port.c::prvSetupTimerInterrupt();
3.4 内存分区设定
<<在线编写中>>
阅读(6425) | 评论(1) | 转发(0) |