第二章 分析app_main之前运行了什么代码
文章目录
前言
编译esp-box sdk下的examples下所有官方demo得到bin文件(此点能独立完成后买个官方样机,等样机到手后自行烧录全部demo都试一遍全部功能)。
一、任务是什么?
分析app_main之前运行了什么代码(可以阅读官方文档,阅读后写下来)。
二、代码分析
1.硬件和基本 C 语言运行环境的端口初始化
ESP-IDF 应用程序的入口是 components/esp_system/port/cpu_start.c 文件中的 call_start_cpu0 函数。
该端口层的初始化功能会初始化基本的 C 运行环境 (“CRT”),并对 SoC 的内部硬件进行了初始配置。
- 为应用程序重新配置 CPU 异常(允许应用程序中断处理程序运行,并使用为应用程序配置的选项来处理 严重错误,而不是使用 ROM 提供的简易版错误处理程序处理。
- 如果没有设置选项 CONFIG_BOOTLOADER_WDT_ENABLE,则不使能 RTC 看门狗定时器。
- 初始化内部存储器(数据和 bss)。
- 完成 MMU 高速缓存配置。
- 如果配置了 PSRAM,则使能 PSRAM。
- 将 CPU 时钟设置为项目配置的频率。
- 根据应用程序头部设置重新配置主 SPI flash,这是为了与 ESP-IDF V4.0 之前的引导程序版本兼容,请参考 引导加载程序兼容性。
- 如果应用程序被配置为在多个内核上运行,则启动另一个内核并等待其初始化(在类似的“端口层”初始化函数 call_start_cpu1 内)。
call_start_cpu0 完成运行后,将调用components/esp_system/startup.c 中找到的“系统层”初始化函数 start_cpu0。
其他内核也将完成端口层的初始化,并调用同一文件中的 start_other_cores。
2.软件服务和 FreeRTOS 的系统初始化
主要的系统初始化函数是 start_cpu0。默认情况下,这个函数与 start_cpu0_default 函数弱链接。
这意味着可以覆盖这个函数,增加一些额外的初始化步骤。
主要的系统初始化阶段包括:
- 如果默认的日志级别允许,则记录该应用程序的相关信息(项目名称、应用程序版本 等)。
- 初始化堆分配器(在这之前,所有分配必须是静态的或在堆栈上)。
- 初始化 newlib 组件的系统调用和时间函数。
- 配置断电检测器。
- 根据 串行控制台配置 设置 libc stdin、stdout、和 stderr。
- 执行与安全有关的检查,包括为该配置烧录 efuse(包括 禁用 ESP32 V3 的 ROM 下载模式、CONFIG_ESP32_DISABLE_BASIC_ROM_CONSOLE)。
- 初始化 SPI flash API 支持。
- 调用全局 C++ 构造函数和任何标有 attribute((constructor)) 的 C 函数。
二级系统初始化允许单个组件被初始化。如果一个组件有一个用 ESP_SYSTEM_INIT_FN 宏注释的初始化函数,它将作为二级初始化的一部分被调用。
3.运行主任务并调用 app_main
在所有其他组件都初始化后,主任务会被创建,FreeRTOS 调度器开始运行。
做完一些初始化任务后(需要启动调度器),主任务在固件中运行应用程序提供的函数 app_main。
运行 app_main 的主任务有一个固定的 RTOS 优先级(比最小值高)和一个 可配置的堆栈大小。
与普通的 FreeRTOS 任务(或嵌入式 C 的 main 函数)不同,app_main 任务可以返回。如果app_main
函数返回,那么主任务将会被删除。系统将继续运行其他的 RTOS 任务。因此可以将 app_main 实现为一个创建其他应用任务然后返回的函数,或主应用任务本身。
总结
总之,在 app_main 函数之前会运行一些代码来完成一些初始化和配置操作。以下是 factory_demo 的主要初始化代码:
- 运行 esp_err_t ret = nvs_flash_init() 来初始化非易失性存储(NVS)。
- 运行 esp_log_set_vprintf() 来设置日志输出函数。
- 运行 esp_err_t ret = esp_periph_set_register_callback() 来注册外设回调函数。
- 运行 periph_service_start() 来启动外设服务。
- 运行 esp_err_t ret = esp_periph_set_periph_overcur_callback() 来注册外设过电流回调函数。
- 运行 esp_err_t ret = esp_periph_set_play_finished_callback() 来注册外设播放完成回调函数。
- 运行 wifi_service_init() 来初始化 Wi-Fi 服务。
- 运行 esp_bluedroid_init() 来初始化蓝牙协议栈。
- 运行 esp_bluedroid_enable() 来启用蓝牙协议栈。
- 运行 esp_bt_gap_register_callback() 来注册蓝牙 GAP 回调函数。
- 运行 esp_bt_gap_set_scan_mode() 来设置蓝牙扫描模式。
- 运行 esp_bt_gap_start_discovery() 来开始进行蓝牙设备的扫描。
以上是 factory_demo 在 app_main 函数之前运行的一些代码,用于初始化和配置外设、Wi-Fi 和蓝牙相关的功能。这些代码将设备从启动状态转换为可执行其他操作的状态,为后续的应用程序逻辑做好准备。