转载于:http://www.cdus.org/cdusbk/bbs.php?id=423
今天开始学习FreeRTOS,就今天一天的学习稍做总结:
开始,对操作系统总有种恐惧的心态,不知从何下手,上午还是在看“FreeRTOS API Reference”,看了大约有二十来页,感觉也没什么,和课本上讲的操作系统差不了太多,下午开始了S800系统(基本FreeRTOS,结合利用的硬件,包括一些低层驱动的软硬件系统)。
对整个系统的架构还不是太了解,总体感觉是一个workspace有好多个project,大多的project输出为库文件,而主project去通过库文件去调用,所以,其中有很多的main函数,而且很多时候我们用"go to definition"的时候都找不到函数的定义。。。
找到mainproject的main函数:
void main(void)
{
HWSetup(); /* 硬件初始化 */
bpool(mHeap,configTOTAL_HEAP_SIZE); /* heap initialize */
xTaskCreate( vTaskStart, /* Create the first task */
(signed portCHAR *)"TaskStart",
TASK_START_STACK_SIZE,
NULL,
TASK_START_PRIORITY,
NULL );
vTaskStartScheduler(); /* Start the scheduler. */
while(1);
}
{
HWSetup(); /* 硬件初始化 */
bpool(mHeap,configTOTAL_HEAP_SIZE); /* heap initialize */
xTaskCreate( vTaskStart, /* Create the first task */
(signed portCHAR *)"TaskStart",
TASK_START_STACK_SIZE,
NULL,
TASK_START_PRIORITY,
NULL );
vTaskStartScheduler(); /* Start the scheduler. */
while(1);
}
可以看到,先进行了硬件初始化和堆的初始化,后建立一个任务,再往后就是任务调度。
再找到任务调度的函数(属于内核,在task.c中),首先又建立一个Idle Task:
xReturn = xTaskCreate( prvIdleTask, ( signed char * ) "IDLE", tskIDLE_STACK_SIZE, ( void * ) NULL, (
xReturn = xTaskCreate( prvIdleTask, ( signed char * ) "IDLE", tskIDLE_STACK_SIZE, ( void * ) NULL, (
tskIDLE_PRIORITY | portPRIVILEGE_BIT ), ( xTaskHandle * ) NULL );
经过少量的初始化操作,在一个if语句中调用了 xPortStartScheduler()函数,开始任务的调度。
注意,此时中断是关闭的。而且系统中现在已存在两个任务,一个是我们建立的任务,一个是在任务调度时建立的IdleTask.每个任务对应着一个TCB(任务控制块)。
注意,此时中断是关闭的。而且系统中现在已存在两个任务,一个是我们建立的任务,一个是在任务调度时建立的IdleTask.每个任务对应着一个TCB(任务控制块)。
然后找到 xPortStartScheduler()函数的定义(在port.c文件中):
portBASE_TYPE xPortStartScheduler( void )
{
/* Make PendSV and SysTick the lowest priority interrupts. */
*(portNVIC_SYSPRI2) |= portNVIC_PENDSV_PRI;
*(portNVIC_SYSPRI2) |= portNVIC_SYSTICK_PRI;
portBASE_TYPE xPortStartScheduler( void )
{
/* Make PendSV and SysTick the lowest priority interrupts. */
*(portNVIC_SYSPRI2) |= portNVIC_PENDSV_PRI;
*(portNVIC_SYSPRI2) |= portNVIC_SYSTICK_PRI;
/* Start the timer that generates the tick ISR. Interrupts are disabled
here already. */
prvSetupTimerInterrupt();
/* Initialise the critical nesting count ready for the first task. */
uxCriticalNesting = 0;
here already. */
prvSetupTimerInterrupt();
/* Initialise the critical nesting count ready for the first task. */
uxCriticalNesting = 0;
/* Start the first task. */
vPortStartFirstTask();
vPortStartFirstTask();
/* Should not get here! */
return 0;
}
设定两个中断的优先级,然后打开时钟中断,才到了最关键的一句:vPortStartFirstTask();
return 0;
}
设定两个中断的优先级,然后打开时钟中断,才到了最关键的一句:vPortStartFirstTask();
此函数定义在portasm.s中,用汇编写的:
vPortStartFirstTask
/* Use the NVIC offset register to locate the stack. */
ldr r0, =0xE000ED08
ldr r0, [r0]
ldr r0, [r0]
/* Set the msp back to the start of the stack. */
msr msp, r0
/* Call SVC to start the first task. */
svc 0
最后一行:svc是一个系统调用,也就是说产生一个系统中断。那我们看看系统中断的中断服务程序是怎么写的(同样在portasm.s中):
vPortSVCHandler;
ldr r3, =pxCurrentTCB
ldr r1, [r3]
ldr r0, [r1]
ldmia r0!, {r4-r11}
msr psp, r0
mov r0, #0
msr basepri, r0
orr r14, r14, #13
bx r14
vPortStartFirstTask
/* Use the NVIC offset register to locate the stack. */
ldr r0, =0xE000ED08
ldr r0, [r0]
ldr r0, [r0]
/* Set the msp back to the start of the stack. */
msr msp, r0
/* Call SVC to start the first task. */
svc 0
最后一行:svc是一个系统调用,也就是说产生一个系统中断。那我们看看系统中断的中断服务程序是怎么写的(同样在portasm.s中):
vPortSVCHandler;
ldr r3, =pxCurrentTCB
ldr r1, [r3]
ldr r0, [r1]
ldmia r0!, {r4-r11}
msr psp, r0
mov r0, #0
msr basepri, r0
orr r14, r14, #13
bx r14
其中用到pxCurrentTCB参数,此参数是指向当前任务TCB的指针,每个任务在建立的时候都会有一个TCB去保存任务的状态等,而TCB的第一个参数就是些任务的堆栈指针,此中断服务程序就利用了堆栈指针位置的关系进行操作,故其位置不可变。。
关于下面的一些操作暂时还没有看明白,明天接着。。。。
关于下面的一些操作暂时还没有看明白,明天接着。。。。