linux系列目录:
linux基础篇(一)——GCC和Makefile编译过程
linux基础篇(二)——静态和动态链接
ARM裸机篇(一)——i.MX6ULL介绍
ARM裸机篇(二)——i.MX6ULL启动过程
ARM裸机篇(三)——i.MX6ULL第一个裸机程序
ARM裸机篇(四)——重定位和地址无关码
ARM裸机篇(五)——异常和中断
linux系统移植篇(一)—— linux系统组成
linux系统移植篇(二)—— Uboot使用介绍
linux系统移植篇(三)—— Linux 内核使用介绍
linux系统移植篇(四)—— 根文件系统使用介绍
linux驱动开发篇(一)—— Linux 内核模块介绍
linux驱动开发篇(二)—— 字符设备驱动框架
linux驱动开发篇(三)—— 总线设备驱动模型
linux驱动开发篇(四)—— platform平台设备驱动


文章目录

  • 一、汇编基础
  • 二、点亮LED灯

一、汇编基础

  1. 处理器内部数据传输指令
  2. 存储器访问指令
  3. 压栈和出栈指令
  4. 跳转指令
  5. 算术运算指令
  6. 逻辑运算指令

二、点亮LED灯

实际开发过程中汇编用的很少,只有在C语言环境没有准备好的情况下,才必须使用汇编,比如初始化 DDR、设置堆栈指针 SP 等。
I.MX6U 内部的 Boot ROM 会读取 DCD 数据中的 DDR 配置参数然后完成 DDR 初始化的,所以我们编写的汇编就可以省了这一部分,只需要设置好栈指针就可以使用C语言了。

编写代码之前,先搞清楚以下几个要点:

  1. C函数为何要用栈
    总的来说,栈的作用就是:保存现场/上下文,传递参数。
  • 保存现场/上下文
    现场,相当于案发现场,总有一些现场的情况,要记录下来的,否则被别人破坏掉之后,你就无法恢复现场了。而此处说的现场,就是指CPU运行的时候,用到的一些寄存器,比如R0~R3,LR等等,对于这些寄存器的值,如果你不保存而直接跳转到函数中去执行,那么很可能会被破坏了,因为函数执行需要用到这些寄存器。
    因此在函数调用之前,应该将这些寄存器等现场,暂时保持起来,等调用函数执行完毕返回后,再恢复现场,这样CPU就可以正确的继续执行了。

  • 传递参数
    当函数被调用并且参数大于4个时,(不包括第4个参数)第4个参数后面的参数就保存在栈中。

  1. 汇编如何调用C函数
  • 当参数小于等下4个时,使用寄存器R0~R3来进行参数传递
  • 当参数大于4个时,前四个参数按照上面方法传递,剩余参数传送到栈中,入栈的顺序与参数顺序相反,即最后一个参数先入栈
  1. C程序如何返回结果给汇编程序
  • 结果为一个32位的整数时,通过寄存器R0返回
  • 结果为一个64位整数时,通过R0和R1返回,依此类推.
  • 结果为一个浮点数时,通过浮点运算部件的寄存器f0,d0或s0返回
  • 结果为一个复合的浮点数时,通过寄存器f0-fN或者d0~dN返回
  • 对于位数更多的结果,通过调用内存来传递

编写汇编部分:

.text            //代码段
.align 2         //设置字节对齐
.global _start   //定义全局变量_start:          //程序的开始b reset      //跳转到reset标号处reset:mrc     p15, 0, r0, c1, c0, 0     /*读取CP15系统控制寄存器   */bic     r0,  r0, #(0x1 << 12)     /*  清除第12位(I位)禁用 I Cache  */bic     r0,  r0, #(0x1 <<  2)     /*  清除第 2位(C位)禁用 D Cache  */bic     r0,  r0, #0x2             /*  清除第 1位(A位)禁止严格对齐   */bic     r0,  r0, #(0x1 << 11)     /*  清除第11位(Z位)分支预测   */bic     r0,  r0, #0x1             /*  清除第 0位(M位)禁用 MMU   */mcr     p15, 0, r0, c1, c0, 0     /*  将修改后的值写回CP15寄存器   */ldr sp, =0x80200000   //栈指针暂时设置到这个位置b main        //跳转到main函数执行/*进入死循环*/
loop:b loop

编写C语言部分:


