i.MX6 裸机 汇编 | GPIO驱动编写


书接上文

i.MX6 裸机 汇编 | GPIO硬件原理分析

还是从STM32对比过来进行学习。C语言类比到汇编到底要怎么转换代码思路。

STM32指令

在C语言中,对于代码操作,我们只需要关心变量就可以了,对我们来说,变量都在在RAM中,不需要知道寄存器地址。

例如

int a,b;

a = b;

这是典型的C语言写法,把b的值赋给a,但是在汇编语言中,情况就变得不一样了,需要对寄存器进行操作。

汇编指令

我先写一下汇编中的实现代码,然后在进行分析讲解

假设a的地址为0x20,b的地址为0x30

LDR R0,=0x30
LDR R1,[R0]

LDR R0,=0x20
STR R1,[R0]

上面的一段汇编指令,主要用到了LDR和STR

然后来介绍这两个指令

在这里插入图片描述

LDR指令

LDR主要用于从存储加载数据到寄存器 Rx中, LDR也可以将一个立即数加载到寄存器 Rx中, LDR加载立即数的时候要使用“ “=”,而不是 “#”。在嵌入式开发中 LDR最常用的就是读取 CPU的寄存器值,比如 I.MX6UL有个寄存器 GPIO1_GDIR,其地址为 0X0209C004,我们现在要读取这个寄存器中的数据,示例代码如下:

LDR R0, =0X0209C004 @将寄存器地址0X0209C004加载到R0中,即R0=0X0209C004 
LDR R1, [R0] @读取地址0X0209C004中的数据到R1寄存器中

上述代码就是读取寄存器 GPIO1_GDIR中的值,读取到的寄存器值保存在 R1寄存器中,
上面代码中 offset是 0,也就是没有用到 offset。

STR指令

LDR是从存储器读取数据, STR就是将数据写入到存储器中,同样以 I.MX6UL寄存器
GPIO1_GDIR为例,现在我们要配置寄存器 GPIO1_GDIR的值为 0X2000002,示例代码如下

LDR R0, =0X0209C004 @将寄存器地址0X0209C004加载到R0中,即R0=0X0209C004
LDR R1, =0X20000002 @R1保存要写入到寄存器的值,即R1=0X20000002
STR R1, [R0] @将R1中的值写入到R0中所保存的地址中

LDR和 STR都是按照字进行读取和写入的,也就是操作的 32位数据,如果要按照字节、
半字进行操作的话可以在指令“ LDR”后面加上 B或 H,比如按字节操作的指令就是 LDRB和
STRB,按半字操作的指令就是 LDRH和 STRH。

对于我们刚才的代码,现在就可以很清楚的知道

LDR R0,=0x30
LDR R1,[R0]

LDR R0,=0x20
STR R1,[R0]

R0首先得到b的地址,现在R0 = 0x30,通过间接寻址符号[],[R0]表示0x30地址的值,也就是b的值,存储到R1中,现在R1 等于 b的值

然后R0得到a的地址,现在a 等于 [R0],通过STR指令,将数据写入到存储器,也就是R1的数据写入到[R0]中,R1存储的是b的值,也就完成了b到a的赋值操作。

解释一下[],这个中括号的问题,这个括号有什么意义?

[ ]表示是间接寻址,bx和[bx]的区别是,前者操作数就是bx中存放的数,后者操作数是以bx中存放的数为地址的单元中的数。

比如bx中存放的数是40F6H
40F6H、40F7H两个单元中存放的数是22H、23H,则

mov ax,[bx];  @2223H传送到ax中
mov ax,bx;    @40F6H传送到ax中

[bx]把bx存放的数当作地址,找到地址40F6H,传送了地址指向的两个字节22H、23H

编写驱动

有了上面的简单认识,现在就可以在VScode上面敲写代码了。

新建一个“.s”格式的文件,我的文件名叫做“GPIOs.s”还另存为了一个“GPIOS”的工作区。

在这里插入图片描述

使能时钟

首先是时钟的初始化,在

《 IMX6芯片手册》

中找到18.6.23这一节,可以看到

在这里插入图片描述

