目录
1 从汇编环境到C语言环境
在开始部分用汇编来初始化 C 语言环境,比如初始化 DDR、设置堆栈指针 SP 等等,然后从汇编语言跳转到C语言的main 函数
①、汇编文件只是用来完成 C 语言环境搭建
②、C 语言文件就是完成我们的业务层代码的,其实就是我们实际例程要完成的功能
1.1 初始化DDR
在 I.MX6U-ALPHA 开发板学习 —— 启动方式 已经讲过关于DDR的初始化(在内部 boot 模式下):
- 不需要程序员手动配置
- 由内部的 Boot ROM 读取 DCD 数据中的 DDR 配置参数完成初始化
1.2 设置SVC模式
Cortex-A7 处理器有 9 种处理模式(运行模型),用的比较多的是Supervisor(SVC)模式,即超级用户模式,有额外的特权,允许你进一步控制CPU

所有的处理器模式都共用一个 CPSR 物理寄存器,因此 CPSR 可以在任何模式下被访问。CPSR 是当前程序状态寄存器,该寄存器包含了条件标志位、中断禁止位、当前处理器模式标志等一些状态位以及一些控制位。对于特殊寄存器的读写,对应的汇编指令是 MRS 和 MSR ,,更多请查看:从基础汇编指令到点亮LED
处理器模式的设置是通过修改 CPSR(程序状态)寄存器来完成的,在程序状态寄存器 CPSR 中,bit4 ~ 0 是处理器模式控制位,比如使用 Supervisor(SVC) 模式,在 CPSR 寄存器中写入 10011 即可

1.3 初始化SP指针
SP指针设置在DDR内存中
对于 I.MX6U-ALPHA 的 DDR3 地址范围是 0X80000000 ~ 0XA0000000(512MB) 或者 0X80000000 ~ 0X90000000(256MB),DDR3 起始地址均为 0X80000000 ;又因为堆栈是向下增长的,所以如果要设置2MB的栈空间,可以将SP指针初始化为 0X80200000(= 0X80000000 + 0X200000 = 2MB),则当需要保存现场时,SP指针指向的方向为:从 0X80200000 到 0X80000000 依次存放现场的信息
1.4 从汇编跳转到C语言
只要使用 B 指令就可以实现跳转,一般是在 .s 文件中初始化结束后进行跳转,B 指令后的 < lable> 为 main , gcc 对 C 代码编译后,通过反汇编 elf 文件即可看到main函数在汇编代码中是一个函数名(即lable)
1.5 代码实现
① 新建一个项目工程文件夹,在 VScode 中打开,然后 new 一个文件,命名为 startup.s,用来编写汇编语言,作为启动文件,一定记得注意,最后一行一定要回车留空,不然不会执行< b main >
// .s文件
.global _start /* 全局标号 */
/*
* 描述: _start 函数,程序从此函数开始执行,此函数主要功能是设置 C
* 运行环境。
*/
_start:
/* 进入 SVC 模式 */
mrs r0, cpsr
bic r0, r0, #0x1f /* 将 r0 的低 5 位清零,也就是 cpsr 的 M0~M4 */
orr r0, r0, #0x13 /* r0 或上 0x13,表示使用 SVC 模式 */
msr cpsr, r0 /* 将 r0 的数据写入到 cpsr_c 中 */
ldr sp, =0X80200000 /* 设置栈指针 */
b main /* 跳转到 main 函数 */
//这里一定要回车!回车!回车!
② 在工程文件 new 一个文件,命名 main.h,用来定义寄存器的地址
#ifndef __MAIN_H
#define __MAIN_H
/*
* CCM 相关寄存器地址(外设时钟使能寄存器)
*/
#define CCM_CCGR0 *((volatile unsigned int *)0X020C4068)
#define CCM_CCGR1 *((volatile unsigned int *)0X020C406C)
#define CCM_CCGR2 *((volatile unsigned int *)0X020C4070)
#define CCM_CCGR3 *((volatile unsigned int *)0X020C4074)
#define CCM_CCGR4 *((volatile unsigned int *)0X020C4078)
#define CCM_CCGR5 *((volatile unsigned int *)0X020C407C)
#define CCM_CCGR6 *((volatile unsigned int *)0X020C4080)
/*
* IOMUX 相关寄存器地址(复用选择、模式选择)
*/
#define SW_MUX_GPIO1_IO03 *((volatile unsigned int *)0X020E0068)
#define SW_PAD_GPIO1_IO03 *((volatile unsigned int *)0X020E02F4)
/*
* GPIO1 相关寄存器地址
*/
#define GPIO1_DR *((volatile unsigned int *)0X0209C000)
#define GPIO1_GDIR *((volatile unsigned int *)0X0209C004)
#define GPIO1_PSR *((volatile unsigned int *)0X0209C008)
#define GPIO1_ICR1 *((volatile unsigned int *)0X0209C00C)
#define GPIO1_ICR2 *((volatile unsigned int *)0X0209C010)
#define GPIO1_IMR *((volatile unsigned int *)0X0209C014)
#define GPIO1_ISR *((volatile unsigned int *)0X0209C018)
#define GPIO1_EDGE_SEL *((volatile unsigned int *)0X0209C01C)
#endif
③ 最后在工程 new 一个 main.c 文件
#include "main.h"
/*
* @description : 使能 I.MX6U 所有外设时钟
* @param : 无
* @return : 无
*/
void clk_enable(void)
{
CCM_CCGR0 = 0xffffffff;
CCM_CCGR1 = 0xffffffff;
CCM_CCGR2 =