一、原理分析
IX6MULL是恩智浦公司的一款Coretex-A7系列的芯片,主频800M。 LED点亮,其实就是最简单的GPIO控制的表现结果。对于GPIO的初始化,通常来说都有以下的过程:
- 查看原理图,查找对应的GPIO序号
- 查寄存器手册,打开GPIO控制的时钟源
- 配置GPIO复用为普通GPIO
- 配置GPIO的电气特性,如输入/输出、速率、输出方式(推挽/开漏等)、默认上拉/下拉
- 配置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的汇编代码
.global _start
_start:
ldr R0, =0x020C406C
ldr R1, =0x0C000000
str R1, [R0]
ldr R0 ,=0x020E0068 @MUX_CTL_PAD_GPIO1_IO03
ldr R1 ,=0x00000005 @bit0-4 set to 1
str R1 ,[R0]
ldr R0 ,=0x020E02F4 @PAD_CTL_PAD_GOIO1_IO03
ldr R1 ,=0x0000238 @
str R1 ,[R0]
ldr R0 ,=0x0209C004 @GPIO1_GDIR
ldr R1 ,=0x00000008 @bit3 : gpio1 IO3
str R1 ,[R0]
ldr R0 ,=0x0209C000 @GPIO1_DR
ldr R1 ,=0x00000000 @bit3 set low level, LED on
str R1 ,[R0]
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的时钟代码为例
ldr R0, =0x020C406C
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格式。
|