【MCU ATS3231】炬芯APP启动分析
WLMIC -- Wireless microphone 无线麦。firmware.xml -- 磁盘分区表信息定义。bootloader.ini -- bootloader程序的配置文件。如何在boot中生效?ats3231L_dvb_ext_nor.dts -- 板型对应的设备树。ats3231L_dvb_ext_nor-pinctrl.dtsi -- 板型对应的 GPIO 复用配置。app.
目录
1、前言
WLMIC -- Wireless microphone 无线麦。
firmware.xml -- 磁盘分区表信息定义。
bootloader.ini -- bootloader程序的配置文件。如何在boot中生效?
ats3231L_dvb_ext_nor.dts -- 板型对应的设备树。
ats3231L_dvb_ext_nor-pinctrl.dtsi -- 板型对应的 GPIO 复用配置。
app.conf -- 编译方案所需要的编译宏配置。
2、概述
BROM -- IC 中的 ROM,其中固化了 IC 上电后要运行的一段程序,这段程序包含如下功能:
Power on -- 首先会把CPU 的 SP 设置为 0x01007ff0(SRAM 地址),然后对硬件进行初始化操作, 选择 HOSC时钟作为 CPU 频率运行,完成后跳转到 Bootloader Launcher 运行。
Bootloader launcher -- 从 norflash 上搜索 mbrec 时, 会到若干个不同位置去读取有效的mbrec 到 sram地址(0x01004000)校验通过后就会将控制权交给 mbrec, mbrec 在 sram 中运行。
Storage driver -- 读存储介质驱动程序,支持 spinor 启动;
ADFU launcher -- Adfu 的全称 actions device firmware upgrade(通过 usb 或 uart 烧录固件)
mbrec -- 不 开 源以 二 进 制 方 式 提 供 。 编 译 后 放 在 sdk 的 板 型 下 :mbrec.bin; 配置文件 bootloader.ini。主要功能:硬件进一步的初始化,包括 pmu 初始化, cpu 跑 48MHZ, spi nor 跑 32MHz, delaychain配置为 8ns, vdd 设置到 1.15v。 初始化打印串口,校验 bootloader,校验通过后跳转到 bootloader 运行。
bootloader -- nor 上 xip 运行。recovery 功能检查 fw0_temp 分区是否存在有效的 ota 升级镜像,如果存在,则执行镜像 code 到 fw0_sys 分区的拷贝(中间存在数据的解压,甚至再加密过程)recovery 运行虚地址固定在 0x11000000,其在 nor 上的位置也是固定的(0x6000)分区表 recovery 的地址是固定 0x6000。recovery 无论是否做 ota 镜像拷贝,最后阶段都跳转开始执行 zephyr(app)系统,具体跳转位置在 zephyr\arch\arm\core\aarch32\cortex_m\reset.S 中的 z_arm_reset。

3、内存映射
SRAM空间使用定义:
CONFIG_SRAM_SIZE=251
CONFIG_SRAM_BASE_ADDRESS=0x21001400
代码都在是放在SPI0 NOR,空间使用定义:
CONFIG_FLASH_BASE_ADDRESS=0x10000000
CONFIG_FLASH_SIZE=4096

4、中断向量
cortex_m\vector_table.S文件定义向量。
SECTION_SUBSEC_FUNC(exc_vector_table,_vector_table_section,_vector_table)
/*
* setting the _very_ early boot on the main stack allows to use memset
* on the interrupt stack when CONFIG_INIT_STACKS is enabled before
* switching to the interrupt stack for the rest of the early boot
*/
.word z_main_stack + CONFIG_MAIN_STACK_SIZE
.word z_arm_reset
.word z_arm_nmi
.word z_arm_hard_fault
#if defined(CONFIG_ARMV6_M_ARMV8_M_BASELINE)
.word 0
.word 0
.word 0
.word 0
.word 0
.word 0
.word 0
.word z_arm_svc
.word 0
#elif defined(CONFIG_ARMV7_M_ARMV8_M_MAINLINE)
.word z_arm_mpu_fault
.word z_arm_bus_fault
.word z_arm_usage_fault
#if defined(CONFIG_ARMV8_M_SE)
#if defined(CONFIG_ARM_SECURE_FIRMWARE)
.word z_arm_secure_fault
#else
.word z_arm_exc_spurious
#endif /* CONFIG_ARM_SECURE_FIRMWARE */
#else
.word 0
#endif /* CONFIG_ARMV8_M_SE */
.word 0
.word 0
.word 0
.word z_arm_svc
.word z_arm_debug_monitor
#else
#error Unknown ARM architecture
#endif /* CONFIG_ARMV6_M_ARMV8_M_BASELINE */
.word 0
#if defined(CONFIG_MULTITHREADING)
.word z_arm_pendsv
#else
.word z_arm_exc_spurious
#endif
#if defined(CONFIG_CPU_CORTEX_M_HAS_SYSTICK)
#if defined(CONFIG_SYS_CLOCK_EXISTS) && \
defined(CONFIG_CORTEX_M_SYSTICK_INSTALL_ISR)
.word sys_clock_isr
#else
.word z_arm_exc_spurious
#endif /* CONFIG_SYS_CLOCK_EXISTS && CONFIG_CORTEX_M_SYSTICK_INSTALL_ISR */
#else
.word 0
#endif /* CONFIG_CPU_CORTEX_M_HAS_SYSTICK */
5、复位中断
cortex_m\reset.S
SECTION_SUBSEC_FUNC(TEXT,_reset_section,z_arm_reset)
/*
* The entry point is located at the z_arm_reset symbol, which
* is fetched by a XIP image playing the role of a bootloader, which jumps to
* it, not through the reset vector mechanism. Such bootloaders might want to
* search for a __start symbol instead, so create that alias here.
*/
SECTION_SUBSEC_FUNC(TEXT,_reset_section,__start)
#if defined(CONFIG_DEBUG_THREAD_INFO)
/* Clear z_sys_post_kernel flag for RTOS aware debuggers */
movs.n r0, #0
ldr r1, =z_sys_post_kernel
strb r0, [r1]
#endif /* CONFIG_DEBUG_THREAD_INFO */
#if defined(CONFIG_INIT_ARCH_HW_AT_BOOT)
/* Reset CONTROL register */
movs.n r0, #0
msr CONTROL, r0
isb
#if defined(CONFIG_CPU_CORTEX_M_HAS_SPLIM)
/* Clear SPLIM registers */
movs.n r0, #0
msr MSPLIM, r0
msr PSPLIM, r0
#endif /* CONFIG_CPU_CORTEX_M_HAS_SPLIM */
#endif /* CONFIG_INIT_ARCH_HW_AT_BOOT */
#if defined(CONFIG_PM_S2RAM)
bl arch_pm_s2ram_resume
#endif /* CONFIG_PM_S2RAM */
#if defined(CONFIG_PLATFORM_SPECIFIC_INIT)
bl z_arm_platform_init
#endif
#if defined(CONFIG_INIT_ARCH_HW_AT_BOOT)
#if defined(CONFIG_CPU_HAS_ARM_MPU)
/* Disable MPU */
movs.n r0, #0
ldr r1, =_SCS_MPU_CTRL
str r0, [r1]
dsb
#endif /* CONFIG_CPU_HAS_ARM_MPU */
ldr r0, =z_main_stack + CONFIG_MAIN_STACK_SIZE
msr msp, r0
/* Initialize core architecture registers and system blocks */
bl z_arm_init_arch_hw_at_boot
#endif /* CONFIG_INIT_ARCH_HW_AT_BOOT */
/* lock interrupts: will get unlocked when switch to main task */
#if defined(CONFIG_ARMV6_M_ARMV8_M_BASELINE)
cpsid i
#elif defined(CONFIG_ARMV7_M_ARMV8_M_MAINLINE)
movs.n r0, #_EXC_IRQ_DEFAULT_PRIO
msr BASEPRI, r0
#else
#error Unknown ARM architecture
#endif
#ifdef CONFIG_WDOG_INIT
/* board-specific watchdog initialization is necessary */
bl z_arm_watchdog_init
#endif
/*
*
* Note: in all Cortex-M variants the interrupt stack area is at
* least equal to CONFIG_ISR_STACK_SIZE + MPU_GUARD_ALIGN_AND_SIZE
* (may be larger due to rounding up for stack pointer aligning
* purposes but this is sufficient during initialization).
*/
#ifdef CONFIG_INIT_STACKS
ldr r0, =z_interrupt_stacks
ldr r1, =0xaa
ldr r2, =CONFIG_ISR_STACK_SIZE + MPU_GUARD_ALIGN_AND_SIZE
bl z_early_memset
#endif
/*
* Set PSP and use it to boot without using MSP, so that it
* gets set to z_interrupt_stacks during initialization.
*/
ldr r0, =z_interrupt_stacks
ldr r1, =CONFIG_ISR_STACK_SIZE + MPU_GUARD_ALIGN_AND_SIZE
adds r0, r0, r1
msr PSP, r0
mrs r0, CONTROL
movs r1, #2
orrs r0, r1 /* CONTROL_SPSEL_Msk */
msr CONTROL, r0
/*
* When changing the stack pointer, software must use an ISB instruction
* immediately after the MSR instruction. This ensures that instructions
* after the ISB instruction execute using the new stack pointer.
*/
isb
/*
* 'bl' jumps the furthest of the branch instructions that are
* supported on all platforms. So it is used when jumping to z_prep_c
* (even though we do not intend to return).
*/
bl z_prep_c
6、C函数入口
cortex_m\prep_c.c -> z_prep_c()//C环境初始化
void z_prep_c(void)
{
relocate_vector_table();
#if defined(CONFIG_CPU_HAS_FPU)
z_arm_floating_point_init();
#endif
z_bss_zero();
z_data_copy();
#if defined(CONFIG_ARM_CUSTOM_INTERRUPT_CONTROLLER)
/* Invoke SoC-specific interrupt controller initialization */
z_soc_irq_init();
#else
z_arm_interrupt_init();
#endif /* CONFIG_ARM_CUSTOM_INTERRUPT_CONTROLLER */
z_cstart();
CODE_UNREACHABLE;
}
zephyr\kernel\init.c->z_cstart()//初始化zephyr内核
__boot_func
FUNC_NO_STACK_PROTECTOR
FUNC_NORETURN void z_cstart(void)
{
/* gcov hook needed to get the coverage report.*/
gcov_static_init();
/* initialize early init calls */
z_sys_init_run_level(INIT_LEVEL_EARLY);
/* perform any architecture-specific initialization */
arch_kernel_init();
LOG_CORE_INIT();
#if defined(CONFIG_MULTITHREADING)
z_dummy_thread_init(&_thread_dummy);
#endif /* CONFIG_MULTITHREADING */
/* do any necessary initialization of static devices */
z_device_state_init();
/* perform basic hardware initialization */
z_sys_init_run_level(INIT_LEVEL_PRE_KERNEL_1);
#if defined(CONFIG_SMP)
arch_smp_init();
#endif
z_sys_init_run_level(INIT_LEVEL_PRE_KERNEL_2);
#ifdef CONFIG_STACK_CANARIES
uintptr_t stack_guard;
z_early_rand_get((uint8_t *)&stack_guard, sizeof(stack_guard));
__stack_chk_guard = stack_guard;
__stack_chk_guard <<= 8;
#endif /* CONFIG_STACK_CANARIES */
#ifdef CONFIG_TIMING_FUNCTIONS_NEED_AT_BOOT
timing_init();
timing_start();
#endif /* CONFIG_TIMING_FUNCTIONS_NEED_AT_BOOT */
#ifdef CONFIG_MULTITHREADING
switch_to_main_thread(prepare_multithreading());
#else
#ifdef ARCH_SWITCH_TO_MAIN_NO_MULTITHREADING
/* Custom ARCH-specific routine to switch to main()
* in the case of no multi-threading.
*/
ARCH_SWITCH_TO_MAIN_NO_MULTITHREADING(bg_thread_main,
NULL, NULL, NULL);
#else
bg_thread_main(NULL, NULL, NULL);
/* LCOV_EXCL_START
* We've already dumped coverage data at this point.
*/
irq_lock();
while (true) {
}
/* LCOV_EXCL_STOP */
#endif /* ARCH_SWITCH_TO_MAIN_NO_MULTITHREADING */
#endif /* CONFIG_MULTITHREADING */
/*
* Compiler can't tell that the above routines won't return and issues
* a warning unless we explicitly tell it that control never gets this
* far.
*/
CODE_UNREACHABLE; /* LCOV_EXCL_LINE */
}
7、初始化&主程序
enum init_level {
INIT_LEVEL_EARLY = 0,
INIT_LEVEL_PRE_KERNEL_1,
INIT_LEVEL_PRE_KERNEL_2,
INIT_LEVEL_POST_KERNEL,
INIT_LEVEL_APPLICATION,
#ifdef CONFIG_SMP
INIT_LEVEL_SMP,
#endif /* CONFIG_SMP */
};
#define SYS_INIT(init_fn, level, prio) SYS_INIT_NAMED(init_fn, init_fn, level, prio)
//宏定义方式线程注册
#define Z_THREAD_COMMON_DEFINE(name, stack_size, \
entry, p1, p2, p3, \
prio, options, delay) \
struct k_thread _k_thread_obj_##name; \
STRUCT_SECTION_ITERABLE(_static_thread_data, \
_k_thread_data_##name) = \
Z_THREAD_INITIALIZER(&_k_thread_obj_##name, \
_k_thread_stack_##name, stack_size,\
entry, p1, p2, p3, prio, options, \
delay, name); \
const k_tid_t name = (k_tid_t)&_k_thread_obj_##name
//线程创建
char *z_setup_new_thread(struct k_thread *new_thread,
k_thread_stack_t *stack, size_t stack_size,
k_thread_entry_t entry,
void *p1, void *p2, void *p3,
int prio, uint32_t options, const char *name)
//启动调度:
void z_sched_start(struct k_thread *thread)
{
k_spinlock_key_t key = k_spin_lock(&_sched_spinlock);
if (z_has_thread_started(thread)) {
k_spin_unlock(&_sched_spinlock, key);
return;
}
z_mark_thread_as_started(thread);
ready_thread(thread);
z_reschedule(&_sched_spinlock, key);
}
主线程创建
//step1
switch_to_main_thread(prepare_multithreading());
//step1.1
static char *prepare_multithreading(void)
{
char *stack_ptr;
/* _kernel.ready_q is all zeroes */
z_sched_init();
#ifndef CONFIG_SMP
_kernel.ready_q.cache = &z_main_thread;
#endif /* CONFIG_SMP */
//主线程创建
stack_ptr = z_setup_new_thread(&z_main_thread,
z_main_stack,
K_THREAD_STACK_SIZEOF(z_main_stack),
bg_thread_main,//主线程入口。里面调用main()函数。
NULL, NULL, NULL,
CONFIG_MAIN_THREAD_PRIORITY,
K_ESSENTIAL, "main");
z_mark_thread_as_started(&z_main_thread);
z_ready_thread(&z_main_thread);
z_init_cpu(0); //空闲线程创建
return stack_ptr;
}
//step1.2
static FUNC_NORETURN void switch_to_main_thread(char *stack_ptr)
{
#ifdef CONFIG_ARCH_HAS_CUSTOM_SWAP_TO_MAIN
arch_switch_to_main_thread(&z_main_thread, stack_ptr, bg_thread_main);
#else
ARG_UNUSED(stack_ptr);
z_swap_unlocked();
#endif /* CONFIG_ARCH_HAS_CUSTOM_SWAP_TO_MAIN */
CODE_UNREACHABLE; /* LCOV_EXCL_LINE */
}
//step2
static void bg_thread_main(void *unused1, void *unused2, void *unused3)
{
z_init_static_threads();//静态线程创建(通过宏定义方式注册的线程)
……
#ifdef CONFIG_SMP
if (!IS_ENABLED(CONFIG_SMP_BOOT_DELAY)) {
z_smp_init();
}
z_sys_init_run_level(INIT_LEVEL_SMP);
#endif /* CONFIG_SMP */
#ifdef CONFIG_MMU
z_mem_manage_boot_finish();
#endif /* CONFIG_MMU */
extern int main(void);
(void)main();//进入用户主程序
……
}
//主APP注册 —— 在主线程中运行(active)
extern char z_main_stack[CONFIG_MAIN_STACK_SIZE];
APP_DEFINE(main, z_main_stack, CONFIG_MAIN_STACK_SIZE,APP_PRIORITY, NULL, NULL, NULL, NULL);
//BT播放器APP注册 —— 在主线程中运行(active)
char __aligned(ARCH_STACK_PTR_ALIGN) bt_player_stack_area[CONFIG_APP_STACKSIZE];
APP_DEFINE(bt_player, bt_player_stack_area, sizeof(bt_player_stack_area),
CONFIG_APP_PRIORITY, NULL, NULL, NULL, _btplayer_main_loop);
//BT播放器模块注册 —— 基于BT播放器APP
#define BTPLAYER_MODE_DEFINE(mode_id, prio, enter_func, exit_func, msg_proc_func, get_status_func)
8、线程管理
SHELL_CMD_REGISTER(kernel, &sub_kernel, "Kernel commands", NULL);//shell命令注册
SHELL_STATIC_SUBCMD_SET_CREATE(sub_kernel,……);//shell 字命令创建。
查看线程命令:kernel_service.c -> kernel threads
【id】【thread entry】【name】 【create_form】【file】【note】
【1】【data_channel_recv_cmd_process】【NA】【os_thread_create】【main.c-> system_init()->data_channel_manager_init()】【】
【2】【data_channel_send_cmd_process】【NA】【os_thread_create】【main.c-> system_init()->data_channel_manager_init()】【】
【3】【media_service_main_loop】【NA】【SERVICE_DEFINE + os_thread_create】【main.c-> system_init()->media_service_init()】【此类服务都会创建线程;服务定义中有定义线程入口,__service_entry_table】
【4】【input_thread】【input】【K_THREAD_DEFINE+z_init_static_threads + z_setup_new_thread】【init.c】【】
【5】【work_queue_main】【sysworkq】【SYS_INIT(k_sys_work_q_init)+k_thread_create】【system_work_q.c】【SYS_INIT定义不一定会创建线程是由init_fn函数内容决定】
【6】【work_queue_main】【dspworkq】【SYS_INIT(dsp_work_q_init)+k_thread_create】【dsp_mailbox.c】【与dsp通信工作线程】
【7】【work_queue_main】【eccwork】【SYS_INIT(ecc_work_q_init)+k_thread_create】【ecc_acts.c】【】
【8】【work_queue_main】【syslowprioworkq】【SYS_INIT(sys_low_prio_work_q_init) + k_thread_create】【user_work_q.c】【】
【9】【shell_thread】【shell_uart】【SYS_INIT+k_thread_create】【shell_uart.c】【串口shell任务】
【10】【idle】【idle】【z_setup_new_thread】【init.c】【空闲任务】
【11】【bg_thread_main】【main】【z_setup_new_thread】【init.c】【主任务】
更多推荐



所有评论(0)