详细的S3C2440的ucOSII和ucGUI移植过程.docx
《详细的S3C2440的ucOSII和ucGUI移植过程.docx》由会员分享,可在线阅读,更多相关《详细的S3C2440的ucOSII和ucGUI移植过程.docx(16页珍藏版)》请在冰豆网上搜索。
详细的S3C2440的ucOSII和ucGUI移植过程
基于S3C2440的uc/OS-II和uc-GUI移植和应用
实验目的:
1.熟悉ARM体系构造
2.深化学习操作系统原理
3.增强动手理论才能
实验平台:
ARM9体系构造处理器—S3C2440
飞凌嵌入式开发板—FL2440〔由于本实验大局部在宿舍完成,故采用了自己的嵌入式开发板作为平台,硬件与实验箱根本相似〕
功能实现
主要功能是利用uc/OS-II的多任务调度功能和uc-GUI提供的图形函数接口,编写一
个Uart传输测试程序。
通过Uart协议,传输PC机键盘输入的数据,在开发板的LCD上显示出来。
同时实现
了字符串挪动和现实系统信息的附加功能。
注:
本实验中,移植代码局部参考了网络上的一些相关文章,应用程序局部全部由自己编写完成。
实验原理:
1.背景介绍
(1)ARM9〔S3C2440〕
ARM9系列处理器是英国ARM公司设计的主流嵌入式处理器。
S3C2440是三星公司消费的基于ARM9体系构造的处理器,可以运行linux、wince等大型操作系统,构成非常典型的cpu+os嵌入式系统。
[1]
(2)uc/OS-II
uc/OS是一种免费公开源代码、构造小巧、具有可剥夺实时内核的实时操作系统。
uc/OS-II是一个实时操作系统内核,它包含了任务调度,任务管理,时间管理,内存管理和任务间的通信和同步等根本功能。
是一个基于优先级调度的抢占式的实时内核,并在这个内核之上提供最根本的系统效劳,如信号量,邮箱,消息队列,内存管理,中断管理等。
(3)uc-GUI
uC/GUI是Micrium公司开发的通用的嵌入式用户图形界面软件。
它给任何使用图形LCD的应用程序提供独立于处理器和LCD控制器之外的有效的图形用户接口。
可以应用于单一任务环境,也可以应用于多任务环境中。
uC/GUI可以应用于任何LCD控制器和CPU的任何尺寸的物理显示或者模拟显示中。
2.移植原理
(1)uc/OS-II移植
为了方便移植,大局部的uC/OSII代码是用c语言写的,但仍需要用c和汇编语言写一些与处理器相关的代码,这是因为uC/OSII在读写处理器存放器时只能通过汇编语言来实现。
由于uC/OSII在设计时就已经充分考虑了可移植性,所以uC/OSII的移植相对来说是比拟容易的。
移植主要涉及的文件。
〔详细移植代码见后文附录〕
(a)设置与处理器及编译器相关的代码[OS_CPU.H]
这局部代码主要实现一些数据类型的定义。
不同的编译器会使用不同的字节长度来表示同一数据类型,所以要定义一系列数据
类型以确保移植的正确性。
下面是uC/OSII定义的一局部数据类型。
typedefunsignedcharBOOLEAN;/*布尔型数据类型*/
typedefunsignedcharINT8U;/*无符号8位*/
typedefsignedcharINT16S;/*带符号8位*/
typedefunsignedintINT16U;/*无符号16位*/
……
uC/OSII需要先关中断再访问临界区的代码,并且在访问完后重新允许中断。
uC/OSII定义了两个宏来制止和允许中断:
OS_ENTER_CRITICAL()和OS_EXIT_CRITICAL(),本移植实现这两个宏的汇编代码。
#defineOS_ENTER_CRITICAL()__asm{blARMDisableInt}//ARMDisableInt()
#defineOS_EXIT_CRITICAL()__asm{blARMEnableInt}//ARMEnableInt()
(b)用C语言实现与处理器任务相关的函数[OS_CPU_C.C]
这局部代码最主要的功能是实现一个系统的堆栈初始化函数
OS_STK*OSTaskStkInit(void(*task)(void*pd),
void*pdata,
OS_STK*ptos,
INT16Uopt)
其他的一些操作系统的钩子函数也在这里定义,如:
voidOSTaskCreateHook(OS_TCB*ptcb);
等等,用来实现操作系统的扩展功能。
由于本实验没有使用到这些钩子函数,故在这里只定义成空函数即可。
(c)处理器相关局部汇编实现
这局部代码是移植的核心内容,主要实现操作系统的任务调度等核心功能。
a)OSStartHighRdy()
该函数在OSStart()多任务启动之后,负责从最高优先级任务的TCB控制块中获得该任务的堆栈指针sp,通过sp依次将CPU现场恢复,此时系统就将控制权交给用户创立的该任务的进程,直到该任务被阻塞或者被其他更高优先级的任务抢占了CPU。
该函数仅仅在多任务启动时被执行一次,用来启动第一个,也就是最高优先级的任务执行。
b)OSCtxSw()
该函数是任务级的上下文切换函数,在任务因为被阻塞而主动恳求与CPU调度时执行,主要工作是先将当前任务的CPU现场保存到该任务堆栈中,然后获得最高优先级任务的堆栈指针,从该堆栈中恢复此任务的CPU现场,使之继续执行,从而完成一次任务切换。
c)OSIntExit()
该函数是中断级的任务切换函数,在时钟中断ISR中发现有高优先级任务在等待时,需要在中断退出后不返回被中断的任务,而是直接调度就绪的高优先级任务执行。
其目的在于可以尽快让高优先级的任务得到响应,保证系统的实时性能。
d)OSTickISR()
该函数是时钟中断处理函数,主要任务是负责处理时钟中断,调用系统实现的OSTimeTick函数,假如有等待时钟信号的高优先级任务,那么需要在中断级别上调度其执行。
另外两个相关函数是OSIntEnter()和OSIntExit(),都需要在ISR中执行。
[2]
〔2〕uc-GUI移植
移植uC/GUI主要集中在修改三个头文件和两个C文件。
三个头文件都在\Config下,分别是GUICon.h,GUITouchConf.h,LCDConf.h;两个C文件一个是GUI_X.C(Sample\GUI_X.C),.另外一个在GUI\LCDDriver目录下〔LCDWin.c〕
(a)
主要修改的地方:
#defineLCD_XSIZE (320)
#defineLCD_YSIZE (240)
#defineLCD_BITSPERPIXEL(16) //16Bpp
#defineLCD_CONTROLLER1375
LCD_XSIZE ,LCD_YSIZE是对应LCD的尺寸大小
LCD_BISPERPIXEL 指定每象素的位的数量
LCD_CONTROLLER是LCD控制器
(b)
#ifndefGUICONF_H
#defineGUICONF_H
#defineGUI_OS
(1)/* 是否支持OS*/
#defineGUI_SUPPORT_TOUCH (0) /*是否支持触摸屏*/
#defineGUI_SUPPORT_UNICODE
(1) /*是否支持ASCII/UNICODE*/
#defineGUI_DEFAULT_FONT &GUI_Font6x8/*选择一个默认的字体*/
#defineGUI_ALLOC_SIZE 1024*1024 /*动态内存的大小*/
#defineGUI_WINSUPPORT
(1) /*是否支持WM〔视窗管理器〕*/
#defineGUI_SUPPORT_MEMDEV
(1) /*是否支持存储设备*/
#defineGUI_SUPPORT_AA (0) /*是否支持反锯齿*/
#endif
在LCD的最根本操作就是在某一个坐标上画点,其他的操作都是画点操作延伸出来的。
uC/GUI的所有对LCD的操作也是基于这个动作。
在FL2440_LCD_for_GUI.c文件中实现开发板LCD的根本操作函数,与uc-GUI中定义的函数对接。
如:
voidFL2440_LCD_SetPixel(U32x,U32y,U16c)
{
PutPixel(x,y,c);/*根本的LCD画点函数*/
}
U16FL2440_LCD_GetPixel(U32x,U32y)
{
return(GUI_Point(x,y));/*根本的LCD读点函数*/
}
voidFL2440_LCD_Off(void)
{
Lcd_EnvidOnOff(0);/*LCD开关*/
}
voidFL2440_LCD_On(void)
{
Lcd_EnvidOnOff
(1);/*LCD开关*/
}
[3]
实验过程:
前面介绍了根本的移植原理,要想让开发板可以正常工作,还需要一些额外的工作。
1.启动代码
采用三星公司针对2440的启动代码,根本无需修改。
2.应用程序
前面介绍的uc/OS-II只是一个操作系统的最根本内核,要实现详细功能,要求开发人员自己编写相关的应用程序。
本实验中,应用程序在主函数文件finalmain.c中实现。
主要功能是利用uc/OS-II的多任务调度功能和uc-GUI提供的图形函数接口,编写一个Uart传输测试程序。
通过Uart协议,传输PC机键盘输入的数据,在开发板的LCD上显示出来。
同时实现了字符串挪动和现实系统信息的附加功能。
主函数如下:
voidMain()
{
//系统时钟,LCD,Uart,GUI以及uc/OS-II的初始化
cpu_init();
FL_Lcd_Init();
Uart_Init(0,115200);
Uart_Printf("begin!
\n");
GUI_Init();
GUITASK_Init();
OSInit();
OSTimeSet(0);
//创立起始任务
OSTaskCreate(TaskStart,0,&TaskStartSTK[TaskStkLeath-1],NormalTaskPrio+13);
//创立信号量,用于在文本框输入满后去除文本框内容使用
Cls=OSSemCreate
(1);
OSStart();
}
voidTaskStart(void*pdata)//起始任务
{
//设置系统时钟节拍
Init_Timer4();
//初始化统计任务
OSStatInit();
//创立任务
/*Task_Text为创立文本框任务,在LCD上画出一个文本框,同时实如今文本框输入满的时候清楚文本框内容*/
OSTaskCreate(Task_Text,0,&Task_Text_Stk[TaskStkLeath-1],NormalTaskPrio);
/*Task_SideText任务,在LCD侧边处现实操作系统名称及版本,并向上挪动*/
OSTaskCreate(Task_SideText,0,&Task_SideText_Stk[TaskStkLeath-1],NormalTaskPrio+3);
/*Task_Info任务,在文本框下方显示系统信息,包括CPU使用率,系统任务切换频率,系统开机时间*/
OSTaskCreate(Task_Info,0,&Task_Info_Stk[TaskStkLeath-1],NormalTaskPrio+5);
/*Task_Title任务在文本框上方滚动现实提示信息*/
OSTaskCreate(Task_Title,0,&Task_Title_Stk[TaskStkLeath-1],NormalTaskPrio+6);
/*Task_Uart任务,从Uart串口读取数据显示在文本框中*/
OSTaskCreate(Task_Uart,0,&Task_Uart_Stk[TaskStkLeath-1],NormalTaskPrio+8);
/*在文本框中现实位图,〔可选〕*/
//OSTaskCreate(Task_Bmp,0,&Task_Bmp_Stk[TaskStkLeath-1],NormalTaskPrio+7);
OSTaskDel(OS_PRIO_SELF);
Uart_Printf("ExitTaskStart.\n");
}
实验结果:
经过屡次实验和调试,最终实现了上述功能,以下是实验结果截图:
ADS工程源文件组织构造
附录:
1.uc/OS-II移植代码〔汇编函数局部〕:
OSStartHighRdy
BLOSTaskSwHook;Calluser-definedhookfunction
LDRr4,=OSRunning;Indicatethatmultitaskinghasstarted
MOVr5,#1
STRBr5,[r4];OSRunning=true
LDRr4,=OSTCBHighRdy;GethighestprioritytaskTCBaddress
LDRr4,[r4];getstackpointer
LDRsp,[r4];switchtothenewstack
LDMFDsp!
{r4};popnewtasksspsr
MSRspsr_c,r4
LDMFDsp!
{r4};popnewtaskspsr
MSRcpsr_c,r4
LDMFDsp!
{r0-r12,lr,pc};popnewtasksr0-r12,lr&pc
OSCtxSw
STMFDsp!
{lr}
STMFDsp!
{r0-r12,lr};pushlr®isterfile
MRSr4,cpsr;copyCPSRtoR4
STMFDsp!
{r4};pushcurrentpsr
MRSr4,spsr;copySPSRtoR4
STMFDsp!
{r4};pushcurrentspsr
_OSCtxSw
LDRr4,=OSPrioCur;OSPrioCur=OSPrioHighRdy
LDRr5,=OSPrioHighRdy
LDRBr6,[r5]
STRBr6,[r4]
LDRr4,=OSTCBCur;GetcurrenttaskTCBaddress
LDRr5,[r4]
STRsp,[r5];storespinpreemptedtasks'sTCB
BLOSTaskSwHook;callTaskSwitchHook
LDRr6,=OSTCBHighRdy;GethighestprioritytaskTCBaddress
LDRr6,[r6]
LDRsp,[r6];getnewtasksstackpointer
STRr6,[r4];setnewcurrenttaskTCBaddress
LDMFDsp!
{r4};popnewtaskspsr
MSRspsr_c,r4
LDMFDsp!
{r4};popnewtaskcpsr
MSRcpsr_c,r4
LDMFDsp!
{r0-r12,lr,pc};popnewtaskr0-r12,lr&pc
OSIntCtxSw
LDRr0,=OSIntCtxSwFlag;OSIntCtxSwFlag=true
MOVr1,#1
STRr1,[r0]
MOVpc,lr;Thisisonlychangeflag,returntoOSIntExit
/
OSTickISR
SUBlr,lr,#4
STMFDsp!
{r0-r12,lr};pushr0-r12registerfileandlr(pcreturnaddress)
MRSr4,spsr
STMFDsp!
{r4};pushcurrentspsr_irq(=cpsr_svc)
movr0,#0x4000
movr1,#0x4a000000
strr0,[r1,#0]
movr0,#0x4000
movr1,#0x4a000000
strr0,[r1,#0x10]
BLOSIntEnter
BLOSTimeTick
BLTmrSignalTmr
BLOSIntExit
LDRr0,=OSIntCtxSwFlag;checkifOSIntCtxFlagismarkedastrue
LDRr1,[r0]
CMPr1,#1
BEQ_IntCtxSw;ifOSIntCtxFlag=true,thenjumpto_IntCtxSw
LDMFDsp!
{r4};getcpsr_svcfromstack
MSRspsr_c,r4;preparespsrtoreturnsvcmode
LDMFDsp!
{r0-r12,pc}^;recoverr0-r12andpcfromstack,cpsralso
_IntCtxSw
MOVr1,#0;clearOSIntCtxSwFlag=flase
STRr1,[r0]
LDMFDsp!
{r4};restorespsr_irq
MSRspsr_c,r4
LDMFDsp!
{r0-r12,lr};recovertheirqstackpointer
LDRr5,=SAVED_LR_IRQ
LDRr6,=SAVED_LR_SVC
STRlr,[r5];savelr_irqtoSAVED_LR_IRQ
MOVlr,#0x00000093;changeforcelycpsrtosvcmode
MSRcpsr_c,lr
STRlr,[r6];savelr_svctoSAVED_LR_SVC
LDRlr,[r5];getlr_irqvaluesavedinSAVED_LR_IRQ
STMFDsp!
{lr}
LDRlr,[r6]
STMFDsp!
{r0-r12,lr};pushlr&r0-r12registerfile
MRSr4,spsr
STMFDsp!
{r4};pushcurrentpsr
MRSr4,spsr
STMFDsp!
{r4};pushspsr
B_OSCtxSw;jumpto_OSCtxSw
ARMDisableInt
MRSr0,cpsr
STMFDsp!
{r0};pushcurrentPSR
ORRr0,r0,#0x80
MSRcpsr_c,r0;disableIRQInts
MOVpc,lr
ARMEnableInt
LDMFDsp!
{r0};popcurrentPSR
MSRcpsr_c,r0;restoreoriginalcpsr
MOVpc,lr
2.uc/OS-II移植代码〔C语言函数局部〕:
OS_STK*OSTaskStkInit(void(*task)(void*pd),void*pdata,OS_STK*ptos,INT16Uopt)
{
unsignedint*stk;
opt=opt;/*'opt'isnotused,preventwarning*/
stk=(unsignedint*)ptos;/*Loadstackpointer*/
/*buildacontextforthenewtask*/
*--stk=(unsignedint)task;/*pc*/
*--stk=(unsignedint)task;/*lr*/
*--stk=0;/*r12*/
*--stk=0;/*r11*/
*--stk=0;/*r10*/
*--stk=0;/*r9*/
*--stk=0;/*r8*/
*--stk=0;/*r7*/
*--stk=0;/*r6*/
*--stk=0;/*r5*/
*--stk=0;/*r4*/
*--stk=0;/*r3*/
*--stk=0;/*r2*/
*--stk=0;/*r1*/
*--stk=(unsignedint)pdata;/*r0*/
*--stk=(SVC32MODE|0x0);/*cpsrIRQ,FIQdisable*/
*--stk=(SVC32MODE|0x0);/*spsrIRQ,FIQdisable*/
return((void*)stk);
}
3.LCD驱动函数相关〔局部〕
staticvoidPutPixel(U32x,U32y,U16c)
{
if((xLCD_BUFFER[(y)][(x)]=c;
}
staticU16GUI_Point(U32x,U32y)
{
U16c;
if((xc=LCD_BUFFER[(y)][(x)];
returnc;
}
参考文献:
[1]
[2]
[3]