#define CCM_CCGR1 (volatile unsigned long*)0x20C406C          //时钟控制寄存器
#define IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO04 (volatile unsigned long*)0x20E006C//GPIO1_04复用功能选择寄存器
#define IOMUXC_SW_PAD_CTL_PAD_GPIO1_IO04 (volatile unsigned long*)0x20E02F8 //PAD属性设置寄存器
#define GPIO1_GDIR (volatile unsigned long*)0x0209C004 //GPIO方向设置寄存器(输入或输出)
#define GPIO1_DR (volatile unsigned long*)0x0209C000   //GPIO输出状态寄存器#define uint32_t  unsigned int /*简单延时函数*/
void delay()
{static uint32_t delay_time = 0x1FFFF;do{delay_time --;}while(delay_time);delay_time = 0x1FFFF;
}int main()
{*(CCM_CCGR1) = 0xFFFFFFFF;   //开启GPIO1的时钟*(IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO04) = 0x5;//设置PAD复用功能为GPIO*(IOMUXC_SW_PAD_CTL_PAD_GPIO1_IO04) = 0x1F838;//设置PAD属性*(GPIO1_GDIR) = 0x10;//设置GPIO为输出模式*(GPIO1_DR) = 0x0;   //设置输出电平为低电平while(1){*(GPIO1_DR) = 0x0;delay();*(GPIO1_DR) = 1<<4;delay();}return 0;
}

编写链接脚本:
链接脚本主要目的是描述输入文件中的段如何被映射到输出文件中,并且控制输出文件中的内存排布。
gcc的链接脚本后缀一般为lds,编写led.lds文件:

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

结合代码各部分讲解如下:

  • 第1行,ENTRY(_start) 用于指定程序的入口,ENTRY( )是设置入口地址的命令, “_start”是程序的入口,本章的led程序的入口地址位于start.S的“_start”标号处。

  • 第2行,定义SECTIONS。SECTIONS可以理解为是一块区域,我们在这块区域排布我们的代码, 链接时链接器就会按照这里的指示链接我们的代码。

  • 第3行,“.”运算符代表当前位置。 我们在SECTION的最开始使用“.= 0X87800000”就是将链接起始地址设置为0X87800000。

  • 第5行,设置字节对齐。这里同样用到了“.”运算符,它表示从当前位置开始执行四字节对齐。 假设当前位置为0x80000001,执行该命令后当前地址将会空出三个字节转到0x80000004地址处。

  • 第6行,定义代码段。“.text :”用于定义代码段,固定的语法要求,我们按照要求写即可。 在“{}”中指定那些内容放在代码段。将start.o中的代码放到代码段的最前面。start.S是启动代码应当首先被执行, 所以通常情况下要把它放到代码段的最前面,其他源文件的代码按照系统默认的排放顺序即可, 通配符“*”在这里表示其他剩余所有的.o文件。

  • 第7-10行,设置数据段。同设置代码段类似,首先设置字节对齐,然后定义代码段。在代码段里使用“*”通配符, 将所有源文件中的代码添加到这个代码段中。

  • 第11-13行,设置BSS段。.bss 段的起始地址和结束地址保存在了“__bss_start”和“__bss_end”中,我们就可以直接在汇编或者 C 文件里面使用这两个符号。

连接器脚本编写完成后,在链接指令中使用链接脚本替换-Ttext 0X87800000

arm-none-eabi-ld -Tled.lds  $^ -o led.elf

编写makefile文件:
我们程序编写完成后需要依次输入编译、链接、格式转换 命令才能最终生成二进制文件。这种编译方式效率低、容易出错。可以使用makefile文件来干这件事。
makefile文件:

all: start.o led.o arm-none-eabi-ld -Tled.lds  $^ -o led.elfarm-none-eabi-objcopy -O binary -S -g led.elf led.binarm-none-eabi-objdump -D -m arm  led.elf  > led.dis%.o : %.Sarm-none-eabi-gcc -g -c $^ -o start.o
%.o : %.carm-none-eabi-gcc -g -c $^ -o led.o.PHONY: clean
clean:rm *.o *.elf *.bin

链接脚本led.lds和makefile编写完成后,就可以直接使用make命令,来一键完成编译和链接了。

然后,只需要把led.bin通过烧录工具制作成镜像文件烧录到SD卡就可以启动了。

