基于IMX6ULL的嵌入式Linux开发学习笔记——(2)五种不同的LED点灯方式之GPIO原理+汇编执行

    在本章中,笔者会逐步介绍在IMX6ULL中的五种LED点灯方式——
(1)纯汇编语言;
(2)汇编混合C语言;
(3)STM32风格;
(4)基于NXP官方提供SDK;
(5)最终版本的ledc_bsp,并以此为基础进行后续的裸机外设开发。

1.纯汇编语言

Cortex-A7常用汇编指令:

(1) MOV

MOV R0,R1	      //将数据从一个寄存器拷贝到另一个寄存器
MOV R0,#0XFF     //或将一个立即数传到寄存器里面;

(2) MRS 读特殊寄存器

MRS R0,CPSR	//将特殊寄存器(CPSR/SPSR)里面的传给通用寄存器

(3) MSR 写特殊寄存器

MSR CPSR,R0		//将通用寄存器的传给特殊寄存器(CPSR/SPSR)

(4) LDR 将立即数加载到寄存器中

LDR R0, =0X0209C004; 	//即R0=0X0209C004,将寄存器地址给R0
LDR R1, [R0]; 			//将R0地址0X0209C004里面的数据给R1

(5) STR 将数据写入存储器中

LDR R0, =0X0209C004; 	//即R0=0X0209C004,将寄存器地址给R0
LDR R1, =0X20000002;	//即R1=0X20000002,将要写入的值给R1
STR R1,[R0];			//将R1的值写入R0的地址中(STR、LDR作用相反 )
对比STM32和IMX6ULL的GPIO初始化

STM32 IO初始化流程:
(1) 使能GPIO时钟
(2) 设置IO复用,将其复用为GPIO
(3) 配置GPIO的电气属性
(4) 使用GPIO,输出高/低电平

由此对比,IMX6ULL的GPIO初始化也可以根据以上步骤进行套用。

IMX6ULL IO初始化流程:

(1) 使能时钟CCGR0-CCGR6,即IMX6ULL所有外设时钟使能;为简单化,设置CCGR0-CCGR6这7个寄存器均为0XFFFFFFFF,相当于使能所有外设时钟。
/*
以CCGR0的使能时钟举例,将CCGR0这一寄存器的地址0X020C4068作为立即数加载至r0寄存器中,
将0XFFFFFFFF这一立即数加载至r1寄存器中,str指令将r1这一立即数,写入r0所指向地址,
则此时0X020C4068地址里被写入0XFFFFFFFF,CCGR0总时钟源使能成功,此后CCGR1~6各时钟使能同理。
*/
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) 设置IO复用

在这里插入图片描述
    查询数据手册可知
IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO00的Address: 20E_005Ch
GPIO1_IO00: 20E_0000h base + 5Ch offset = 20E_005Ch
GPIO1_IO01: 20E_0000h base + 60h offset = 20E_0060h
GPIO1_IO02: 20E_0000h base + 64h offset = 20E_0064h
GPIO1_IO03: 20E_0000h base + 68h offset = 20E_0068h

    由此可以看出,这一寄存器每个占四字节。此时设置IO复用,将IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO03的bit3~0设置为0101,即为5,此时GPIO_IO03复用为GPIO了。

/* 2、设置GPIO1_IO03复用为GPIO1_IO03 */
ldr r0, =0X020E0068	/* 将寄存器地址加载到r0中 */
ldr r1, =0X5		/* 设置寄存器SW_MUX_GPIO1_IO03_BASE的MUX_MODE为5 */
str r1,[r0]			/* 将0101写入复用SW_MUX的地址0X020E0068,设置复用完成*/
(3)配置GPIO的电气属性

    将寄存器IOMUXC_SW_PAD_CTL_PAD_GPIO1_IO03进行配置,其中包括压摆率、速度、驱动能力、开漏、上下拉等。

/* 3、配置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 低转换率
 */
ldr r0, =0X020E02F4	/*寄存器SW_PAD_GPIO1_IO03_BASE */
ldr r1, =0X10B0
str r1,[r0]
(4) 使用GPIO,设置输入输出。

    设置GPIO1_GDIR寄存器bit3位1,设置为输出模式。(配置DR/GDIR)
在这里插入图片描述
    如上图所示,设置为SW_MUX_CTL_PAD和SW_PAD_CTL_PAD后,就要设置GPIO的DR、GDIR、PSR、ICR1/ICR2、IMR、ISR、EDGE_SEL了。

DR——DataBits 数据寄存器