这里是配置时钟的寄存器,我们要把全部的时钟都使能,需要找到CCM_CCGR0寄存器的地址,往下拉,在这个位置:

Address: 20C_4000h base + 68h offset = 20C_4068h

这里有一个地方,地址 20c4068h 最后的 h 是表示16进制,所以地址在使用时候要写成

020c4068

在这里插入图片描述

所以,我们在代码中就可以这样来把CCGR寄存器全部置1

    ldr r0, =0x020c4068     @CCGR0
    ldr r1, =0xffffffff     @要向CCGR0写入的数据
    str r1, [r0]           @将0xffffffff写入到CCGR0

    ldr r0, =0x020c406c     @CCGR1
    str r1, [r0]           @将0xffffffff写入到CCGR1

    ldr r0, =0x020c4070     @CCGR2
    str r1, [r0]           @将0xffffffff写入到CCGR2

    ldr r0, =0x020c4074     @CCGR3
    str r1, [r0]           @将0xffffffff写入到CCGR3

    ldr r0, =0x020c4078     @CCGR4
    str r1, [r0]           @将0xffffffff写入到CCGR4

    ldr r0, =0x020c407c     @CCGR5
    str r1, [r0]           @将0xffffffff写入到CCGR5

    ldr r0, =0x020c4080     @CCGR6
    str r1, [r0]           @将0xffffffff写入到CCGR6

IO复用 配置

与时钟的配置思路相同,先找到对应寄存器的地址,然后对相应的位置进行赋值操作。

《 IMX6芯片手册》

找到36.4.135 的IOMUXC_SW_MUX_CTL_PAD_GPIO03的寄存器地址

Address: 20E_0000h base + 22Ch offset = 20E_022Ch

在这里插入图片描述

对于模式的选择,可以看到我们需要的GPIO1_IO03是101 = 5,也就是给寄存器地址20e022ch赋值0x00000101就可以了。

在这里插入图片描述

    /*IO复用 配置GPIO1_IO03 PIN的复用为GPIO,也就是设置寄存器
     *IOMUXC_SW_MUX_CTL_PAD_GPIO03 = 5
     *IOMUXC_SW_MUX_CTL_PAD_GPIO03 地址为0x20e022ch
     */

    ldr r0, =0x020e022c     @IOMUXC_SW_MUX_CTL_PAD_GPIO03
    ldr r1, =0x5     		@要向IOMUXC_SW_MUX_CTL_PAD_GPIO03写入的数据
    str r1, [r0]           @将0x00000101 = 5写入到IOMUXC_SW_MUX_CTL_PAD_GPIO03

电气属性 配置

配置GPIO1_IO03的电气属性,依旧是

《 IMX6芯片手册》

找到36.4.379 的IOMUXC_SW_PAD_CTL_PAD_GPIO03寄存器位置

在这里插入图片描述
电气参数配置从下往上看
在这里插入图片描述
在这里插入图片描述

    /* 配置GPIO01_IO3的电气属性 也就是寄存器:
     * IOMUXC_SW_PAD_CTL_PAD_GPIO03
     * IOMUXC_SW_MUX_CTL_PAD_GPIO03 寄存器地址为0x20e05fch
     * 
     * bit0:       0     低速率
     * bit5:3      110   R0/6驱动能力
     * bit7:6      10    100MHz速度
     * bit11:      0     关闭开路输出
     * bit12:      1     使能pull/kepper
     * bit15:14:   00    默认100K下拉
     * bit16:      0     关闭hys
     */

    ldr r0, =0x020e05fc
    ldr r1, =0x0x10b0
    str r1, [r0]           @将0x0x10b0写入到IOMUXC_SW_PAD_CTL_PAD_GPIO03

地址怎么计算呢,拿出微软自带的计算器,切换到程序员模式,手动点就可以了,恩,没错,就是辣么机智。
在这里插入图片描述

配置GPIO功能

《 IMX6芯片手册》

找到GPIO章节地址在28.5 GPIO Memory Map/Register Definition中找到

GPIO1_GDIR寄存器地址为209c004

在这里插入图片描述

