4-24得知RAW-OS重新开通了~鼓掌~
http://www.raw-os.org/
扑街啊,今日一上Q嗰时就知道RAW-OS官网挨封杀,顶佢个肺啊,E个年头连自己友都唔撑自己友,世态炎凉,世风日下啊,唉~想话向前发展谈何容易啊~~
现在RAW-OS的代码托管在google code上,望大家也可以默默支持啦,小弟我也是只能帮顶上了,支持txj~支持raw-os~
源码位置:https://[email protected]/p/raw-os/
好,现在可以转入我们今天的正题了,RAW-OS详细的移植步骤,并且下载的FPGA板子上跑起来。
上一篇的blog《or1200移植实时系统Raw-os(一)》中已经把移植相关的主要函数全部写通了,这篇blog主要是其他一些细节的描述
下载后解压,得到如下目录
分别说说
/kernel:RAW-OS操作系统源码
/drivers:or1200_basic_soc相关外设驱动
/lib:printf函数实现
/port:CPU架构汇编部分
/znFAT:znFat文件系统源码
/application:应用层代码
好,这次我们主要讲RAW-OS移植,所以
/znFAT可以放着不管,后两节我们在移植文件系统回过头去看;
/lib我们也可以不管,打印函数的实现,有兴趣可以看看;
/kernel移植过程不需要去修改任何东西,所以移植就可以直接放一边了,不过到最后学习RAW-OS的时候就要自己不断地去看了
/drivers存放相关的外设驱动,浏览一下,我们之前写过的UART、Timer、Interrupt等等,其他的驱动可以先放着,以后用到的时候会有详细说明,这次移植我们还用不到;
/port:这个文件夹的东西就要好好说明了,来看图
reset.S,和以前一样,or1200架构的启动代码,在之前写裸机程序和移植u-boot的时候大家很熟悉的啦,并且,里面包括上一篇blog提到的4个重要函数的编写。
port_hook.c,一系列的hooks fuctions,诸如任务建立,删除,tick中断,初始化等等的钩子函数,目前全部没有编写实现,有需要的朋友可以自行去实现这些钩子函数。
port.c,里面有上一篇blog提到的任务建立时的stack_init()函数,还有当OS需要寄存CPU的super register状态时调用的函数
CPU_SR OS_CPU_SR_Save(void) { CPU_SR cpu_sr; cpu_sr = mfspr(SPR_SR); mtspr(SPR_SR, cpu_sr & ~(SPR_SR_IEE | SPR_SR_TEE)); return cpu_sr; } void OS_CPU_SR_Restore(CPU_SR cpu_sr) { mtspr(SPR_SR, cpu_sr); /* | (SPR_SR_IEE | SPR_SR_TEE)*/ }
再有就是/include里面的头文件
raw_type.h:数据类型的重定义,根据自己的CPU架构来吧。
port_idle_config.h:直接忽略掉,进入源码学习的时候会懂的。
raw_cpu.h里面要注意的就是有关寄存or1200状态寄存器的几个宏定义,或者仿照ucos理解后直接抄过来~这里是声明,在port.c有有关这些宏的定义,很简单,看看就明白了~
#ifndef RAW_CPU_H #define RAW_CPU_H #define NEED_STATUS 1 typedef unsigned int CPU_SR; CPU_SR OS_CPU_SR_Save( void ); void OS_CPU_SR_Restore( CPU_SR cpu_sr ); #ifdef NEED_STATUS #define RAW_SR_ALLOC() CPU_SR cpu_sr = (CPU_SR)0 #else #define RAW_SR_ALLOC() #endif // #define RAW_CRITICAL_ENTER() {cpu_sr = OS_CPU_SR_Save();} // #define RAW_CRITICAL_EXIT() {OS_CPU_SR_Restore(cpu_sr);} #define RAW_CPU_DISABLE() {cpu_sr = OS_CPU_SR_Save();} #define RAW_CPU_ENABLE() {OS_CPU_SR_Restore(cpu_sr);} #endif
最后就是port.h
里面是reset.S里面四个汇编相关的函数声明和hook functions的函数声明,要注意的就是任务切换宏定义的内容,是用or1200提供的系统调用l.sys指令来实现任务切换。
/* 2012-8 Created by jorya_txj * xxxxxx please added here */ #ifndef PORT_H #define PORT_H /* function prototype for task context switch during interrupt */ void raw_int_switch(void); RAW_VOID *port_stack_init(PORT_STACK *p_stk_base, RAW_U32 stk_size, RAW_VOID *p_arg, RAW_TASK_ENTRY p_task); void port_task_switch(void); void raw_start_first_task(void); #define RAW_ASSERT(CON) if (!(CON)) { volatile RAW_U8 dummy = 0; while (dummy==0); } // #define CONTEXT_SWITCH() port_task_switch(); #define CONTEXT_SWITCH() __asm__ ("l.sys 0"); \ __asm__ ("l.nop"); #if (CONFIG_RAW_USER_HOOK > 0) RAW_VOID raw_os_init_hook(void); RAW_VOID task_create_hook(RAW_TASK_OBJ *task_ptr); RAW_VOID raw_task_delete_hook(RAW_TASK_OBJ *task_ptr); RAW_VOID raw_task_abort_hook(RAW_TASK_OBJ *task_ptr); RAW_VOID raw_idle_task_hook(void); RAW_VOID raw_task_switch_hook(void); RAW_VOID raw_tick_hook(void); #endif #endif
还有reset.S中添加一段bass段清零的代码,之前我没注意这个细节,跑到内核code的时候各种蛋碎~原因是内核boot的过程依赖某些全局变量的值为0,所以添加如下代码
1: l.sw (0)(r28), r0 l.sfltu r28, r30 l.bf 1b l.addi r28, r28, 4
并且修改link.lds文件如下
/* Linker script for OR1200 program */ /* Linking for loading into external RAM */ MEMORY { /* ld_info : ORIGIN = 0x00000000, LENGTH = 0x000000F0 */ vectors : ORIGIN = 0x00000000, LENGTH = 0x2000 - 0x100 ram : ORIGIN = 0x00002000, LENGTH = 0x00040000 - 0x00002000 } /* The following section defines where to put the different input sections. .text contains the code. .data contains the initialized data. .bss contains uninitialized data. .sdata contains small constant data. */ /* Stack information variables */ _min_stack = 0x2000; /* 8K - minimum stack space to reserve */ SECTIONS{ /* .ld_info :{ } > ld_info */ .vectors : { *(.vectors) } > vectors .text : { _stext = .; *(.text) _etext = .; __CTOR_LIST__ = .; LONG((__CTOR_END__ - __CTOR_LIST__) / 4 - 2) *(.ctors) LONG(0) __CTOR_END__ = .; __DTOR_LIST__ = .; LONG((__DTOR_END__ - __DTOR_LIST__) / 4 - 2) *(.dtors) LONG(0) __DTOR_END__ = .; *(.lit) *(.shdata) _endtext = .; } > ram .rodata : { *(.rodata); *(.rodata.*) } > ram .shbss : { *(.shbss) } > ram .talias : { } > ram .data : { sdata = .; _sdata = .; *(.data) edata = .; _edata = .; } > ram .bss SIZEOF(.data) + ADDR(.data) : { sbss = . ; _sbss = . ; __bss_start = ALIGN(0x8); ___bss_start = ALIGN(0x8); *(.bss) *(COMMON) end = ALIGN(0x8); _end = ALIGN(0x8); __end = ALIGN(0x8); ebss = .; _ebss = .; } > ram /* ensure there is enough room for stack */ .stack (NOLOAD): { . = ALIGN(4); . = . + _min_stack ; . = ALIGN(4); stack = . ; _stack = . ; } > ram .stab 0 (NOLOAD) : { [ .stab ] } .stabstr 0 (NOLOAD) :{ [ .stabstr ] } }
OK
在移植这里需要注意的代码再检查一番后,就可以转入/application目录下写应用层的简单测试代码了~
在/application/inlcude中,我把所有用到的头文件写进application.h,在写其他代码就直接包含这个头文件,方便管理。
好,接下来board.c文件,现在只编写Tick ISR函数,回想前面分析Tick ISR所遗留做的工作,清除Tick中断,调用raw_time_tick()。
#include "application.h" /* * This is the timer interrupt service routine. */ void SysTickHandler(void) { TimerClearInterrupt(); raw_time_tick(); // task_0_tick_post(); // raw_printk("timer interrupt ...\n"); } /* Initialize interrupt routines */
转入main.c函数,很简单,先初始化UART,这个代码以前在写裸机代码的时候我们写过了~然后就是RAW-OS内核初始化~接下去application_init(),这个函数稍后介绍,最后就是启动RAW-OS,完毕,说说application_init()
注意main.c中先把sdcard_init()屏蔽掉,若不是在or1ksim中仿真不出结果
#include "application.h" int main(){ uart_init(); sd_test(); raw_os_init(); application_init(); raw_os_start(); return 0; }
Application.c文件中我们定义两个任务,task1和task2,task1中初始化timer,然后计数,休眠10个ticks,task2先休眠50个ticks,再把task1删除,所以结果应该系task1会计数5次,然后task2把task1删除。
#include "application.h" #define TEST_TASK_STK_SIZE 512 PORT_STACK test_task_stack1[TEST_TASK_STK_SIZE]; PORT_STACK test_task_stack2[TEST_TASK_STK_SIZE]; RAW_TASK_OBJ test_task1_obj, test_task2_obj; void test_task1(void * pParam) { RAW_U32 count = 0; raw_printk("creat task1 successful ...\n"); TimerInit(); while(1){ raw_printk("task1 count : %d ...\n", count++); raw_sleep(10); } } void test_task2(void * pParam) { raw_printk("creat task2 successful ...\n"); raw_sleep(50); raw_task_delete(&test_task1_obj); raw_printk("task1 delete OK ...\n"); while(1); } int application_init(void){ RAW_U16 result1, result2; /* Creat task1 */ result1 = raw_task_create(&test_task1_obj, "task1", 0, 15, 0, test_task_stack1, TEST_TASK_STK_SIZE, test_task1, 1); /* Creat task2 */ result2 = raw_task_create(&test_task2_obj, "task2", 0, 15, 0, test_task_stack2, TEST_TASK_STK_SIZE, test_task2, 1); return 0; }
OK,测试代码就这样编写完毕,最后就是makefile的编写,makefile的内容就不详述了,参考别人的修修补补,或者直接看源码里面写好的吧。
又到老规矩了,先在or1ksim中仿真。
Make完之后sim一sim可以看到我们想要的结果啦~
然后就是download到basic soc中跑起来~这个basic soc小弟又重新修改了,自己也可以根据自己的需求添加自己需要的东西,我只是在原来的basic soc中添加上了gpio、simple-spi、i2c master。
目前也在业余时间编写一个i2s的core,虽然说opencores社区上面也有,但是还是想自己练练手,下一步想把板子上的音频芯片调通,然后把裸机的驱动write一write,再挤点时间出来看看linux的音频子系统,慢慢来吧~公司这边也有两个M4单片机的项目在负责软件部分~苦逼的程序员~废话少说吧,有空把本科时候做的毕设也晒晒出来,做的是一个NFC方面的东西,chirp信源和其匹配滤波器关于基带信号传输部分~
至于修改过的soc和raw-os的工程,有兴趣的朋友发个邮件给我向我要吧,CSDN上传之后又不能修改~太有特色了~泥煤~
OK,the final operation
open a terminal in ubuntu,
then connect your downloader to vbox,
follows the steps refer to the blog written before named The First Program Under Or1200,
and final you will get information you want, if not, check your character, hahahaha~
那下篇blog就写写基于simple-spi这个core下编写SD卡的裸机驱动了,然后大家抽空去了解了解znFat这个文件系统吧~也是国内一位牛人写的开源的Fat32格式的文件系统,帮顶~驱动完成之后就把这个文件系统移植上去~
各位拜拜~小弟我动漫去了,话说这次4月番好多猛的~进击的巨人~有木有~