实验必需
硬件
- 开发板:野火Linux开发板-EBF6ULL S1Pro
- TF卡
- USB读卡器
软件
- Ubuntu 16.0.4 (环境已搭建完成)
- imxdownload (正点原子裸机烧写软件,没错白嫖真香,感谢正点原子大大)
- VSCode代码编辑器
原理分析
IO命名规则
- IOMUXC_SW_MUX_CTL_PAD_XX_XX为IMX6ULL引脚命名规则,后面的XX_XX即为IO名,根据其具体功能命名。
IO功能复用
6ULL的IO是可以复用多种功能的,通过寄存器配置其具体功能。
以IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO00为例,其复用寄存器如下:
寄存器地址:0x020E_005C
为32位寄存器,只用了低五位[4:0]。其中bit0~bit3(MUX_MODE)就是设置 GPIO1_IO00 的复用功能的。共9种功能,ALT5就是作为GPIO1_IO00。
IO属性配置
选择复用功能为GPIO后,需要对其进行进行属性配置。配置寄存器如下:
此寄存器也是32位寄存器,只用了低17位。
- HYS(bit16):迟滞比较器使能位,IO输入时有效,设置施密特触发器是否使能。0 禁止,1使能
- PUS(bit15:14):上下拉电阻设置,00:100K下拉,01:47K上拉,10:100K上拉,11:22K上拉。
- PUE(bit13):IO作输入时,设置IO使用状态保持器还是上下拉,0:使用状态保持器,1:使用上下拉。状态保持器:外部电路断电时,IO保持以前状态不变。
- PKE(bit12):使能/禁止上下拉/状态保持器。0:禁止,1:使能。
- ODE(bit11):当 IO 作为输出的时候,此位用来禁止或者使能开路输出,此位为 0 的时候禁止开路输出,当此位为 1 的时候就使能开路输出功能。
- SPEED(bit7:6): IO 用作输出的时候,此位用来设置 IO 速度,00:低速50M,01:中速100M,10:中速100M,11:高速200M。
- DSE(bit5:3):当 IO 用作输出的时候用来设置 IO 的驱动能力,000:输出驱动关闭,001:R0(3.3V下260ohm,1.8V–150ohm,DDR–240ohm),010:R0/2,011:R0/3,100:R0/4,101:R0/5,110:R0/6,111:R0/7。
- SRE(bit0):设置压摆率,0:低压摆率,1:高压摆率。
GPIO配置
当IO作为GPIO使用时,需要设置的寄存器一共有八个:
- DR:数据寄存器,每位对应一个GPIO,输出时写入0/1控制高低电平,输入时保存对应GPIO电平状态。
- GDIR:方向寄存器,32位,设置IO工作方向,0:输入,1:输出。每个IO对应1位。
- PSR:GPIO状态寄存器,每一个GPIO对应1位,功能和输入状态的DR寄存器一样。
- ICR1:中断控制寄存器,ICR1用于配置低16个GPIO,IO0-15,ICR1 寄存器中一个 GPIO 用两个位,这两个位用来配置中断的触发方式。00:低电平触发,01:高电平触发,10:上升沿触发,11:下降沿触发
- ICR2:中断控制寄存器,ICR2 用于配置高 16 个 GPIO,IO16-31,ICR2 寄存器中一个 GPIO 用两个位,这两个位用来配置中断的触发方式。00:低电平触发,01:高电平触发,10:上升沿触发,11:下降沿触发
- EDGE_SEL
- IMR:中断屏蔽寄存器,每个IO对应1位,1:使能中断,0:禁止中断。
- ISR:中断状态寄存器,一个 GPIO 对应一个位,只要某个 GPIO 的中断发生,那么ISR 中相应的位就会被置 1。当我们处理完中断以后,必须清除中断标志位,即写0。
GPIO时钟使能
时钟使能寄存器有CCM_CCGR0~CCM_CCGR6这7个寄存器。控制着所有外设时钟开关。
以CCM_CCGR0为例:
每 2 位控制一个外设的时钟,比如 bit31:30 控制着
GPIO2 的外设时钟,两个位就有 4 中操作方式,00:关闭,01:运行模式下开启。10:未使用,11:除停止模式外,其他所有模式都打开。
代码编写
代码分析
前面原理分析可知,GPIO使用需要如下步骤:
- 使能GPIO对应时钟
- 设置复用寄存器,选择功能
- 设置配置寄存器,配置IO属性
- 设置GPIO属性。
- 控制GPIO。
代码编写
新建工程
新建1.leds文件夹,在文件夹内新建led.s文件,.vscode文件夹。其中.vscode文件夹是vs工程。
代码
vscode打开文件夹,编辑led.s代码:
.global _start /*全局标识*/
/* _start函数,程序从此函数开始执行,此函数完成
时钟使能,GPIO初始化,最终控制GPIO输出低电平
点亮LED灯 */
_start:
/* 1.使能所有时钟 */
ldr r0, =0x020C4068 /* 寄存器CCGR0 */
ldr r1, =0xffffffff
str r1, [r0]
ldr r0, =0x020C406C /* 寄存器CCGR1 */
str r1, [r0]
ldr r0, =0x020C4070 /* 寄存器CCGR2 */
str r1, [r0]
ldr r0, =0x020C4074 /* 寄存器CCGR3 */
str r1, [r0]
ldr r0, =0x020C4078 /* 寄存器CCGR4 */
str r1, [r0]
ldr r0, =0x020C407C /* 寄存器CCGR5 */
str r1, [r0]
ldr r0, =0x020C4080 /* 寄存器CCGR6 */
str r1, [r0]
/* 2.设置GPIO1_IO04为复用GPIO1_IO04 */
ldr r0, =0x020E006C /* 将寄存器SW_MUX_CTL_PAD_GPIO1_IO04 添加到r0中 */
ldr r1, =0x05 /* 设置寄存器的MUX_MODE为5*/
str r1, [r0]
/*
3.配置GPIO1_IO04的IO属性
*bit 16:0 HYS关闭
*bit 15:14 :00默认下拉
*bit 13 :0 keeper使能
*bit 12 :1 pull/keeper使能
*bit 11 : 0 关闭开路输出
*bit 7:6 :10 速度100Mhz
*bit 5:3 : 110 R0/6驱动能力
*bit 0 : 0 低转换率
*/
ldr r0, =0x20E02F8 /* 寄存器SW_PAD_GPIO1_IO03_BASE */
ldr r1, =0x10B0 /* */
str r1, [r0]
/* 4.设置GPIO1_IO04为输出*/
ldr r0, =0X0209C004 /* 寄存器 GPIO1_GDIR */
ldr r1, =0X00000010 /* */
str r1, [r0]
/* 5.打开LED */
ldr r0, =0X0209C000 /* 寄存器 GPIO1_DR */
ldr r1, =0x00000010 /* */
str r1, [r0]
loop:
b loop
编译链接
- 编译:将程序换换成二进制文件,生成.o文件
arm-linux-gnueabihf-gcc -g -c led.s -o led.o
- 链接:将多个.O文件连接到一起,从指定地址开始。
arm-linux-gnueabihf-ld -Ttext 0X87800000 led.o -o led.elf
- 格式转换:将链接好的文件转换为.bin文件
arm-linux-gnueabihf-objcopy -O binary -S -g led.elf led.bin
- 反汇编:将elf文件反汇编为.dis文件
arm-linux-gnueabihf-objdump -D led.elf > led.dis
Makefile文件
为了方便编译,一般把多条指令编辑成Makefile文件。
led.bin:led.s
arm-linux-gnueabihf-gcc -g -c led.s -o led.o
arm-linux-gnueabihf-ld -Ttext 0X87800000 led.o -o led.elf
arm-linux-gnueabihf-objcopy -O binary -S -g led.elf led.bin
arm-linux-gnueabihf-objdump -D led.elf > led.dis
clean:
rm -rf *.o led.bin led.elf led.dis
程序烧录运行
下载代码到SD卡
前面我们已经得到了led.bin文件,下面还需要在bin文件前添加一个头部信息,才可以运行。我们使用的工具是正点原子提供的imxdownload软件。
- 将软件拷贝到代码所在文件夹
- 给软件开执行权限
chmod 777 imxdownload
- 查看U盘盘符
ls /dev/sd*
- 烧录代码
./imxdownload led.bin /dev/sdc
运行
运行前需要把开发板调到SD卡启动模式,然后把SD卡查到卡槽内,上电看到彩灯红色亮,即控制了IO输出低电平。
开发板启动方式选择如下: