文章目录

  • 一、利用汇编初始化C环境
  • 二、C语言部分实验程序编写
  • 三、Makefile程序编写
  • 四、链接脚本程序编写
  • 五、编译及烧录

利用汇编编写LED灯点亮程序我们已经实现过了,所以这里不再着重讲解基本原理,直接上C语言版实现过程了。

一、利用汇编初始化C环境

1、确定Cortex-A 处理器运行模式
我们说过 Cortex-A 有九个运行模型,这里我们设置处理器运行在 SVC 模式下。处理器模式的设置是通过修改 CPSR(程序状态)寄存器来完成的,其中 M[4:0](CPSR 的 bit[4:0])就是设置处理器运行模式的如果要将处理器设置为 SVC 模式,那么 M[4:0]就要等于 0X13。11~13 行代码就是先使用指MRS 将 CPSR寄存器的值读取到 R0 中,然后修改 R0 中的值,设置 R0 bit[4:0]为 0X13,然后再使用指令MSR 将修改后的 R0 重新写入到 CPSR 中。
2、确定堆栈指针初始地址
行通过 ldr 指令设置 SVC 模式下的 SP 指针=0X80200000,因为 I.MX6U-ALPHA 开发 板 上 的 DDR3 地 址 范 围 是0X80000000~0XA0000000(512MB) 或 者0X80000000~0X90000000(256MB),不管是 512MB 版本还是 256MB 版本的,其 DDR3 起始地址都是 0X80000000。由于 Cortex-A7 的堆栈是向下增长的,所以将 SP 指针设置为 0X80200000,因此 SVC 模式的栈大小 0X80200000-0X80000000=0X200000=2MB,2MB 的栈空间已经很大了,
如果做裸机开发的话绰绰有余。
3、汇编启动代码实现

.global _start       /* 全局标号 *//** 描述:    _start函数,程序从此函数开始执行,此函数主要功能是设置C*       运行环境。*/
_start:/* 进入SVC模式 */mrs r0, cpsrbic 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函数,似乎需要多敲几个空格,要不然跳转不到我们的main函数里面去*/

二、C语言部分实验程序编写

1、main.h的编写
各个寄存器的用途以及寻找方法在上一个博客中已经介绍到了,这里就不再进行赘诉。重点关注一下“volatile”的用法:
volatile的本意是“易变的” 因为访问寄存器要比访问内存单元快的多,所以编译器一般都会作减少存取内存的优化,但有可能会读脏数据。当要求使用volatile声明变量值的时候,系统总是重新从它所在的内存读取数据,即使它前面的指令刚刚从该处读取过数据。精确地说就是,遇到这个关键字声明的变量,编译器对访问该变量的代码就不再进行优化,从而可以提供对特殊地址的稳定访问;如果不使用valatile,则编译器将对所声明的语句进行优化。(简洁的说就是:volatile关键词影响编译器编译的结果,用volatile声明的变量表示该变量随时可能发生变化,与该变量有关的运算,不要进行编译优化,以免出错)

#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

2、main.c的编写
这部分直接给出如下:

#include "main.h"/** @description : 使能I.MX6U所有外设时钟* @param       : 无* @return       : 无*/
void clk_enable(void)
{CCM_CCGR0 = 0xffffffff;CCM_CCGR1 = 0xffffffff;CCM_CCGR2 = 0xffffffff;CCM_CCGR3 = 0xffffffff;CCM_CCGR4 = 0xffffffff;CCM_CCGR5 = 0xffffffff;CCM_CCGR6 = 0xffffffff;
}/** @description  : 初始化LED对应的GPIO* @param        : 无* @return       : 无*/
void led_init(void)
{/* 1、初始化IO复用 */SW_MUX_GPIO1_IO03 = 0x5;   /* 复用为GPIO1_IO03 *//* 2、、配置GPIO1_IO03的IO属性  *bit 16:0 HYS关闭*bit [15:14]: 00 默认下拉*bit [13]: 0 kepper功能*bit [12]: 1 pull/keeper使能*bit [11]: 0 关闭开路输出*bit [7:6]: 10 速度100Mhz*bit [5:3]: 110 R0/6驱动能力*bit [0]: 0 低转换率*/SW_PAD_GPIO1_IO03 = 0X10B0;     /* 3、初始化GPIO */GPIO1_GDIR = 0X0000008; /* GPIO1_IO03设置为输出 *//* 4、设置GPIO1_IO03输出低电平,打开LED0 */GPIO1_DR = 0X0;
}/** @description  : 打开LED灯* @param       : 无* @return       : 无*/
void led_on(void)
{/* * 将GPIO1_DR的bit3清零   */GPIO1_DR &= ~(1<<3);
}/** @description  : 关闭LED灯* @param       : 无* @return       : 无*/
void led_off(void)
{/*    * 将GPIO1_DR的bit3置1*/GPIO1_DR |= (1<<3);
}/** @description  : 短时间延时函数* @param - n  : 要延时循环次数(空操作循环次数,模式延时)* @return        : 无*/
void delay_short(volatile unsigned int n)
{while(n--){}
}/** @description  : 延时函数,在396Mhz的主频下*                   延时时间大约为1ms* @param - n   : 要延时的ms数* @return         : 无*/
void delay(volatile unsigned int n)
{while(n--){delay_short(0x7ff);}
}/** @description  : mian函数* @param       : 无* @return       : 无*/
int main(void)
{clk_enable();      /* 使能所有的时钟          */led_init();           /* 初始化led           */while(1)          /* 死循环              */{ led_off();      /* 关闭LED            */delay(500);       /* 延时大约500ms        */led_on();     /* 打开LED            */delay(500);       /* 延时大约500ms        */}return 0;
}

三、Makefile程序编写

先补充一下基本的makefile语法知识:
$<的意思是依赖目标集合的第一个文件;
$@的意思是目标集合。
$^的意思是所有依赖文件的集合

objs := start.o main.o ledc.bin:$(objs)arm-linux-gnueabihf-ld -Timx6ul.lds -o ledc.elf $^arm-linux-gnueabihf-objcopy -O binary -S ledc.elf $@arm-linux-gnueabihf-objdump -D -m arm ledc.elf > ledc.dis%.o:%.sarm-linux-gnueabihf-gcc -Wall -nostdlib -c -O2 -o $@ $<%.o:%.Sarm-linux-gnueabihf-gcc -Wall -nostdlib -c -O2 -o $@ $<%.o:%.carm-linux-gnueabihf-gcc -Wall -nostdlib -c -O2 -o $@ $<clean:rm -rf *.o ledc.bin ledc.elf ledc.dis

特别注意我们的代码是:

arm-linux-gnueabihf-ld -Timx6ul.lds -o ledc.elf $^

而不是上一章内容的

arm-linux-gnueabihf-ld -Ttext 0X87800000 -o ledc.elf $^

四、链接脚本程序编写

前一博客中我们是通过“-Ttext”来指定链接地址是 0X87800000 的,这样的话所有的文件都会链接到以 0X87800000 为起始地址的区域。但是有时候我们很多文件需要链接到指定的区域,或者叫做段里面,比如在 Linux 里面初始化函数就会放到 init 段里面。因此我们需要能够自定义一些段,这些段的起始地址我们可以自由指定,同样的我们也可以指定一个文件或者函数应该存放到哪个段里面去。要完成这个功能我们就需要使用到链接脚本,看名字就知道链脚本主要用于链接的,用于描述文件应该如何被链接在一起形成最终的可执行文件。其主要目的是描述输入文件中的段如何被映射到输出文件中,并且控制输出文件中的内存排布。比如我们编译生成的文件一般都包含 text 段、data 段等等。链接脚本的语法很简单,就是编写一系列的命令,这些命令组成了链接脚本,每个命令是一个带有参数的关键字或者一个对符号的赋值,可以使用分号分隔命令。像文件名之类的字符串可以直接键入,也可以使用通配符“*”。最简单的链接脚本可以只包含一个“SECTIONS”,
我们可以在这一个“SECTIONS”里面来描述输出文件的内存布局。我们一般编译出来的代码都包含在 text、data、bss 和 rodata 这四个段内。
我们本试验的链接脚本要求如下:
①、链接起始地址为 0X87800000。
②、start.o 要被链接到最开始的地方,因为 start.o 里面包含这第一个要执行的命令。
根据要求,在 Makefile 同目录下新建一个名为“imx6ul.lds”的文件,然后在此文件里面输入如下所示代码:

SECTIONS{. = 0X87800000;.text :{start.o main.o *(.text)}.rodata ALIGN(4) : {*(.rodata*)}     .data ALIGN(4)   : { *(.data) }    __bss_start = .;    .bss ALIGN(4)  : { *(.bss)  *(COMMON) }    __bss_end = .;
}

五、编译及烧录

最终实验现象为闪烁灯。

