一.LED灯的点亮——从简单的汇编开始了解

首先,我们一步步从汇编开始点亮板子上的LED灯!

为什么要先从汇编开始呢?一般来说我们只用C写程序就行了,但是系统上电以后要对SOC的外设、DDR进行初始化(我们用的是I.MX6U,不需要这一步),设置堆栈指针(一般指向DDR),设置好C语言的环境关闭看门狗等流程,但这些功能用C是无法实现的,必须通过汇编来做。好在只需要简单几个指令就可以了。

下面我们从开发板的LED硬件来分析下原理:

先看下硬件原理图:

                 

灯通过3.3V供电,经过510欧的限流电阻和控制口LED0相连,通过搜索查询,我们发现LED0节点和GPIO_3相连(应该是GPIO1_3)

以前搞过STM32的伙伴们应该知道,要对IO进行初始化,需要下面的流程:

  1. 使能GPIO时钟
  2. 设置IO复用,将其设置为GPIO
  3. 配置GPIO的电气属性
  4. 使用GPIO,输出高低电平

对于IMX6ULL来说,流程基本是一样的,我们一步一步来设置

一.使能GPIO时钟:

查询IMX6ULL的芯片手册,CCM_CCGR0-6一共7个寄存器控制了6UL上所有的外设时钟的使能(第18.6.23章 CCM Clock Gating Register 0 (CCM_CCGR0)),而gpio1对应的时钟管理是归属于CCM_CCGR1的26、27两个bit管理,要想使能这个时钟,将其按照要求设置就可以了

设置值得要求

 简单化,只要把两个比特值都置一就行了。更简单,吧CCGR0-6都设为0xFFFFFFFF,相当于使能所有外设时钟。

 二.IO复用设置

 复用设置的管理属于IOMUX Controller管理,查询芯片手册,我们要设置的是GPIO1的IO3,要设置的是IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO03(SW_MUX_CTL_PAD_GPIO1_IO03 SW MUX Control Register )

下面有个表是对其进行说明的

 复用模式(MUX_MODE)一共有7种模式,对应3-0bit,我们是要使用GPIO功能,也就是对应0101=5。

三.设置电气属性

下面要对GPIO1_IO03的电气属性进行设置。可以查下目录,管理其属性的寄存器是IOMUXC_SW_PAD_CTL_PAD_GPIO1_IO03(32.6.156 SW_PAD_CTL_PAD_GPIO1_IO03 SW PAD Control Register)注意跟复用的区别,一个是PAD,一个是MUX

这个电气属性的内容比较多

Field Description
 

0     ODE_0_Open_Drain_Disabled — Open Drain Disabled

1     ODE_1_Open_Drain_Enabled — Open Drain Enabled

31–17
-

This field is reserved.
Reserved

16
HYS

Hyst. Enable Field
Select one out of next values for pad: GPIO1_IO03

0  HYS_0_Hysteresis_Disabled — Hysteresis Disabled
1  HYS_1_Hysteresis_Enabled — Hysteresis Enabled

15–14
PUS

Pull Up / Down Config. Field
Select one out of next values for pad: GPIO1_IO03

00  PUS_0_100K_Ohm_Pull_Down — 100K Ohm Pull Down
01  PUS_1_47K_Ohm_Pull_Up — 47K Ohm Pull Up
10  PUS_2_100K_Ohm_Pull_Up — 100K Ohm Pull Up
11  PUS_3_22K_Ohm_Pull_Up — 22K Ohm Pull Up

13
PUE

Pull / Keep Select Field

Select one out of next values for pad: GPIO1_IO03

0  PUE_0_Keeper — Keeper
1  PUE_1_Pull — Pull

12
PKE

 

Pull / Keep Enable Field
Select one out of next values for pad: GPIO1_IO02

 

0  PKE_0_Pull_Keeper_Disabled — Pull/Keeper Disabled
1  PKE_1_Pull_Keeper_Enabled — Pull/Keeper Enabled

11
ODE

 

Open Drain Enable Field
Select one out of next values for pad: GPIO1_IO02

 

10–8

-

 This field is reserved.