ARM裸机篇(三)——i.MX6ULL第一个裸机程序相关推荐

  1. 安卓篇-我自己的第一个安卓程序(附源码链接)

    在上一期的教程中我们已经成功把安卓工作室(以下简称AS)安装到了我们的电脑上啦~那么这一期我们就要来创建属于我们自己的第一个安卓程序,并且运行到模拟器上. 上期内容传送门~~~ 如何安装Android ...

  2. 快速入门丨篇三:如何进行运动控制器ZPLC程序开发?

    此前,正运动技术给大家讲了,运动控制器的"固件升级"以及"ZBasic程序开发",今天我们来学习一下运动控制器ZPLC程序开发. ZPLC是Zmotion运动控 ...

  3. ARM裸机篇(二)——i.MX6ULL启动过程

    linux系列目录: linux基础篇(一)--GCC和Makefile编译过程 linux基础篇(二)--静态和动态链接 ARM裸机篇(一)--i.MX6ULL介绍 ARM裸机篇(二)--i.MX6 ...

  4. ARM裸机篇(五)——异常和中断

    linux系列目录: linux基础篇(一)--GCC和Makefile编译过程 linux基础篇(二)--静态和动态链接 ARM裸机篇(一)--i.MX6ULL介绍 ARM裸机篇(二)--i.MX6 ...

  5. 开发板、原理图和数据手册-1.3.ARM裸机第三部分-朱有鹏-专题视频课程

    开发板.原理图和数据手册-1.3.ARM裸机第三部分-7453人已学习 课程介绍         本期课程承上启下,主要目的是让大家把开发板玩起来.很多同学买了开发板接上线,串口都连不上,或者连刷系统 ...

  6. i.MX6ULL裸机篇(二)NXP官方SDK移植之踩坑 网口驱动

    MX6ULL官方SDK移植之踩坑 网口驱动 一.引言 NXP MX6ULL 网口移植其实主要修改底层驱动程序,LWIP协议通用,一般不用修改,这里主要和大家分享在Linux环境下移植修改网口驱动程序. ...

  7. ARM裸机篇---启动代码分析

    ARM裸机篇---启动代码分析 先搞清楚启动代码和Bootloader的区别,启动代码是指CPU复位后到进入C语言的main函数之前需要执行的那段汇编代码. 下面的代码先暂且这样吧,没啥注释的,时间关 ...

  8. 第三章 裸机_第一个裸机程序(上)

    第一章 裸机调试入门知识 1.对于友善之臂Micro2440开发板进行裸机调试时,需要将启动FLASH选项开关拨动到NOR FLASH上.这样做的原因:裸机程序里面会包含很多的初始化,这些初始化一般都 ...

  9. docker omv 防火墙_我的软路由折腾之旅 篇三:在openmediavault上通过Docker实现OPENWRT旁路由功能...

    我的软路由折腾之旅 篇三:在openmediavault上通过Docker实现OPENWRT旁路由功能 2020-06-20 11:28:38 57点赞 415收藏 74评论 你是AMD Yes党?还 ...

  10. MACE源码解析【ARM卷积篇(一) 】1*N和N*1卷积实现

    MACE Mobile AI Compute Engine (MACE) 是一个专为移动端异构计算平台优化的神经网络计算框架,旨在深度神经网络部署在移动端,是一个SoC上的神经网络实现.主要涉及的硬件 ...

最新文章

  1. 大场景三维点云的语义分割综述
  2. 当开启了延迟加载的开关,对象是怎么变成代理对象的?
  3. 【翻译】GitHub Pages Basics 基本使用帮助【一】GitHub Pages 是什么?
  4. HTML5程序开发范例宝典 完整版 (韩旭等著) 中文pdf扫描版
  5. mysql的sql优化工具下载_MySQL SQL查询优化工具EverSQL
  6. python自动化读取和写入文件_基于Python的接口自动化读写excel文件的方法
  7. win11右键新建没有txt文本文档记事本怎么办
  8. et99php,加密锁/加密狗ET199(包含网络锁功能)
  9. 打造有身体的 AI丨记青源Workshop具身智能与机器人研讨会(2022年第8期)
  10. 如何制作一张3D复古拼贴海报 Part II
  11. 李清照最经典的10首诗词
  12. Vue:前端体系与前后端分离
  13. 13.14.4 文本文件到电子表格。python编程快速上手--让繁琐工作自动化 第2版。【美】阿尔·斯维加特 Al Sweigart 著 王海鹏 译 中国工信出版集团 人民邮电出版社
  14. Client can't access Jboss server, the port is not accessable.
  15. html5是什么语言,html5 css3是什么?
  16. Linux 灾难恢复
  17. 西门子PLC产生随机数
  18. 盛世昊通2022全新布局,九大生态板块赋能产业数字化
  19. 基于 FPGA 的模拟 I²C协议设计(中)
  20. Vue、VueCLI(脚手架)安装、使用详细步骤

热门文章

  1. 注册码系统V2的自动发卡功能使用流程
  2. @Formula的使用
  3. formula one不兼容win10
  4. esxi虚拟化是基于linux吗,虚拟化 – 如何在虚拟机中运行VMWare ESX或ESXi?
  5. 饭后小甜点leetcode——哈希表
  6. 程序员如何更好的提升自己
  7. 计算机硬件开关打开无线网络,如何打开电脑无线网络_如何打开无线网络连接...
  8. 计算机应用基础制作新春贺卡图片,WORD制作新年贺卡和个人简历大学计算机基础课程设计报告书...
  9. 再见,996!程序员开源考公指南火了:三人已成功上岸!
  10. 2020家用千兆路由器哪款好_家用千兆路由器哪款好(2020年千兆路由器排行榜)...