<IMX6ULL芯片学习记录> 汇编点亮LED灯

一、原理分析

IX6MULL是恩智浦公司的一款Coretex-A7系列的芯片,主频800M。
LED点亮,其实就是最简单的GPIO控制的表现结果。对于GPIO的初始化,通常来说都有以下的过程:

  1. 查看原理图,查找对应的GPIO序号
  2. 查寄存器手册,打开GPIO控制的时钟源
  3. 配置GPIO复用为普通GPIO
  4. 配置GPIO的电气特性,如输入/输出、速率、输出方式(推挽/开漏等)、默认上拉/下拉
  5. 配置GPIO的电平

1、查看原理图

从原理图可知,当LED0控制为低电平,LED可以被点亮。

在这里插入图片描述
LED0接到了芯片的GPIO3处
在这里插入图片描述

2、使能GPIO时钟

只有使能时钟,才可以让GPIO正常工作。找到GPIO时钟寄存器,并使能它。
时钟有4种模式,这里需要停止模式外,所有模式都保持工作,即11

寄存器地址为:0x020C 406C
在这里插入图片描述

在这里插入图片描述
可以看到gpio1的时钟在bit26-27,将该两位置为1即可。即为0x0C00 0000
在这里插入图片描述

3、配置GPIO复用

大部分功能强大的芯片,GPIO通常都不是作为普通的IO使用,一个GPIO有许多可选(复用)的功能,想要让GPIO作为普通IO使用,就需要配置对应的复用寄存器,选择为普通GPIO的功能。查看IX6MULL芯片的参考手册,找到对应的复用配置寄存器。

配置该寄存器的0-3bit为0101,即16进制的0x5,可以配置为普通GPIO功能,表中还可以看到该GPIO的其他可选功能。
在这里插入图片描述

4、配置GPIO的电气特性

GPIO的基本属性,如方向(input/output)、状态(浮空、开漏、推挽、上下拉等)、速率(50Mbps,100Mpbs、200Mbps等)。
控制LED亮灭,需要控制电平,所以需要配置为输出模式,简单的灯亮灭对速率没有特别要求。状态希望默认是熄灭的状态,所以初始化的时候,可以配置为上拉,即默认输出高电平的状态,根据原理图分析可知LED0为高电平,LED熄灭。

手册对应的寄存器如下:

