💌 所属专栏:【BES2500x系列】
😀 作 者:我是夜阑的狗🐶
🚀 个人简介:一个正在努力学技术的CV工程师,专注基础和实战分享 ,欢迎咨询!
💖 欢迎大家:这里是CSDN,我总结知识的地方,喜欢的话请三连,有问题请私信 😘 😘 😘
您的点赞、关注、收藏、评论,是对我最大的激励和支持!!!🤩 🤩 🤩
前言
大家好,又见面了,我是夜阑的狗🐶,本文是专栏【BES2500x系列】专栏的11篇文章;
今天开始学习BES2500x系列的一天💖💖💖,开启新的征程,记录最美好的时刻🎉,每天进步一点点。
专栏地址:【BES2500x系列】, 此专栏是我是夜阑的狗对BES2500x系列开发过程的总结,希望能够加深自己的印象,以及帮助到其他的小伙伴😉😉。
如果文章有什么需要改进的地方还请大佬不吝赐教👏👏。
1 系统初始化
前面学习了嵌入式系统启动的基本流程,可以分为 引导程序
和 系统初始化程序
这两部分,并对引导程序 boot loader
进行了详细讲解。接下来就来 系统初始化程序
是怎么跑的吧。话不多说,让我们原文再续,书接上回吧。
1.1 系统启动(System Startup)
mian
函数不再以一个线程的形式运行,因此在 main
函数运行之前,RTX5 不会干预系统的启动。main
函数运行之后,推荐按照以下的流程初始化硬件并启动内核:
Step1、硬件的初始化和配置,包括外设,内存,引脚,时钟和中断系统。
Step2、使用 CMSIS-Core
函数更新系统核心时钟。
Step3、使用 osKernelInitialize
函数初始化 CMSIS-RTOS
内核。
Step4、使用 osThreadNew
函数创建一个主线程(例如 app_mian
),然后在这个线程中创建和启动对象。当然也可以直接在main函数中创建和启动对象。
Step5、使用 OSKernelStart
启动 RTOS
调度器,该函数会配置 system tick
定时器以及初始化 RTOS 相关中断。如果这个函数运行成功,则不会在返回,因此该函数之后的代码将不会被执行。
🚨 🚨 🚨 注意:在上述流程之后,不推荐应用程序修改NVIC的优先级和分组;在执行 osKernelStart
之前,只能调用 osKernelGetInfo
、osKernelGetState
和对象创建函数(osXxxNew
)。
- 代码
__WEAK void software_init_hook (void) {
__asm (
".syntax unified\n"
".thumb\n"
"movs r0,#0\n"
"movs r1,#0\n"
"mov r4,r0\n"
"mov r5,r1\n"
"bl SystemCoreClockUpdate\n"
"bl osKernelInitialize\n"
"ldr r0,= __libc_fini_array\n"
"bl atexit\n"
"bl __libc_init_array\n"
"mov r0,r4\n"
"mov r1,r5\n"
"bl set_main_stack\n"
"ldr r0,=main\n"
"movs r1,#0\n"
"ldr r2,=os_thread_attr_main\n"
"bl osThreadNew\n"
"bl osKernelStart\n"
"bl exit\n"
);
}
- 参数/函数讲解
这段代码是一个软件初始化钩子函数,使用了 __WEAK
关键字,表示这是一个弱符号,允许在其他地方重新定义同名函数。函数内部包含了一段嵌入式汇编代码,执行了一系列初始化操作,主要用于系统启动时进行一些必要的初始化工作。
序号 | 汇编指令 | 说明 |
---|---|---|
1 | .syntax unified 和 .thumb | 指定汇编语法和指令集。在这里,使用了 Thumb 指令集。 |
2 | movs r0,#0 和 movs r1,#0 | 用于将寄存器 r0 和 r1 中的值设置为 0。 |
3 | mov r4,r0 和 mov r5,r1 | 将 r0 和 r1 中的值分别复制到 r4 和 r5 寄存器中。 |
4 | bl SystemCoreClockUpdate | 调用 SystemCoreClockUpdate 函数更新系统核心时钟。 |
5 | bl osKernelInitialize | 调用 osKernelInitialize 函数初始化操作系统内核。 |
6 | ldr r0,= __libc_fini_array | 加载 __libc_fini_array 的地址到寄存器 r0。 |
7 | bl atexit | 调用 atexit 注册退出处理函数。 |
8 | bl __libc_init_array | 调用 __libc_init_array 函数初始化 C 库数组。 |
9 | mov r0,r4 | 将 r4 中的值分别复制回 r0 寄存器中。 |
10 | mov r1,r5 | 将 r5 中的值分别复制回 r1 寄存器中。 |
11 | bl set_main_stack | 调用 set_main_stack 函数设置主栈。 |
12 | ldr r0,=main | 加载 main 函数的地址到寄存器 r0,并调用 osThreadNew 创建主线程。 |
13 | movs r1,#0 | 将常量值 0 移动到寄存器 r1 |
14 | ldr r2,=os_thread_attr_main | 加载 os_thread_attr_main 的地址到寄存器 r2 |
15 | bl osThreadNew | 调用 osThreadNew 创建主线程,这个过程用于初始化操作系统的线程环境,将 main 函数作为新线程的入口点。 |
16 | bl osKernelStart | 调用 osKernelStart 启动操作系统内核。 |
17 | bl exit | 调用 exit 函数以退出程序 |
1.2 系统 main 函数
执行完成这些创建好主线程后,就能来到 main
函数了,因为第一个线程os_thread_attr_main
就是 main
,可以在 main.cpp
文件中看到该 main
函数。
- 代码
这里由于 main
函数代码过多,这里不就放出来了,只讲解一下其中的各个函数作用。
int main(void)
{
uint8_t sys_case = 0;
int ret = 0;
#if !defined(BLE_ONLY_ENABLED)
app_wdt_open(15);
#else
app_wdt_open(30);
#endif
......省略后续
......
}
注意:该函数并不是完整的函数,只截取部分代码
- 参数/函数讲解
main
函数详细讲解,这些函数调用涉及到了系统的初始化、配置以及关机过程的一些操作:
序号 | 参数/函数 | 说明 |
---|---|---|
1 | app_wdt_open(30) | 开启打开应用程序看门狗定时器,间隔为30秒; |
2 | tgt_hardware_setup() | 硬件初始化,输入输出IO初始化; |
3 | osThreadGetId() | 返回当前线程ID; |
4 | hwtimer_init(void) | 初始化硬件定时器,用于在系统中进行定时操作或者时钟管理; |
5 | hal_dma_set_delay_func | 设置了一个 DMA(Direct Memory Access,直接内存访问)延迟函数,它将 osDelay 函数作为参数传入。这通常是为了在 DMA 操作中引入延迟,以便与其他系统操作进行同步。 |
6 | hal_audma_open() | 初始化音频 DMA,即用于音频数据传输的 DMA 控制器。 |
7 | hal_gpdma_open() | 初始化通用 DMA(General Purpose DMA,通用目的 DMA),用于处理非音频数据的高速数据传输。 |
8 | norflash_api_init() | 初始化 NOR Flash 存储器,把 flash 中从 0 到NORFLASH_API_MODULE_ID_COUNT 的空间清零,以便系统能够正确地与 NOR Flash 进行通信和操作。 |
9 | hal_iomux_set_uart0() | 设置 UART0 的 I/O 多路复用(I/O Multiplexing),以确保 UART0 的引脚正确配置为 UART 功能,从而可以进行串口通信 |
10 | hal_trace_open | 打开了追踪功能,并指定了 UART0 作为传输通道。追踪功能通常用于在调试或日志记录时输出系统状态、错误信息等,简单点就是打开串口。 |
11 | hal_iomux_ispi_access_init() | 初始化 SPI(Serial Peripheral Interface,串行外设接口)的 I/O 多路复用,以确保 SPI 接口的引脚正确配置,并且可以被使用。 |
12 | hal_iomux_ispi_access_disable() | 禁用 SPI 接口的访问。可能在某些情况下,系统需要在初始化时先禁用 SPI 接口,待需要时再启用。 |
13 | pmu_open() | 初始化电源管理单元(PMU),以便系统能够正确管理电源,包括电池管理、供电管理等。 |
14 | analog_open() | 初始化模拟外设,例如模拟输入输出、模拟信号处理等。 |
15 | mpu_setup() | 设置 MPU(Memory Protection Unit,内存保护单元),以保护系统的内存不受未经授权的访问和修改。具体操作是先open mpu() 然后mpu_init_table() ,mpu_fast_ram_protect() |
16 | srand(hal_sys_timer_get()) | 设置了随机数发生器的种子,通常使用系统时钟来生成一个初始种子,以便在后续的随机数生成中产生不同的随机序列。 |
17 | app_audio_buffer_check() | 检查音频缓冲区的状态,以确保音频数据的准备和处理工作正常进行。 |
18 | app_init() | 应用程序的初始化函数,用于执行应用程序的各种初始化任务,例如初始化变量、配置参数等。 |
19 | system_shutdown_wdt_config(10) | 配置了系统的看门狗定时器(Watchdog Timer,WDT),设置了定时器的超时时间为10秒。看门狗定时器通常用于监视系统运行状态,如果系统出现异常或停滞,超过了设置的时间,系统会自动重启以恢复正常运行。 |
20 | app_deinit(ret) | 在应用程序结束时进行一些清理工作, |
21 | hal_sw_bootmode_clear() | 清除软件引导模式(Software Boot Mode)的状态,以确保系统下次启动时不会处于特定的引导模式下。 |
22 | pmu_shutdown() | 关闭电源管理单元(PMU),以准备系统关机。 |
总结
感谢观看,这里就是 系统初始化 – main函数的讲解,如果觉得有帮助,请给文章点个赞吧,让更多的人看到。🌹 🌹 🌹
也欢迎你,关注我。👍 👍 👍
原创不易,还希望各位大佬支持一下,你们的点赞、收藏和留言对我真的很重要!!!💕 💕 💕 最后,本文仍有许多不足之处,欢迎各位认真读完文章的小伙伴们随时私信交流、批评指正!下期再见。🎉
更多专栏订阅:
订阅更多,你们将会看到更多的优质内容!!