在这里插入图片描述
    DR为32位寄存器。DR寄存器中每位都对应一个GPIO。
    当 GPIO 被配置为输出功能以后,向指定的位写入数据那么相应的 IO 就会输出相应的高低电平,比如要设置 GPIO1_IO00 输出高电平,那么就应该设置 GPIO1.DR=1。
    当 GPIO被配置为输入模式以后,此寄存器就保存着对应 IO 的电平值,每个位对对应一个 GPIO,例如,当 GPIO1_IO00 这个引脚接地的话,那么 GPIO1.DR 的 bit0 就是 0。

GDIR——Gpio Direction IO工作方向寄存器

在这里插入图片描述
    GDIR 寄存器也是 32 位的,此寄存器用来设置某个 IO 的工作方向,是输入还是输出。同样的,每个 IO 对应一个位,如果要设置 GPIO 为输入的话就设置相应的位为 0,如果要设置为输出的话就设置为 1。
    比如要设置 GPIO1_IO00 为输入,那么 GPIO1.GDIR=0。

PSR——Pad Stauts Bits 状态寄存器

在这里插入图片描述
    PSR读取相应的位即可获取对应的 GPIO 的状态,也就是 GPIO 的高低电平值。功能和输入状态下的 DR 寄存器一样。

ICR1/ICR2——Interrupt Control 中断控制寄存器

在这里插入图片描述
在这里插入图片描述

IMR——Interrupt Mask 中断屏蔽寄存器

在这里插入图片描述
    IMR 寄存器用来控制 GPIO 的中断禁止和使能,如果使能某个 GPIO 的中断,那么设置相应的位为 1 即可,反之,如果要禁止中断,那么就设置相应的位为 0 即可。例如,要使能 GPIO1_IO00 的中断,那么就可以设置 GPIO1.MIR=1 即可。

ISR——Interrupt Status 中断状态寄存器

在这里插入图片描述
    ISR 寄存器也是 32 位寄存器,一个 GPIO 对应一个位,只要某个 GPIO 的中断发生,那么ISR 中相应的位就会被置 1。所以,我们可以通过读取 ISR 寄存器来判断 GPIO 中断是否发生,相当于 ISR 中的这些位就是中断标志位。
    当我们处理完中断以后,必须清除中断标志位,清除方法就是向 ISR 中相应的位写 1,也就是写 1 清零。

EDGE_SEL——edge select 边沿选择寄存器

在这里插入图片描述

    EDGE_SEL 寄存器用来设置边沿中断,这个寄存器会覆盖 ICR1 和 ICR2 的设置,同样是一个 GPIO 对应一个位。如果相应的位被置 1,那么就相当与设置了对应的 GPIO 是上升沿和下降沿(双边沿)触发。
    例如,我们设置GPIO1.EDGE_SEL=1,那么就表示 GPIO1_IO01 是双边沿触发中断,无论 GFPIO1_CR1 的设置为多少,都是双边沿触发。
######小结
    以上,GPIO的DR、GDIR、PSR、ICR1/ICR2、IMR、ISR、EDGE_SEL均简要进行介绍。这7类8个寄存器为gpio最常用的寄存器。

  1. DR:数据存储;
  2. GDIR:io方向;
  3. PSR:状态寄存,等效输入状态的dr;
  4. ICR1/ICR2:中断控制;
  5. IMR:中断屏蔽;
  6. ISR:中断状态;
  7. EDGE_SEL:边沿选择;

故在此点灯方式中,仅需设置GDIR为输出模式,并设置GPIO1_IO03输出低电平。
即GDIR=1,DR=0。

/* 4、设置GPIO1_IO03为输出 */
ldr r0, =0X0209C004	/*寄存器GPIO1_GDIR的地址 */
ldr r1, =0X0000008	/*转二进制则为1000,此时设置为输出模式*/
str r1,[r0]
/* 5、打开LED0
 * 设置GPIO1_IO03输出低电平
 */
	ldr r0, =0X0209C000	/*寄存器GPIO1_DR */
   ldr r1, =0		
   str r1,[r0]

并且其中Makefile如下,笔者将在第(3)部分继续讲解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
	
总结

    这是极其生硬且难啃的一章,需要对系统时钟、GPIO的复用、GPIO的电气属性,作为GPIO的输入输出以及相关的8个寄存器进行学习。是从STM32到Linux嵌入式的拦路虎,需要对数据手册以及相关的知识进行学习,并且形成博客以此输出知识从而达到加深记忆的目的。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

潜心修行嵌入式Linux的鼠鼠

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值