寄存器地址为:0x020E 02F4
在这里插入图片描述
在这里插入图片描述
寄存器共有32bit

  • bit0:
    slew rate 就是电压转换速率(Slew Rate),简写为SR,简称压摆率。其定义是在1微秒或者1纳秒等时间里电压升高的幅度,可以简单理解为电平切换时的速度快慢。
    快速、慢速,具体的时间需要细看手册。对于LED的控制,没有那么精确的要求,可以选择其中一个,这里选择默认配置0b0

  • bit1-2:
    保留,无功能作用,所以不需要配置,默认为0b00

  • bit3-5:
    配置GPIO的驱动能力,这里是通过调整电阻的大小来提高驱动能力,电压相同的情况下,电阻越小驱动能力越强。不确定需要的电流,可以选择驱动能力最强的,当然也可以通过公式来计算,这里选择最强的驱动能力,即bit3-5需要配置为0b111

  • bit6-7:
    配置GPIO的输出速率,同样对于普通电平控制,没有对速率的要求。选择默认即可,即0b00

  • bit8-10:
    保留, 即配置为0b00

  • bit11:
    开漏输出:输出端相当于三极管的集电极,要得到高电平状态需要上拉电阻才行。适合于做电流型的驱动,其吸收电流的能力相对强(一般20mA以内)。开漏形式的电路有以下几个特点:

    1、利用外部电路的驱动能力,减少IC内部的驱动。当IC内部MOSFET导通时,驱动电流是从外部的VCC流经上拉电阻、MOSFET到GND。IC内部仅需很小的栅极驱动电流。
    
    2、一般来说,开漏是用来连接不同电平的器件,匹配电平用的,因为开漏引脚不连接外部的上拉电阻时,只能输出低电平,如果需要同时具备输出高电平的功能,则需要接上拉电阻,很好的一个优点是通过改变上拉电源的电压,便可以改变传输电平。比如加上上拉电阻就可以提供TTL/CMOS电平输出等。(上拉电阻的阻值决定了逻辑电平转换的速度。阻值越大,速度越低功耗越小,所以负载电阻的选择要兼顾功耗和速度。)
    
    3、开漏输出提供了灵活的输出方式,但是也有其弱点,就是带来上升沿的延时。因为上升沿是通过外接上拉无源电阻对负载充电,所以当电阻选择小时延时就小,但功耗大;反之延时大功耗小。所以如果对延时有要求,则建议用下降沿输出。
    
    4、可以将多个开漏输出连接到一条线上。通过一只上拉电阻,在不增加任何器件的情况下,形成“与逻辑”关系,即“线与”。可以简单的理解为:在所有引脚连在一起时,外接一上拉电阻,如果有一个引脚输出为逻辑0,相当于接地,与之并联的回路“相当于被一根导线短路”,所以外电路逻辑电平便为0,只有都为高电平时,与的结果才为逻辑1。
    

    摘自https://blog.csdn.net/smfnjkgt/article/details/42101361
    对于LED的电平控制,我们需要手动输出高低电平,所以关掉开漏模式即可。配置为0b0

  • bit12:
    keeper功能暂不能很深入的理解其作用与含义,手册描述入下
    在这里插入图片描述
    个人理解为,开启Keeper后,GPIO的电压与OVDD保持一致了,当核心的VDD断电或者出现其他状态的时候,回保持之前的电平。也有资料说,核心休眠时,GPIO可以保持原来的电平。这里我们不需要使用该功能,选择关掉,设置为0b0

  • bit13:
    同样为keeper的功能,选择时keeper模式还是PUll模式,PULL模式个人理解为出现上述情况的时候,IO的电平会拉高。比如核心休眠的时候,会将IO的状态拉高。bit12(Pull_Keeper)功能关闭,该bit配置无意义。所以默认0b0

  • bit14-15:
    正常的IO上下拉配置,可以选择不同电阻模式下的上下拉,默认状态下的驱动能力不同。这里想要默认关闭LED,所以选择默认上拉模式,配置为0b01

  • bit16:
    GPIO磁滞模式开关,对抗不稳定的波形,图中生动形象!不需要配置迟滞,配置为0b0
    在这里插入图片描述

  • bit17-31: 保留

到这里GPIO的电器特性就配置完成了,所有寄存器数值拼凑一起就是0b0 0010 0000 0011 1000,一共配置17位,打开计算器,选择对应的位置即可以快速获取最终的数值0x00000238

在这里插入图片描述
配置GPIO方向的寄存器如下:
寄存器地址为:0x0209 C004
在这里插入图片描述

在这里插入图片描述

32bit分别表示GPIO1_IO0-31的方向。这里需要配置GPIO3,即bit3为输出模式,配置为0x0000 0001

在这里插入图片描述

5、配置GPIO输出电平

可以看到该寄存器为GPIO的输入模式读取寄存器,与输出模式下的电平输出寄存器。
bit0-31 分别代表GPIO0-31的电平情况,输出为1代表高电平,为0表示低电平。
在这里插入图片描述

在这里插入图片描述

二、代码编写

编写文件名为led.s的汇编代码

/*
    IMX6ULL led.s
    Use for control led.
 */

 .global _start 

 _start:
    /* Enable gpio clock */
	ldr R0, =0x020C406C  	/* CCGR1 */
    ldr R1, =0x0C000000
	str R1, [R0]

    /* gpio1 03 MUX_MODE to gpio */
    ldr R0 ,=0x020E0068 @MUX_CTL_PAD_GPIO1_IO03
    ldr R1 ,=0x00000005 @bit0-4 set to 1
    str R1 ,[R0]

    /* gpio1 03 Electrtion */
    ldr R0 ,=0x020E02F4 @PAD_CTL_PAD_GOIO1_IO03
    ldr R1 ,=0x0000238 @
    str R1 ,[R0]

    /* gpio1 03 Direction for output */
    ldr R0 ,=0x0209C004 @GPIO1_GDIR
    ldr R1 ,=0x00000008 @bit3 : gpio1 IO3
    str R1 ,[R0]

    /* gpio 03 output level */
    ldr R0 ,=0x0209C000 @GPIO1_DR
    ldr R1 ,=0x00000000 @bit3 set low level, LED on
    str R1 ,[R0]

