esp32c3 hal 架构笔记

构建过程

大量的构建过程都在各个库中的 build.rs 中实现,主要是通过不同的构建目录将预定点的链接文件复制到输出目录中,并通过 cargo:rustc-link-search= 指令将对应的目录加入到链接脚本的查询目录中,最后在构建是 通过 link-arg= 加上指定的入口链接脚本 构建完成的目标文件.

链接脚本的主要作用就是指定程序在内存中的布局

rust 代码入口在 esp-riscv-rt 库中的 lib.rs 中,通过一段内嵌宏实现的入口点,在引导程序bootloader执行完成后会跳转到 _start 入口处。在进入main方法前的代码需要结合 链接脚本中的符号定义进行分析。

跳转过程:

_start -》 _abs_start -》_start_rust

_start_rust 方法对应start_rust 方法,

start_rust方法中顺序调用 __post_init(); _setup_interrupts();main(a0, a1, a2);

fn main 对应到我们定义的main方法

__post_init 对应 default_post_init 方法,这个方法是一个外部方法,置未找到实现位置,

_setup_interrupts = default_setup_interrupts

default_setup_interrupts 中会调用 mtvec::write 设置中断入口为_start_trap

_start_trap = default_start_trap

default_start_trap 定义在汇编部分

代码执行流程大概如下:

通过_start 进入程序后跳转到 _start_rust 汇编处 ,start_rust 中会调用 _setup_interrupts() 设置中断入口,

然后通过main(a0, a1, a2);进入被#[entry]标记的方法中。当有中断触发时会进入default_start_trap

汇编处再跳到 start_trap_rust 中,通过mcause 寄存器判断出是异常还是中断,中断与异常会进入不同的处理方法,

异常会进入ExceptionHandler , 中断会判断中断类型进入不同的handler中,这些handler 都是与相应的中断名称相关联的,

在链接脚本当中会定义所有中断默认为 DefaultInterruptHandler ,这个默认处理中是一空loop,所以我们需要定义不同的

中断处理程序,比如GPIO 中断就定义一个GPIO方法并用 #[interrupt]标记, 中断标记与入口标记类似会导出相应的符号

由对应的程序调用。