IMX6ULL -- 汇编led

汇编led

一、原理图

原理图部分:

 

 

可以看出DS0是一个发光二极管,当LED0为低时,DS0亮起。

LED0接GPIO1_IO3

GPIO IO初始化流程:

1. 使能GPIO时钟,根据imx6ull数据手册可看出CCGR0-CCGR7使能了所有的外设的时钟,可设置这7个寄存器全部为0xffffffff,相当于使能所有的外设,CCM_CCRG:clock controll module_clock gating register

2. 设置IO服用,将寄存器IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO03其复用为GPIO,bit0-bit3设置为0101

3. 配置GPIO的电气属性,IOMUXC_SW_PAD_CTL_PAD_GPIO1_IO03设置电气属性

包括压摆率、速度、驱动能力、开漏、上下拉等

4.配置GPIO功能,设置输入输出。设置GPIO1_DR寄存器bit3为1,也就是设置为输出模式,bit3为1表示高电平,为0表示输出低电平

二、GNU汇编语法

汇编程序的默认入口标号是_start,不过我们也可以在链接脚本中使用 ENTRY 来指明其它

的入口点,下面的代码就是使用_start 作为入口标号:

.global _start      // 全局标号
_start: 
    ldr r0, =0x12 @r0=0x12

1、LDR 指令

LDR 主要用于从存储加载数据到寄存器 Rx 中,

LDR 也可以将一个立即数加载到寄存器 Rx

中,LDR 加载立即数的时候要使用“=”,而不是“#”。在嵌入式开发中,LDR 最常用的就是读

取 CPU 的寄存器值,比如 I.MX6UL 有个寄存器 GPIO1_GDIR,其地址为 0X0209C004,我们

现在要读取这个寄存器中的数据,示例代码如下:

示例代码 7.2.2.1 LDR 指令使用

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

上述代码就是读取寄存器 GPIO1_GDIR 中的值,读取到的寄存器值保存在 R1 寄存器中,

上面代码中 offset 是 0,也就是没有用到 offset。

R0-R7:因为ARM指令不能直接读取RAM里面的数据,所以要借助R0等寄存器

2、STR 指令

LDR 是从存储器读取数据,STR 就是将数据写入到存储器中,同样以 I.MX6UL 寄存器

GPIO1_GDIR 为例,现在我们要配置寄存器 GPIO1_GDIR 的值为 0X20000002,示例代码如下:

示例代码 7.2.2.2 STR 指令使用

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。

三、汇编代码

.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_IO03复用为GPIO1_IO03 */
        ldr r0, =0X020E0068     /* 将寄存器SW_MUX_GPIO1_IO03_BASE加载到r0中 */
        ldr r1, =0X5            /* 设置寄存器SW_MUX_GPIO1_IO03_BASE的MUX_MODE为5 */
        str r1,[r0]

        /* 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、设置GPIO1_IO03为输出 */
    ldr r0, =0X0209C004 /*寄存器GPIO1_GDIR */
    ldr r1, =0X0000008
    str r1,[r0]

        /* 5、打开LED0
         * 设置GPIO1_IO03输出低电平
         */
        ldr r0, =0X0209C000     /*寄存器GPIO1_DR */
   ldr r1, =0
   str r1,[r0]

/*
 * 描述:       loop死循环
 */
loop:
        b loop

四、编译程序

  1. 使用arm-linux-gnueabihf-gcc将.c .s文件变成.o文件

  2. 将所有的.o文件链接为elf格式的可执行文件,链接就是将所有的.o文件链接在一起,并且链接到指定的地方

  3. 将elf文件转成bin文件便于烧录

链接的时候要指定链接起始地址 ,链接起始地址就是代码运行的起始地址

对于imx6ull来说,链接起始地址应该指向RAM地址。RAM分为内部RAM和外部RAM,也就是DDR,imx6ull内部RAM地址为0x900000-0x91ffff,也可以放在外部DDR中,对于alpha512字节开发板而言,DDR范围就是0x80000000-0x9fffffff。要使用DDR,那么必须初始化DDR,对于IMX来说bin文件不能直接运行,需要添加一个头部,这个头部信息包含了DDR的初始化参数,IMX系列SOC内部boot rom会从SD卡,EMMC等外置存储中读取头部信息,然后初始化DDR,并且将bin文件拷贝到链接地址处。

bin文件的运行地址一定要和链接起始地址一致,位置无关代码除外

四、烧写bin文件

imx6ull支持SD卡,EMMC、NAND、nor、spi flash等等启动。裸机例程选择烧写到sd卡中

在ubuntu下向SD卡烧写裸机bin文件。烧写不是将bin文件拷贝到SD卡中,而是将bin文件烧写到SD卡绝对路径,需要借助imxdownload工具

imxdownload会向led.bin添加一个头部,生成新的load.imx文件,这个load.imx文件就是最终烧写到SD卡里面去的

猜你喜欢

转载自blog.csdn.net/qq_58550520/article/details/132398772