最近淘到一个瑞萨的板子,MCU是R7FA6M5BH,官方推荐用e2studio或rasc,用rasc生成的Keil等工程每次编译都要调用rasc不知道干嘛,发布时候也特别麻烦,决定手戳一个最小启动代码.
完整项目 https://github.com/nickfox-taterli/embedfire-ra6m5
首先在LD文件指定入口点是复位.这是ARM定义好的.
ENTRY(Reset_Handler)

大家都见过STM32的启动代码是汇编写的,用C可以不可以呢,答案是肯定可以,但是有限制,比如一开始时不能传递参数(毕竟堆栈还没准备好).
// 复位处理函数
void Reset_Handler(void)
{
/* 初始化系统 */
SystemInit();
/* 调用用户主函数 */
extern void main(void);
main();
/* 主函数不应返回,如果返回则进入死循环 */
while (1) {}
}
定义中断向量表,因为瑞萨的用户中断都是自定义映射,所以只写ARM内置中断,第一个是栈指针,手册上写了,因为栈是往小地址生长,所以我设置为0x400是栈顶,就是有0x400这么大的堆栈了.
// 主栈空间定义(1KB大小,8字节对齐,放在stack段)
static uint8_t g_main_stack[0x400] __attribute__((aligned(8))) __attribute__((section("stack"))) __attribute__((__used__));
__attribute__((used)) const exc_ptr_t __Vectors[] __attribute__((section(".fixed_vectors"))) __attribute__((__used__)) =
{
(exc_ptr_t) (&g_main_stack[0] + 0x400), // 初始栈指针
Reset_Handler, // 复位处理函数
NMI_Handler, // NMI中断处理函数
HardFault_Handler, // 硬件错误处理函数
MemManage_Handler, // 内存管理错误处理函数
BusFault_Handler, // 总线错误处理函数
UsageFault_Handler, // 用法错误处理函数
SecureFault_Handler, // 安全错误处理函数
0, // 保留
0, // 保留
0, // 保留
SVC_Handler, // SVC调用处理函数
DebugMon_Handler, // 调试监控处理函数
0, // 保留
PendSV_Handler, // PendSV处理函数
SysTick_Handler, // SysTick处理函数
};
然后进入后就初始化堆栈,填充bss区域,调用各种C/C++构造函数.
// 系统初始化函数
void SystemInit(void)
{
/* 启用FPU */
SCB->CPACR = (uint32_t)(0xFU << 20);
/* 设置向量表偏移寄存器 */
SCB->VTOR = (uint32_t)&__Vectors;
/* 设置主栈指针限制 */
__set_MSPLIM((uint32_t)&g_main_stack[0]);
/* 清零.bss段(未初始化的全局变量区) */
extern uint32_t __bss_start__;
extern uint32_t __bss_end__;
uint32_t *bss_start = &__bss_start__;
uint32_t *bss_end = &__bss_end__;
uint32_t bss_size = (uint32_t)bss_end - (uint32_t)bss_start;
for(uint32_t i = 0; i < bss_size; i++) {
*((uint8_t*)bss_start + i) = 0;
}
/* 初始化.data段(已初始化的全局变量区) */
extern uint32_t _sidata;
extern uint32_t _sdata;
extern uint32_t _edata;
uint32_t *src = &_sidata; /* Flash中的数据源地址 */
uint32_t *dest = &_sdata; /* RAM中的目标地址 */
uint32_t size = (uint32_t)&_edata - (uint32_t)&_sdata;
for (uint32_t i = 0; i < size; i += 4) {
*dest++ = *src++;
}
/* 调用全局构造函数 */
extern void (*__init_array_start[])(void);
extern void (*__init_array_end[])(void);
int32_t count = __init_array_end - __init_array_start;
for (int32_t i = 0; i < count; i++) {
__init_array_start[i]();
}
}
这些段定义都在LD文件写着的,下面是一个完整例子.
/* 程序入口点 */
ENTRY(Reset_Handler)
/* 存储器定义 */
MEMORY
{
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 128K /* RAM:可执行/可读/可写,起始地址0x20000000,长度128KB */
FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 2M /* FLASH:只读/可执行,起始地址0x00000000,长度2MB */
}
/* 段(Section)定义 */
SECTIONS
{
/* 启动代码存放在FLASH中 */
.isr_vector :
{
. = ALIGN(4); /* 4字节对齐 */
KEEP(*(.fixed_vectors*)) /* 固定向量表 */
. = ALIGN(4);
} >FLASH
/* 程序代码和其他数据存放在FLASH中 */
.text :
{
. = ALIGN(4);
*(.text) /* 代码段 */
*(.text*) /* 其他代码段 */
*(.glue_7) /* ARM/Thumb代码粘合段 */
*(.glue_7t) /* Thumb/ARM代码粘合段 */
*(.eh_frame) /* 异常处理帧信息 */
KEEP (*(.init)) /* 保留初始化代码 */
KEEP (*(.fini)) /* 保留终止代码 */
. = ALIGN(4);
_etext = .; /* 定义代码结束的全局符号 */
} >FLASH
/* 常量数据存放在FLASH中 */
.rodata :
{
. = ALIGN(4);
*(.rodata) /* 只读数据段(常量、字符串等) */
*(.rodata*) /* 其他只读数据段 */
. = ALIGN(4);
} >FLASH
/* ARM异常处理表 */
.ARM.extab () :
{
. = ALIGN(4);
*(.ARM.extab* .gnu.linkonce.armextab.*)
. = ALIGN(4);
} >FLASH
/* ARM索引表 */
.ARM () :
{
. = ALIGN(4);
__exidx_start = .; /* 定义索引表开始 */
*(.ARM.exidx*)
__exidx_end = .; /* 定义索引表结束 */
. = ALIGN(4);
} >FLASH
/* 初始化数组 */
.init_array () :
{
. = ALIGN(4);
PROVIDE_HIDDEN (__init_array_start = .);
KEEP (*(SORT(.init_array.*)))
KEEP (*(.init_array*))
PROVIDE_HIDDEN (__init_array_end = .);
. = ALIGN(4);
} >FLASH
/* 供启动代码初始化数据使用的符号 */
_sidata = LOADADDR(.data);
/* 初始化数据段(加载到FLASH但运行在RAM) */
.data :
{
. = ALIGN(4);
_sdata = .; /* 定义数据段开始的全局符号 */
*(.data) /* 数据段 */
*(.data*) /* 其他数据段 */
. = ALIGN(4);
_edata = .; /* 定义数据段结束的全局符号 */
} >RAM AT> FLASH
/* 未初始化数据段(BSS) */
. = ALIGN(4);
.bss :
{
_sbss = .; /* 定义BSS段开始的全局符号 */
__bss_start__ = _sbss;
*(.bss) /* BSS段 */
*(.bss*) /* 其他BSS段 */
*(COMMON) /* 公共符号 */
. = ALIGN(4);
_ebss = .; /* 定义BSS段结束的全局符号 */
__bss_end__ = _ebss;
} >RAM
/* 堆栈段(不加载) */
.stack_dummy (NOLOAD):
{
. = ALIGN(8);
/* 主堆栈 */
KEEP(*(.stack))
} > RAM
/* 丢弃的段 */
/DISCARD/ :
{
libc.a ( * ) /* 丢弃标准库 */
libm.a ( * ) /* 丢弃数学库 */
libgcc.a ( * ) /* 丢弃GCC库 */
}
/* ARM属性段 */
.ARM.attributes 0 : { *(.ARM.attributes) }
}