前言
memfault有这么一篇文章:
From Zero to main(): Bare metal C
这个文章的措辞本身就很有意思,bare metal,裸露金属,表示原生的C。 文章开头还用了莎翁式的古英语:
- The entry point of thy program shall be named “main”.
你的程序的入口点应命名为“main”。
- Thou shalt initialize thy static variables, else The Machine shall set them to zero.
你必须自行初始化静态变量,否则系统会将其设置为零。
- Thou shalt implement The Interrupts. HardFault_Handler chief among them, but also SysTick_Handler.
你必须实现各种中断处理程序。其中,HardFault_Handler 是最重要的,SysTick_Handler 也同样重要
(这里的thou =you,shelt=shell,是圣经口吻的古英语)
于是它很快就引起了我的兴趣。是从什么时候开始,我们把标准库,startup当成真理一样崇拜与遵循?我们是不是缺失了一堂课,一堂告诉我们真正的嵌入式是什么的课? 所以我在这里写这篇文章,记录,学习到底什么是真正有趣的嵌入式。
祂说:要有电
显然MCU是从上电开始运行的。但是上电之后发生了什么?原作是用Atmel 公司的 SAMD21G18 处理器(Cortex-M0+内核,和rp2040一样)做例子的,参考的是ARMv6-M 架构参考手册,我这里用ARMv7-M来替代,在B1.5.5 Reset behavior这一节里记录着:
// TakeReset()
// ============
TakeReset()
CurrentMode = Mode_Thread;
PRIMASK<0> = '0';
FAULTMASK<0> = '0';
/* priority mask cleared at reset */
/* fault mask cleared at reset */
BASEPRI<7:0> = Zeros(8); /* base priority disabled at reset */
if HaveFPExt() then /* initialize the Floating Point Extn */
CONTROL<2:0> = '000'; /* FP inactive, stack is Main, thread is privileged */
CPACR.cp10 = '00';
CPACR.cp11 = '00';
FPDSCR.AHP = '0';
FPDSCR.DN = '0';
FPDSCR.FZ = '0';
FPDSCR.RMode = '00';
FPCCR.ASPEN = '1';
FPCCR.LSPEN = '1';
FPCCR.LSPACT = '0';
FPCAR = bits(32) UNKNOWN;
FPFSR = bits(32) UNKNOWN;
for i = 0 to 31
S[i] = bits(32) UNKNOWN;
else
CONTROL<1:0> = '00'; /* current stack is Main, thread is privileged */
for i = 0 to 511 /* all exceptions Inactive */
ExceptionActive[i] = '0';
ResetSCSRegs(); /* catch-all function for System Control Space reset */
ClearExclusiveLocal(ProcessorID()); /* Synchronization (LDREX* / STREX*) monitor support */
ClearEventRegister(); /* see WFE instruction for more details */
for i = 0 to 12
R[i] = bits(32) UNKNOWN;
bits(32) vectortable = VTOR<31:7>:'0000000';
SP_main = MemA_with_priv[vectortable, 4, AccType_VECTABLE] AND 0xFFFFFFFC<31:0>;
SP_process = ((bits(30) UNKNOWN):'00');
LR = 0xFFFFFFFF<31:0>; /* preset to an illegal exception return value */
tmp = MemA_with_priv[vectortable+4, 4, AccType_VECTABLE];
tbit = tmp<0>;
APSR = bits(32) UNKNOWN; /* flags UNPREDICTABLE from reset */
IPSR<8:0> = Zeros(9); /* Exception Number cleared */
EPSR.T = tbit; /* T bit set from vector */
EPSR.IT<7:0> = Zeros(8); /* IT/ICI bits cleared */
BranchTo(tmp AND 0xFFFFFFFE<31:0>); /* address of reset service routine */