Reserved
 7–6
SPEED
Speed Field
Select one out of next values for pad: GPIO1_IO03
00  SPEED_0_low_50MHz_ — low(50MHz)
01  SPEED_1_medium_100MHz_ — medium(100MHz)
10  SPEED_2_medium_100MHz_ — medium(100MHz)
11  SPEED_3_max_200MHz_ — max(200MHz)
 5–3
DSE

Drive Strength Field
Select one out of next values for pad: GPIO1_IO03

000  DSE_0_output_driver_disabled_ — output driver disabled;
001  R0(3.3V下为260Ω,1.8V下为150Ω,接DDR时为240Ω)
010  DSE_2_R0_2 — R0/2
011  DSE_3_R0_3 — R0/3
100  DSE_4_R0_4 — R0/4
101  DSE_5_R0_5 — R0/5
110  DSE_6_R0_6 — R0/6
111  DSE_7_R0_7 — R0/7

 
 2–1
-
This field is reserved.
Reserved 
 

0
SRE

 
 

Slew Rate Field
Select one out of next values for pad: GPIO1_IO02

0  SRE_0_Slow_Slew_Rate — Slow Slew Rate
1  SRE_1_Fast_Slew_Rate — Fast Slew Rate

也就是说寄存器IOMUSXC_SW_PAD_CTL_PAD_GPIO1_IO03是用来配置GPIO_IO03的,包括速度、驱动能力压摆率等设置,下面挨个分析下这几个参数

  • SRE(bit0):压摆率,指IO电平反转所需要的时间,时间越小波形就越抖,即压摆率高。0的时候为低压摆率,1时为高。当我们的IO做高速IO时要设置为1
  • DSE(bit5-3):当IO作为输出时的驱动能力。共8个选项,0为关闭驱动,其余对应表格查询即可
  • SPEED(bit7-6):IO用作输出时的IO速度,按需求依据表格设置
  • ODE(bit11):IO作为输出时,是否使能开路输出,0时禁止开路输出,1时使能
  • PKE(bit12):用来使能或禁止上下拉、状态保持器的功能:0时禁止上下拉/状态保持器,1时使能
  • PUE(bit13):当IO为输如的时候,用来设置IO使用上下拉还是状态保持器:1时为上下拉,0时为状态保持器,即外部电路断电后此IO口可保持以前的状态。
  • PUS(bit15-14):设置上下拉电阻阻值,按需设置
  • HYS(bit16):使能迟滞比较器,当IO作为输入功能时有效,用于设置输入接收器的施密特触发器是否使能,如果需要对输入波形进行整形的时候可以使能此位,0时禁止,1时使能

整个功能图如图所示

四.GPIO配置

这里还有一个要配置是在STM32里没有的:配置GPIO,包含输入/输出,数据等等

手册里有一章是专门讲GPIO的(Chapter28) ,查寄存器目录发现有8个寄存器是我们需要设置的

GPIO data register(GPIOx_DR)

GPIO数据寄存器,一共32位,对应了IO的32个点,当GPIO配置为输出到时候时,0为低电平,1为高电平。当GPIO为输出到模式时,每个位对应一个GPIO,比方GPIO1_IO00引脚接地时,GPIO.DR的bit0值为0

 GPIO direction register (GPIOx_GDIR)

方向寄存器(GPIO direction register (GPIOx_GDIR),28.5.2)

同样也是32位,表明32个IO点工作的方向,0为输入,1为输出

我们需要的是将GPIO1_IO03设置为输出模式,就要将GPIO1_GDIR的第3个bit置1

剩下的还有PSR,ICR1,ICR2,IMR,ISR,EDGE_SEL我们暂时用不到,这里就先不讲了,总之,GPIO的整体配置流程如下图所示

 

代码编写

这里使用汇编来实现,汇编语言的介绍我们放在另一章来讲。反正这里要用到就是读取、写入寄存器。

就按照前面的流程,先使能GPIO时钟,这里为了简化操作,把所有Soc和GPIO1一个寄存器控制的所有外设都设为使能,也就是将CCM_CCGR1全都使能。

