第十六章 RT-Thread 的启动流程
在RTOS 中,主要有两种比较流行的启动方式:
一、万事俱备,只欠东风
1 int main (void)
2 {
3
4 HardWare_Init(); (1)
5
6
7 RTOS_Init(); (2)
8
9 (3)
10 RTOS_ThreadCreate(Task1);
11
12 RTOS_ThreadCreate(Task2);
13
14
15
16
17 RTOS_Start(); (4)
18 }
19
20 void Thread1( void *arg ) (5)
21 {
22 while (1)
23 {
24
25 }
26 }
27
28 void Thread2( void *arg ) (6)
29 {
30 while (1)
31 {
32
33 }
34 }
(1):硬件初始化。硬件初始化这一步还属于裸机的范畴,我们可以把需要使用到的硬件都初始化好而且测试好,确保无误。
(2):RTOS 系统初始化。比如 RTOS 里面的全局变量的初始化,空闲线程的创建等。不同的 RTOS,它们的初始化有细微的差别。
(3):创建各种线程。这里把所有要用到的线程都创建好,但还不会进入调度,因为这个时候 RTOS 的调度器还没有开启。
(4):启动 RTOS 调度器,开始线程调度。这个时候调度器就从刚刚创建好的线程中选择一个优先级最高的线程开始运行。
(5) (6):线程实体通常是一个不带返回值的无限循环的 C 函数,函数体必须有阻塞的情况出现,不然线程(如果优先权恰好是最高)会一直在 while 循环里面执行,导致其它线程没有执行的机会。
二、小心翼翼,十分谨慎
在 main 函数中将硬件和 RTOS 系统先初始化好,然后创建一个启动线程后就启动调度器,然后在启动线程里面创建各种应用线程,当所有线程都创建成功后,启动线程把自己删除。
1 int main (void)
2 {
3
4 HardWare_Init(); (1)
5
6
7 RTOS_Init(); (2)
8
9
10 RTOS_ThreadCreate(AppThreadStart); (3)
11
12
13 RTOS_Start(); (4)
14 }
15
16
17 void AppThreadStart( void *arg ) (5)
18 {
19
20 RTOS_ThreadCreate(Thread1); (6)
21
22
23 RTOS_ThreadCreate(Thread2);
24
25
26
27
28 RTOSThreadClose(AppThreadStart); (7)
29 }
30
31 void Thread1( void *arg ) (8)
32 {
33 while (1)
34 {
35
36 }
37 }
38
39 void Thread2( void *arg ) (9)
40 {
41 while (1)
42 {
43
44 }
45 }
(1):**硬件初始化。来到硬件初始化这一步还属于裸机的范畴,我们可以把需要使用到的硬件都初始化好而且测试好,确保无误。
(2):RTOS 系统初始化。比如 RTOS 里面的全局变量的初始化,空闲线程的创建等。不同的 RTOS,它们的初始化有细微的差别。
(3):创建一个开始线程。然后在这个初始线程里面创建各种应用线程。
(4):启动 RTOS 调度器,开始线程调度。这个时候调度器就去执行刚刚创建好的初始线程。
(5):我们通常说线程是一个不带返回值的无限循环的 C 函数,但是因为初始线程的特殊性,它不能是无限循环的,只执行一次后就关闭。在初始线程里面我们创建我们需要的各种线程。
(6):创建线程。每创建一个线程后它都将进入就绪态,系统会进行一次调度,如果新创建的线程的优先级比初始线程的优先级高的话,那将去执行新创建的线程,当新的线程阻塞时再回到初始线程被打断的地方继续执行。反之,则继续往下创建新的线程,直到所有线程创建完成。
(7):各种应用线程创建完成后,初始线程自己关闭自己,使命完成。
(8) (9):线程实体通常是一个不带返回值的无限循环的 C 函数,函数体必须有阻塞的情况出现,不然线程(如果优先权恰好是最高)会一直在 while 循环里面
执行,其它线程没有执行的机会。
*
ucos第一种和第二种都可以使用,由用户选择,freertos 和 RT-Thread 则默认使用第二种。
三、RT-Thread 的启动流程
只能在 main 函数里面看到创建线程和启动线程的代码,硬件初始化,系统初始化,启动调度器等信息都看不到。
——原因:因为 RT-Thread 拓展了 main 函数,在 main 函数之前把这些工作都做好了。
系统上电小流程:
**Reset_Handler 函数**
1 Reset_Handler PROC
2 EXPORT Reset_Handler [WEAK]
3 IMPORT SystemInit
4 IMPORT __main
5
6 CPSID I ; 关中断
7 LDR R0, =0xE000ED08
8 LDR R1, =__Vectors
9 STR R1, [R0]
10 LDR R2, [R1]
11 MSR MSP, R2
12 LDR R0, =SystemInit
13 BLX R0
14 CPSIE i ; 开中断
15 LDR R0, =__main
16 BX R0
17 ENDP
若当需要扩展的函数不是 main 的时候,只需要将 main 换成你要扩展的函数名即可,即
S
u
b
Sub
Sub
f
u
n
c
t
i
o
n
和
function和
function和Super$$function
**$Sub$$和$Super$$的使用方法**
1 extern void ExtraFunc(void);
2
3
4 void $Sub$$function(void)
5 {
6 ExtraFunc();
7 $Super$$function();
8 }
9
10
14 void function(void)
15 {
16
17 }
1、$Sub$$main
函数
1 int $Sub$$main(void)
2 {
3 rt_hw_interrupt_disable();
4 rtthread_startup(); (2)
5 return 0;
6 }
2、rtthread_startup()
函数
1 int rtthread_startup(void)
2 {
3
4 rt_hw_interrupt_disable(); (1)
5
6
9 rt_hw_board_init(); (2)
10
11
12 rt_show_version(); (3)
13
14
15 rt_system_timer_init(); (4)
16
17
18 rt_system_scheduler_init(); (5)
19
20 #ifdef RT_USING_SIGNALS
21
22 rt_system_signal_init(); (6)
23 #endif
24
25
26 rt_application_init(); (7)
27
28
29 rt_system_timer_thread_init(); (8)
30
31
32 rt_thread_idle_init(); (9)
33
34
35 rt_system_scheduler_start(); (10)
36
37
38 return 0; (11)
39 }
(1):关中断。在硬件初始化之前把中断关闭是一个很好的选择,如果没有关闭中断,在接下来的硬件初始化中如果某些外设开启了中断,那么它就有可能会响应,可是后面的 RTOS 系统初始化,调度器初始化这些都还没有完成,显然这些中断我们是不希望响应的。
(2):板级硬件初始化。RT-Thread 把板级硬件相关的初始化都放在rt_hw_board_int()函数里面完成 ,该函数需要用户在 board.c 实现。
(3):打印 RT-Thread 的版本号,该函数在 kservice.c 中实现
(4):定时器初始化,实际上就是初始化一个全局的定时器列表,列表里面存放的是处于延时状态的线程。
(5):调度器初始化。
(6):信号初始化,
(7):创建初始线程。
3、rt_application_init()
函数
**创建初始线程**
1 (2)
2 #define RT_USING_USER_MAIN
3 #define RT_MAIN_THREAD_STACK_SIZE 256
4 #define RT_THREAD_PRIORITY_MAX 32
5
6 (4)
7 #ifdef RT_USING_USER_MAIN
8 #ifndef RT_MAIN_THREAD_STACK_SIZE
9 #define RT_MAIN_THREAD_STACK_SIZE 2048
10 #endif
11 #endif
12
13 #ifndef RT_USING_HEAP
14 ALIGN(8)
15 static rt_uint8_t main_stack[RT_MAIN_THREAD_STACK_SIZE];
16 struct rt_thread main_thread;
17 #endif
18
19 void rt_application_init(void)
20 {
21 rt_thread_t tid;
22
23 #ifdef RT_USING_HEAP
24 (1)
25 tid =
26 rt_thread_create("main",
27 main_thread_entry,
28 RT_NULL,
29 RT_MAIN_THREAD_STACK_SIZE,
30 RT_THREAD_PRIORITY_MAX / 3, (初始线程优先级)
31 20);
32 RT_ASSERT(tid != RT_NULL);
33 #else
34 (3)
35 rt_err_t result;
36
37 tid = &main_thread;
38 result =
39 rt_thread_init(tid,
40 "main",
41 main_thread_entry,
42 RT_NULL,
43 main_stack,
44 sizeof(main_stack),
45 RT_THREAD_PRIORITY_MAX / 3, (初始线程优先级)
46 20);
47 RT_ASSERT(result == RT_EOK);
48 (void)result;
49 #endif
50
51
52 rt_thread_startup(tid); (6)
53 }
54
55
56
57 void main_thread_entry(void *parameter) (5)
58 {
59 extern int main(void);
60 extern int $Super$$main(void);
61
62
63 rt_components_init();
64
65
66 $Super$$main();
67 }
(1):创建初始线程的时候,分使用动态内存和静态内存两种情况,这是使用动态内存,有关动态内存需要用到的宏定义具体见代码清单 (2)。
(3):创建初始线程的时候,分使用动态内存和静态内存两种情况,这里是使用静态内存,有关静态内存需要用到的宏定义具体见代码清单 (4)。
4、$Super$$main()
函数
(5):初始线程入口
(6):启动初始线程
(初始线程优先级):初始线程的优先级默认配置为最大优先级/3。控制最大优先级的宏 RT_THREAD_PRIORITY_MAX 在 rt_config.h 中定义,目前配置为 32 ,那初始线程的优先级即是 10
5、main()
函数
main 函数里面只是创建并启动一些线程
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)