从汇编环境到C语言环境、volatile关键字、编译原理、链接脚本

本文详细介绍了从汇编环境到C语言环境的过渡,包括DDR初始化、SVC模式设置、SP指针初始化及从汇编跳转到C的实现。同时,讨论了volatile关键字在编译优化中的作用,防止变量优化并确保对特殊地址的稳定访问。最后,探讨了编译下载验证过程,包括Makefile编写、编译原理和链接脚本的使用,以及如何修改Makefile以适应链接脚本。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >



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 = 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值