GPIOx_GDIR用来配置接口是输入还是输出,GPIO1_IO03在第三个位置,0-31位的GPIOx也就是00000000000000000000000001000,对应到HEX,也就是8

所以寄存器的值为0x000000008 = 0x8

    /* 设置GPIO
     * 设置GPIO1_GDIR寄存器,设置GPIO1_GPIO03为输出
     * GPIO1_GDIR寄存器地址为209c004,设置GPIO1_GDIR寄存器bit3为1
     * 也就是设置GPIO1_IO03为输出
     */

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

在这里插入图片描述
下面设置GPIO1_DR,也是先找到地址,DR就可以配置高低电平了

在这里插入图片描述

     /* 设置GPIO1_IO03 为1 
      * GPIO1_DR寄存器地址为0x0209c000
      */

      ldr r0, = 0x0209c00
      ldr r1, 1
      str r1, [r0]

驱动代码



.global _start @全局标号



_start:

    /* 使能所有外设时钟 */

    ldr r0, = 0x020c4068     @CCGR0

    ldr r1, = 0xffffffff     @要向CCGR0写入的数据

    str r1,   [r0]           @将0xffffffff写入到CCGR0

 

    ldr r0, = 0x020c406c     @CCGR1

    str r1,   [r0]           @将0xffffffff写入到CCGR1

 

    ldr r0, = 0x020c4070     @CCGR2

    str r1,   [r0]           @将0xffffffff写入到CCGR2

 

    ldr r0, = 0x020c4074     @CCGR3

    str r1,   [r0]           @将0xffffffff写入到CCGR3

 

    ldr r0, = 0x020c4078     @CCGR4

    str r1,   [r0]           @将0xffffffff写入到CCGR4

 

    ldr r0, = 0x020c407c     @CCGR5

    str r1,   [r0]           @将0xffffffff写入到CCGR5

 

    ldr r0, = 0x020c4080     @CCGR6

    str r1,   [r0]           @将0xffffffff写入到CCGR6





    /* IO复用 配置GPIO1_IO03 PIN的复用为GPIO,也就是设置寄存器

     * IOMUXC_SW_MUX_CTL_PAD_GPIO03 = 5

     * IOMUXC_SW_MUX_CTL_PAD_GPIO03 地址为0x20e022ch

     */



    ldr r0, = 0x020e022c    @IOMUXC_SW_MUX_CTL_PAD_GPIO03

    ldr r1, = 0x5           @要向IOMUXC_SW_MUX_CTL_PAD_GPIO03写入的数据

    str r1,   [r0]          @将0x00000101 = 5写入到IOMUXC_SW_MUX_CTL_PAD_GPIO03



    /* 配置GPIO01_IO3的电气属性 也就是寄存器:

     * IOMUXC_SW_PAD_CTL_PAD_GPIO03

     * IOMUXC_SW_MUX_CTL_PAD_GPIO03 寄存器地址为0x20e05fch

     * 

     * bit0:       0     低速率

     * bit5:3      110   R0/6驱动能力

     * bit7:6      10    100MHz速度

     * bit11:      0     关闭开路输出

     * bit12:      1     使能pull/kepper

     * bit15:14:   00    默认100K下拉

     * bit16:      0     关闭hys

     */



    ldr r0, = 0x020e05fc

    ldr r1, = 0x10b0

    str r1,   [r0]           @将0x0x10b0写入到IOMUXC_SW_PAD_CTL_PAD_GPIO03



    /* 设置GPIO

     * 设置GPIO1_GDIR寄存器,设置GPIO1_GPIO03为输出

     * GPIO1_GDIR寄存器地址为209c004,设置GPIO1_GDIR寄存器bit3为1

     * 也就是设置GPIO1_IO03为输出

     */



     ldr r0, = 0x0209c004

     ldr r1, = 0x8

     str r1,   [r0]           



     /* 设置GPIO1_IO03 为1 

      * GPIO1_DR寄存器地址为0x0209c000

      */



      ldr r0, = 0x0209c000

      ldr r1, = 0x1

      str r1, [r0]



loop:                       @b loop 在73 74行死循环

    b loop


汇编驱动编写好了,下一步就是编译了,下篇文章见。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值