基于Cortex-A7架构的嵌入式linux ARM裸机开发<2>——LED灯闪烁(C版本)相关推荐

  1. 基于Cortex-A7架构的嵌入式linux ARM驱动开发<1>——字符设备驱动开发

    一.什么是字符设备 字符设备是 Linux 驱动中最基本的一类设备驱动,字符设备就是一个一个字节,按照字节流进行读写操作的设备,读写数据是分先后顺序的.比如我们最常见的点灯.按键.IIC.SPI, L ...

  2. A7跑linux芯片,ST意法半导法发布第一款Cortex A7架构处理器芯片

    最近,意法半导体推出其第一款Cortex A7架构的处理器芯片系列,STM32MP1.不仅有双核A7, 内部还有Cortex M4,来运行一些低功耗的任务. STM32MP1有三种型号: STM32M ...

  3. 基于stm32mp157 linux开发板ARM裸机开发教程4:Cortex-A7 内核存储系统与流水线(连载中)

    前言: 目前针对ARM Cortex-A7裸机开发文档及视频进行了二次升级持续更新中,使其内容更加丰富,讲解更加细致,全文所使用的开发平台均为华清远见FS-MP1A开发板(STM32MP157开发板) ...

  4. ARM嵌入式Linux系统设计与开发

    ARM嵌入式Linux系统设计与开发 基本信息 作者: 俞辉    李永    刘凯    王晓虹    丛书名: 高等院校计算机教材系列 出版社:机械工业出版社 ISBN:9787111300045 ...

  5. linux 嵌入式汇编 adc,嵌入式Linux ARM汇编(四)——ARM汇编程序设计

    嵌入式Linux ARM汇编(四)--ARM汇编程序设计 汇编程序有顺序.循环.分支.子程序四种结构形式. 一.顺序结构 程序实例: AREA Buf,DATA,READWRITE;定义数据段Buf ...

  6. [嵌入式Linux项目实战开发]基于QT4.7.4的音乐播放器实现与设计【2018年给力项目】

    [嵌入式Linux项目实战开发]基于QT4.7.4的音乐播放器实现与设计[2018年给力项目]是[创科之龙]团队aiku嵌入式视频教程系列制作的现有的音乐播放器. 主要功能实现: 1.新建工程,基类选 ...

  7. [嵌入式Linux项目实战开发]基于QT4.8的仓库管理系统实现功能【2019年给力项目】

    [嵌入式Linux项目实战开发]基于QT4.8的仓库管理系统实现功能[2019年给力项目] 支持导出 excel 表格 支持查看商品操作日志 支持高精度浮点运算 支持同一商品以不同价格入库 该软件已开 ...

  8. 通过vscode进行嵌入式linux arm开发板gdb调试

    下载和安装vscode, 下载 vscode for windows 地址:  Visual Studio Code - Code Editing. Redefined 安装 "remote ...

  9. 基于龙芯 2K1000 的嵌入式 Linux 系统移植和驱动程序设计(二)

    第 3 章 嵌入式软件系统移植 本课题中嵌入式系统正常工作的前提是嵌入式软件系统完整且能正常工作, 以便为之后的软件开发提供一个能够正常工作的平台.引导程序 PMON 需要完成 内核引导,嵌入式 Li ...

最新文章

  1. 各国自动驾驶政策概况及特征
  2. 网络安全界永恒不变的10大安全法则
  3. 我自己写的3D图形数学库。。。有点乱!
  4. HDU 3954 Level up(线段树)
  5. Erlang China 大会 - CN Erlounge III - 发起
  6. ASP.NET 实现Base64文件流下载PDF
  7. 怎么把c语言转换汇编程序,如何把汇编语言转换成C语言
  8. 页面每次添加都显示最后一次访问记录spring scope=prototype 学习笔记
  9. sap快捷搜索菜单栏
  10. lingo17.0软件工具
  11. 一群人在网上直播自己怎么写代码,而且还有人爱看
  12. 服务器手机远程控制,【图文解析】手机端远程控制服务器的方法以及步骤
  13. 一万块内工作站型计算机配置,1.5万元i7-7700K用于图形工作站高端电脑配置推荐...
  14. saltstack实战--远程执行之返回(returner)
  15. Learn Python The Hard Way (python 2.7) ex45.py 你来制作一个游戏
  16. 2022/3/27 Java开发之Java web编程 第十一章 Ajax交互扩展
  17. 这些都是成为高薪运维必备的 Linux 技能,你具备了吗?
  18. Galgames Hgames下载中心,无毒
  19. Linux学习笔记week1
  20. 2021年新能源汽车行业造车新势力专题研究报告

热门文章

  1. C语言中的自定义函数
  2. MSP430 5xx/6xx 定时器A增计数模式编程实例
  3. jquery徽章_城市需要能够获得数字徽章
  4. xdm俺来了、详解超市订单管理系统SSM版本
  5. alert弹出[object Object]解决方法
  6. 适合新手 练手的Java 实战项目
  7. java乘法逆元与除法取模,关于数论乘法逆元及相关知识点
  8. NP问题真的很难理解
  9. 开源的ERP:WebERP
  10. 6种PS常用字体字号