LED汇编实验

1.原理分析:

为什么要学习Cortex-A汇编?

①需要利用汇编来初始化一些Soc外设;

②需要利用汇编语言来初始化DDR(但我们这里的IMX.6U不需要);

③设置sp指针,一般指向DDR(sp是CPU内部寄存器,用于保存栈顶指针,栈顶指针指向的是RAM,因此要么是内部RAM要么是外部RAM。对于跑linux的Cortex-A芯片而言,一般内部RAM比较小,所以实际使用中都指向外部    RAM,DDR就是外部RAM。),设置好C语言环境。

2.Mini开发板LED硬件原理分析:

回顾:STM32 IO初始化为GPIO:

①、使能指定 GPIO 的时钟。

②、初始化 GPIO,比如输出功能、上拉、速度等等。

③、STM32 有的 IO 可以作为其它外设引脚,也就是 IO 复用,如果要将 IO 作为其它外设引脚使用的话就需要设置 IO 的复用功能。

④、最后设置 GPIO 输出高电平或者低电平。

IMX.6U IO初始化为GPIO的一般步骤:

①、使能 GPIO 对应的时钟。

②、设置寄存器 IOMUXC_SW_MUX_CTL_PAD_XX_XX,设置 IO 的复用功能,使其复用

为 GPIO 功能。

③、设置寄存器 IOMUXC_SW_PAD_CTL_PAD_XX_XX,设置 IO 的上下拉、速度等等。

④、第②步已经将 IO 复用为了 GPIO 功能,所以需要配置 GPIO,设置输入/输出、是否使

用中断、默认输出电平等。

此处LED的GPIO初始化设置为:

I.MX6ULL IO初始化:

①、使能时钟,CCGR0~CCGR6这7个寄存器控制着6ULL所有外设时钟的使能。为了简单,设置CCGR0~CCGR6这7个寄存器全部为0XFFFFFFFF,相当于使能所有外设时钟。

②、IO复用,将寄存器IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO03的bit3~0设置为0101=5,这样GPIO1_IO03就复用为GPIO。

③、寄存器IOMUXC_SW_PAD_CTL_PAD_GPIO1_IO03是设置GPIO1_IO03的电气属性。包括压摆率、速度、驱动能力、开漏、上下拉等。

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

3.汇编基本语法:

汇编由一条一条指令构成,指令就涉及到汇编指令。

例如:C语言的赋值如下:

Int a,b;

a=b;

汇编实现:

假设a地址为0X20,b地址为0x30

LDR R0, =0X30

LDR R1, [R0]

LDR R0, =0X20

STR R1, [R0]

我们在使用汇编编写驱动的时候最常用的就是LDR和STR这两个指令。

4.驱动编写:

leds.s:

 1 .global _start  /* 全局标号 */
 2 
 3 /*
 4  * 描述:_start函数,程序从此函数开始执行此函数完成时钟使能、
 5  * GPIO初始化、最终控制GPIO输出低电平来点亮LED灯。
 6  */
 7 _start:
 8     /* 例程代码 */
 9     /* 1、使能所有时钟 */
10     ldr r0, =0X020C4068     /* CCGR0 */
11     ldr r1, =0XFFFFFFFF  
12     str r1, [r0]        
13     
14     ldr r0, =0X020C406C      /* CCGR1 */
15     str r1, [r0]
16 
17     ldr r0, =0X020C4070      /* CCGR2 */
18     str r1, [r0]
19     
20     ldr r0, =0X020C4074      /* CCGR3 */
21     str r1, [r0]
22     
23     ldr r0, =0X020C4078      /* CCGR4 */
24     str r1, [r0]
25     
26     ldr r0, =0X020C407C      /* CCGR5 */
27     str r1, [r0]
28     
29     ldr r0, =0X020C4080      /* CCGR6 */
30     str r1, [r0]
31     
32     /* 2、设置GPIO1_IO03复用为GPIO1_IO03 */
33     ldr r0, =0X020E0068    /* 将寄存器SW_MUX_GPIO1_IO03_BASE加载到r0中 */
34     ldr r1, =0X5        /* 设置寄存器SW_MUX_GPIO1_IO03_BASE的MUX_MODE为5 */
35     str r1,[r0]
36 
37     /* 3、配置GPIO1_IO03的IO属性    
38      *bit 16:0 HYS关闭
39      *bit [15:14]: 00 默认下拉
40      *bit [13]: 0 kepper功能
41      *bit [12]: 1 pull/keeper使能
42      *bit [11]: 0 关闭开路输出
43      *bit [7:6]: 10 速度100Mhz
44      *bit [5:3]: 110 R0/6驱动能力
45      *bit [0]: 0 低转换率
46      */
47     ldr r0, =0X020E02F4    /*寄存器SW_PAD_GPIO1_IO03_BASE */
48     ldr r1, =0X10B0
49     str r1,[r0]
50 
51     /* 4、设置GPIO1_IO03为输出 */
52     ldr r0, =0X0209C004    /*寄存器GPIO1_GDIR */
53     ldr r1, =0X8        
54     str r1,[r0]
55 
56     /* 5、打开LED0
57      * 设置GPIO1_IO03输出低电平
58      */
59     ldr r0, =0X0209C000    /*寄存器GPIO1_DR */
60    ldr r1, =0        
61    str r1,[r0]
62 
63 /*
64  * 描述:    loop死循环
65  */
66 loop:
67     b loop

 5.程序编译:编译出bin文件即可烧写

