2-BIOS&mbedOS启动过程

芯片启动后转向用户程序、操作系统的过程

上一章介绍了芯片启动后的过程,芯片上电后开始启动执行到无操作系统主函数main(07_NosPrg\main.cpp)前。那么针对于BIOS最小系统和mbedOS的跳转过程如下:

1. BIOS最小系统的跳转

BIOS的main函数如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
int main(void)
{
//(1)======启动部分(开头)============================================
//(1.1)声明main函数使用的局部变量(声明时不准赋值)
uint_8 muFlag; //更新状态标志
uint_32 mCount; //延时计数变量

//(1.2)【不变】关总中断
DISABLE_INTERRUPTS;

//(1.3)给全局变量及主函数使用的局部变量赋初值
muFlag=0; //更新状态标志=0,默认进入User
mCount=0; //延时计数变量
if (IS_POWERON_RESET) //若是冷复位,给有关全局变量赋初值
{
gFunFlag = 0; //更新操作提示初始化
gCount=0; //500ms计数单元
gTime=0; //全局时间戳,复位计时初始化
Rst_Count = 0; //按“复位键”的次数
memcpy((void*)gcUpdateFlag,"POWSTART\0",9); //初始化字符串,默认进入User
}

//(1.4)初始化外设模块
gpio_init(LIGHT_GREEN,GPIO_OUTPUT,LIGHT_OFF); //初始化BIOS运行指示灯
emuart_init(UART_UPDATE,115200); //初始化BIOS程序更新串口
timer_init(TIMER_BIOS,20); //初始化BIOS定时器
flash_init(); //初始化Flash构件
shakeDataInit(); //初始化握手数据

//(1.5)使能模块中断
uart_enable_re_int(UART_UPDATE); //使能UART_UPDATE模块中断
timer_enable_int(TIMER_BIOS); //使能BIOS定时器中断

//(1.6)【不变】开总中断
ENABLE_INTERRUPTS; //开总中断
//(1.7)按键复位判断
pin_reset_judge(); //如果短时间发生了多次按键复位,则不进入用户程序

//(1.8)判断是否需要进行更新操作
muFlag = updateJudge();
if(muFlag != 0) gFunFlag = 1; //需进行更新提示操作
else gcRecvLen = 0;

//(1)======启动部分(结尾)============================================

//(2)======主循环部分(开头)==========================================
for(;;)
{
switch(gFunFlag) //根据gFunFlag跳转执行
{
case 0: //无需更新数据,跳转User程序执行
gpio_set(LIGHT_GREEN,LIGHT_OFF); //关闭绿灯
uart_send_string (UART_UPDATE," 【BIOS提示信息】:USER程序开始运行...\r\n");
user_reset(GEC_USERBASE); //跳转User程序
break;
case 1: //需进行更新提示操作
gFunFlag = 10;
break;
default: //其他情况,绿灯闪烁,提示处于BIOS程序
mCount++;
if(mCount > 0x5fffff)
{
mCount = 0;
gpio_reverse(LIGHT_GREEN);
}
}
}
//(2)======主循环部分(结尾)==========================================
return 0;
}

那么,在上述代码中,有两处关键代码 pin_reset_judge();user_reset(GEC_USERBASE);

pin_reset_judge();

代码进行的是复位引脚被触碰了几次,本例子中以6次为限,触碰6次则程序返回BIOS中。

那么上一章所提的BSS段被注释掉就是希望芯片启动后不清楚某些全局变量的状态,如果芯片复位标志被置位,说明已触碰6次,那么就不会跳转到GEC_USERBASE用户区。反之,芯片启动后会直接跳转到用户区。具体流程见后续章节。

user_reset(GEC_USERBASE);

这段代码会让芯片直接跳转到用户区,GEC_USERBASE是用户区的首地址。

2. mbedOS的跳转

​ main 函数开始 mbedOS 的启动,我们把 mbedOS 启动过程梳理到一个函数中运行,由 main 函数来调用,这个函数原型为:

1
2
3
4
5
mbedOS_start(osThreadId_t &thd, void (*func)(void))。
//该函数有两个参数
//thd 为将要运行的主线程控制块的引用
//func为主线程执行的实际函数
//实际调用时为 mbedOS_start(thd_main,*app_init)。

​ mbedOS 进入 main 函数之后,调用 mbedOS 的启动函数,mbedOS 就开始启动,并无休无止地开始运行,进行任务调度。

mbedOS_start 函数是 mbedOS 启动过程函数

其主要任务是:

1.设置 mbedOS 堆栈区

2.重定向中断向量表

3.完成内核初始化

4.建立互斥信号

5.创建主线程和启动内核

类似于BIOS,在main函数中会直接调用mbedOS_start这个函数跳转到mbedOS的首地址处。

当内核启动成功后,函数 svcRtxKernelStart 执行完成返回到 SVC 中断中,进行上下文切换,返回到定时器线程中执行。定时器线程 osRtxInfo.timer.thread 运行后会进入阻塞状态,此时 mbedOS 会选择就绪队列中优先级最高的线程,即主线程 main_thread,使其进入激活态。

主线程被调度运行时,其执行函数 app_init主要负责完成初始化外设模块、初始化全局变量、使能中断模块、创建并启动其他用户线程、阻塞主线程的功能,之后的线程运行和切换都由 mbedOS 调度完成