/* while(1) */
loop: 
    b loop

1、代码分析

  • .global 关键字一个符号对链接器可见,可以供其他链接对象模块使用。声明_start函数,可以让链接器作为默认入口地址
  • _start: 汇编代码起始的位置
  • IMX6ULL是arm架构的芯片,所以用到的是arm的汇编指令。
命令作用
LDR Rd, [Rn , #offset]从存储器 Rn+offset 的位置读取数据存放到 Rd 中
STR Rd, [Rn, #offset]将 Rd 中的数据写入到存储器中的 Rn+offset 位置

以配置GPIO的时钟代码为例

 /* Enable gpio clock */
	ldr R0, =0x020C406C  	/* CCGR1 */
    ldr R1, =0x0C000000
	str R1, [R0]

(1)时钟寄存器地址为0x020C406C,先用ldr,将寄存器地址存入到R0.
(2)使用ldr将要写入寄存器的数值0x0C000000写入到寄存器R1
(3)使用str将R1的数值写入到地址为R0的寄存器。[R0] 表示0x020C406C地址存储的数值。将R1的数值,写入到该地址里面,相当于把地址为0x020C406C的寄存器的数值配置为0x0C000000。

后续步骤均为同样的操作,按照上述寄存器的分析,分别写入对应寄存器的数值,进行GPIO的初始化配置。

  • b loop 指令相当于c语言中的while(1)操作。 b为不带返回的跳转,跳转到loop函数中。此时程序会一直重复在loop。防止程序执行完成后,芯片跑飞。

2、汇编代码编译

由于使用的是Ubuntu环境进行测程序开发,ubuntu安装的是x86架构的系统,而IX6MULL是arm架构的芯片。ubuntu默认的gcc只能编出x86使用的程序代码,跨平台的编译,则需要交叉编译工具进行编译了。

(1)首先需要安装交叉编译工具链:

在这里插入图片描述
创建/usr/local/arm,将工具链解压到/usr/local/arm目录下,该目录作为arm编译工具链的存储目录。然后可以进入到 /usr/local/arm/gcc-arm-linux64/bin目录下看到我们交叉编译工具链的gcc等编译工具。
在这里插入图片描述

(2)添加工具链目录到环境变量

/usr/local/arm目录并不在ubuntu默认的环境配置中,在终端是无法直接找到编译工具链的位置,需要在/etc/profile文件中,添加环境配置,告诉ubuntu在哪里可以找到编译工具链。

在这里插入图片描述
只需要在profile文件的最后一行添加编译工具的路径。

export PATH=$PATH:/usr/local/arm/gcc-arm-linux64/bin

然后使用source命令更新一下/etc/profile文件或者重启一次系统,就可以将环境配置好。

source /etc/profile

随后我们在终端输入arm-linux前缀,然后按TABLE补全,可以自动出现匹配的编译工具链,代表环境已经配置完成。

在这里插入图片描述

(3)编译

汇编编译过程如下:

  • arm-linux-gnueabihf-gcc -c -g led.s -o led.o
    先使用gcc -c将.s文件编译成目标文件led.o

  • arm-linux-gnueabihf-ld -Ttext 0x87800000 led.o -o led.elf
    再使用链接工具,指定text段的起始位置(0x87800000),同时将led.o链接成可以执行的elf格式文件。 起始位置可以通过芯片手册找到对应的启动范围。

  • arm-linux-gnueabihf-objcopy -O binary -S -g led.elf led.bin
    使用objcopy,-O表示输出为binary格式的文件, -S表示不复制源文件中的重定向信息与符号信息,-g表示不复制源文件的调试信息,最后将elf复制为bin格式。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值