①、使用arm-linux-gnueabihf-gcc,将.c .s文件变为.o

②、将所有的.o文件链接为elf格式的可执行文件。

③、将elf文件转为bin文件。

④、将elf文件转为汇编,反汇编。

链接:

  链接就是将所有.o文件链接在一起,并且链接到指定的地方。本实验链接的时候要指定链接起始地址。链接起始地址就是代码运行的起始地址。

  对于6ULL来说,链接起始地址应该指向RAM地址。RAM分为内部RAM和外部RAM,也就是 DDR。6ULL内部RAM地址范围0X900000~0X91FFFF。也可以放到外部DDR中,对于I.MX6U-ALPHA开发板,512MB字节DDR版本的核心板,DDR范围就是0X80000000~0X9FFFFFFF。对于256MB的DDR来说,那就是0X80000000~0X8FFFFFFF(Mini板和Alpha板子一样)。

  但我们默认裸机代码的链接起始地址为0X87800000。要使用DDR,那么必须要初始化DDR,对于I.MX来说bin文件不能直接运行(严格来说,应该是bin文件不能直接烧写到SD卡,EMMC,NAND等外置存储中启动运行,而不是bin文件不能直接运行,使用JLINK将bin文件直接下载到内部RAM中还是可以运行的),需要添加一个头部,这个头部信息包含了DDR的初始化参数,I.MX系列SOC内部boot rom会从SD卡,EMMC等外置存储中读取头部信息,然后初始化DDR,并且将bin文件拷贝到指定的地方。

  Bin的运行地址一定要和链接起始地址一致。位置无关代码除外。

1 cd linux/IMX6ULL/Board_Drivers/1_leds
2 arm-linux-gnueabihf-gcc -g -c leds.s -o led.o
3 arm-linux-gnueabihf-ld -Ttext 0X87800000 led.o -o led.elf
4 arm-linux-gnueabihf-objcopy -O binary -S -g led.elf led.bin
5 arm-linux-gnueabihf-objdump -D led.elf > led.dis

6.bin文件烧写:

  STM32烧写到内部FLASH。

  6ULL支持SD卡、EMMC、NAND、nor、SPI flash等等启动。裸机例程选择烧写到SD卡里面。

  在ubuntu下向SD卡烧写裸机bin文件。烧写不是将bin文件拷贝到SD卡中,而是将bin文件烧写到SD卡绝对地址上。而且对于I.MX而言,不能直接烧写bin文件,必须先在bin文件前面添加头部(之后讲解)。完成这个工作,需要使用正点原子提供的imxdownload软件(使用前先把它复制到1_leds下边)。

  Imxdownload使用方法,确定要烧写的SD卡文件,我的是/dev/sdb。

  给予imxdownload可执行权限:

  Chmod 777 imxdownload

烧写:

1.将tf卡插到读卡器上插到电脑,连接到ubuntu虚拟机;

2.到1_leds文件夹下执行./imxdownload led.bin /dev/sdf(当然,你的SD卡是哪个需要修改)

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

1 ./imxdownload led.bin /dev/sdb

 

4.烧录好之后,拔下来tf卡插到开发板,将拨码开关拨至10000010(SD卡启动模式)。

注意:在将bin文件烧录到SD卡时一定要注意确认好自己的SD卡是哪个,否则即使烧录成功实验现象也可能不对。比如因为我的SD卡插到电脑上出来两个名称(/dev/sdb和/dev/sdb1,出来两个名称的原因是sdb表示我整个的SD卡磁盘,而sdb1是这个SD的一个分区,如果还有其他分区可能会有sdb2之类的),我烧录到sdb1成功了但实验现象不正确,sdb也烧录成功了现象正确。

5.上电之后就可以看到用户灯先不亮后面就亮了(程序执行需要一些时间)。

问题:JLINK能不能给IMX6ULL烧写程序呢?

①6ULL支持JTAG,但是因为没有烧写算法所以无法烧写;

②但是我们可以用JTAG把bin文件下载到内部RAM;

③奇葩问题:6ULL的JTAG口竟然和SAI复用,SAI连接了WM8960的音频DAC,如果使用还得拆了喇叭,得不偿失,所以我们一般不用;

④对于普通开发者,在嵌入式Linux开发中基本不使用JLINK;

⑤我们可以使用点灯,串口来调试程序。

 

  本篇完!!!

posted @ 2021-12-03 11:05  平_意*  阅读(138)  评论(0编辑  收藏  举报