CCM_CCGR1的地址为20C_4000h base + 6Ch offset = 20C_406Ch(0x020c406c)

    /*使能所有外设时钟 */
    ldr r0,=0x020c4068   @CCGR0
    ldr r1,=0xffffffff   @向CCGR0待写入的数据
    str r1,[r0]          @将r1里的数据写入r0地址的寄存器

第二步就是设置复用,对应寄存器为IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO03,地址为0x020e0068,应讲MUX_MODE设置为ALT5

@设置复用IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO03 = 5
    ldr r0,=0x020e0068
    ldr r1,=0x5
    str r1,[r0]

 第三步是设置电气属性,设置寄存器

IOMUXC_SW_PAD_CTL_PAD_GPIO1_IO03 地址0x020E02F4,对应前面的分解说明,按照下面的要求设置
  • bit 16:0 HYS关闭
  • bit [15:14]: 00 默认下拉
  • bit [13]: 0 kepper功能
  • bit [12]: 1 pull/keeper使能
  • bit [11]: 0 关闭开路输出
  • bit [10-8]: 000 空
  • bit [7:6]: 10 速度100Mhz
  • bit [5:3]: 110 R0/6驱动能力
  • bit [2:1]: 00 空
  • bit [0]: 0 低转换率
写下来就是00001 0000 1011 0000,也就是0x10B0,使用代码实现,就是
    ldr r0,=0x020e02f4
    ldr r1,=0x10b0
    str r1,[r0]

第四步是将GPIO设置为输出模式,也就是将GPIO1_GDIR的第2个bit置1,换算值为0x8,GPIO1_GDIR的地址为0x209c004

    ldr r0,=0x0209c004
    ldr r1,=0x8
    str r1,[r0]

下一步就是给GPIO的数据寄存器赋值,注意看前面的硬件原理图,我们的LED要想点亮的话控制端需要为低电平,所以直接把GPIO1的值置0就好,GPIO1_DR的地址为0x209c000

    ldr r0,=0x0209C000
    ldr r1,=0
    str r1,[r0]

最后放个死循环,让程序跑起来就行了

loop:
    b loop

最后放上所有的代码

.global _start @全局标号
_start:
@ 开启所有时钟CCM_CCGR0-6

    /*使能所有外设时钟 */
    ldr r0,=0x020c4068   @CCGR0
    ldr r1,=0xffffffff   @向CCGR0待写入的数据
    str r1,[r0]          @将r1里的数据写入r0地址的寄存器内

@设置复用IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO03 = 5
    ldr r0,=0x020e0068
    ldr r1,=0x5
    str r1,[r0]

@设置电气属性IOMUXC_SW_PAD_CTL_PAD_GPIO1_IO03 地址0x020E02F4
/*
    @  *bit 16:0 HYS关闭
    @  *bit [15:14]: 00 默认下拉
    @  *bit [13]: 0 kepper功能
    @  *bit [12]: 1 pull/keeper使能
    @  *bit [11]: 0 关闭开路输出
    @  *bit [10-8]: 000 空
    @  *bit [7:6]: 10 速度100Mhz
    @  *bit [5:3]: 110 R0/6驱动能力
    @  *bit [2:1]:  00  空
    @  *bit [0]: 0 低转换率
    @   00001 0000 1011 0000>0x10B0
 */

    ldr r0,=0x020e02f4
    ldr r1,=0x10b0
    str r1,[r0]

/*设置GPIO1_IO03为输出,
GPIO1_GDIR地址为 0x209_C004
IO03对应第2bit,值为0x8
*/
    ldr r0,=0x0209C004
    ldr r1,=0x8
    str r1,[r0]

/*设置GPIO输出高电平
GPIO1_DR,地址为0x209_C000
IO03对应第3bit,低电平时灯点亮,值为0
*/

    ldr r0,=0x0209C000
    ldr r1,=0
    str r1,[r0]

loop:
    b loop
code

整个代码的流程就完了,因为代码已经跑过,我这里就不讲调试的过程了,下一章再仔细讲一下如何编译代码

原文地址:https://www.cnblogs.com/yinsedeyinse/p/15726822.html