• 使用迅为IMX6ULL开发板第一个汇编实验(二)


    94 .4  GPIO 时钟 时钟
    如果使用 GPIO,我们必须要使能 GPIO 的时钟。i.MX6 ULL 的每个外设的时钟可以独立的使能,我们可以关闭不使用的外设时钟,可以达到节能的目的。如果使用某个外设,我们必须要打开对应的时钟。《I.MX6ULL 参考手册》的第 18 章“Clock Controller Module (CCM)”是关于 i.MX6ULL 时钟的讲解,我们可以看下该章节里面外设时钟的使能寄存器。跟外设时钟使能相关的寄存器有:
    CCM_CCGR0
    CCM_CCGR1
    CCM_CCGR2
    CCM_CCGR3
    CCM_CCGR4
    CCM_CCGR5
    CCM_CCGR6
    一共 7 个。我们来看下 CCM_CCGR0 寄存器如何使能一个外设时钟,改寄存器的描述如下图所示:
    <ignore_js_op>
    我们从上图可以看到 CCM_CCGR0 寄存器是 32 位的,每 位控制一个外设时钟,比如 bit1:bit0 控制aips_tz1 的时钟,两位的操作方式如下:
    00 //所有模式下都关闭外设时钟
    01 //只有在运行模式下打开外设时钟
    10 //保留
    11 //除了停止模式以外,其他所有模式下时钟都打开
    如果我们要打开 aips_tz1 的外设时钟,需要设置 CCM_CCGR0 的 bit1 和 bit0 都为 1,也就是 CCM_CCGR0=3,如果关闭 aips_tz1 的外设时钟,CCM_CCGR0 的 bit1 和 bit0 都设置为 0CCM_CCGR0-CCM_CCGR6 这 个寄存器的功能都是类似的,也是每两位控制一种外设的时钟,为了便于开发,我们在后面的例程里把所有的外设时钟都使能了。至此关于 GPIO 的操作我们可以总结成下面的步骤:
    1.使能 GPIO 对应的时钟
    2.设置 IOMUXC_SW_MUX_CTL_PAD_XX_XX 寄存器,把对应的 IO 设置成 GPIO 功能
    3.设置 IOMUXC_SW_PAD_CTL_PAD_XX_XX 寄存器,设置 GPIO 的上拉下拉,以及驱动能力
    4.设置输入还是输出,是否使用中断,以及默认的输出电平
    9 95 .5  LED 原理分析 原理分析
    i.MX6ULL 终结者开发板板载了一个 LED 灯,打开底板的原理图(光盘资料的“i.MX6UL 终结者光盘资料3_开发板硬件资料1_开发板原理图pdf itopmx6ul_terminator_v1_0.pdf”)原理图如下图所示:
    <ignore_js_op>
    从上图可以看到 LED2 一段接到了 3.3V 电源,另一端接到了 GPIO_3CPU 的 GPIO1_IO03)引脚上,当GPIO1_IO03 引脚输出低电平(0)的时候,LED2 会被点亮,当 GPIO1_IO03 引脚输出高电平(1)的时候,LED2 会灭掉。
    9 96 .6  LED 汇编程序 汇编程序
    按照前面的介绍,我们需要对 GPIO1_IO03 做如下的设置:
    1.使能 GPIO1 的时钟
    GPIO1 的时钟由 CCM_CCGR1 寄存器的 bit27 和 26 控制,我们把这两位设置成 1,就会使能 GPIO1 的时钟了。
    2.配置 GPIO1_IO03 的复用功能
    IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO03 寄存器是 GPIO1_IO03 的复用寄存器,地址是 0x20e0068,把这个寄存器设置成 GPIO 功能。
    3.配置 GPIO1_IO03 上下拉
    IOMUXC_SW_PAD_CTL_PAD_GPIO1_IO03 寄存器是 GPIO1_IO03 的配置寄存器,通过该寄存器配置 GPIO1_IO03为 GPIO 的上下拉。
    4.设置 GPIO1_IO03 输出
    在第二步骤我们已经把 GPIO1_IO03 复用成 GPIO 了,然后我们需要配置 GPIO 为输出,以及输出时候的高低电平,在《IMX6ULL 参考手册》的 1357 页我们可以看到 GPIO1_IO03 对应的 GPIO 寄存器组,如下图所示:
    <ignore_js_op>
    通过设置寄存器 GPIO1_GDIR 的 bit3 为 1,可以设置 GPIO1_IO03 为输出。然后通过设置 GPIO1_DR 寄存器的bit30,可以控制GPIO1_IO03输出低电平,LED会亮。GPIO1_DRbit3设置为1,可以控制GPIO1_IO03输出高电平,LED 会灭。
    本实验的源码在开发板光盘资料的"i.MX6UL 终结者光盘资料4_裸机例程源码1_leds1_leds"目录下,我们可以把这个文件夹拷贝到 UBuntu 下,使用交叉编译器编译。
    下面我们开始一步步的实现 LED 这个实验。首先登录 Ubuntu 系统,在用户的根目录下的 work 文件夹创建led 文件夹然后在 led 目录下新建“led.s”的汇编文件,如下图所示:
    <ignore_js_op>
    然后使用“vi led.s”命令打开 led.s 文件,在 led.s 文件输入如下代码:
    1 .global _start /* 全局标号 */
    2 /*
    3 * _start 函数,程序从此函数开始执行此函数完成时钟使能、
    4 * GPIO 初始化、最终控制 GPIO 输出低电平来点亮 LED 灯。
    5 */
    6 _start:
    7 /* 1、使能所有时钟 */
    8 ldr r0, =0X020C4068 /* CCGR0 */
    9 ldr r1, =0XFFFFFFFF
    10 str r1, [r0]
    11 ldr r0, =0X020C406C /* CCGR1 */
    12 str r1, [r0]
    13 ldr r0, =0X020C4070 /* CCGR2 */
    14 str r1, [r0]
    15 ldr r0, =0X020C4074 /* CCGR3 */
    16 str r1, [r0]
    17 ldr r0, =0X020C4078 /* CCGR4 */
    18 str r1, [r0]
    19 ldr r0, =0X020C407C /* CCGR5 */
    20 str r1, [r0]
    21 ldr r0, =0X020C4080 /* CCGR6 */
    22 str r1, [r0]
    23 /* 设置 GPIO1_IO03 为 GPIO 模式 */
    24 ldr r0, =0X020E0068 /* 把寄存器 SW_MUX_GPIO1_IO03_BASE 加载到 r0 中 */
    25 ldr r1, =0X5 /* 设置寄存器 SW_MUX_GPIO1_IO03_BASE 的 MUX_MODE 为 5 */
    26 str r1,[r0]
    27 /* 配置 GPIO1_IO03 的 IO 属性
    28 *bit 16:0 HYS 关闭
    29 *bit [15:14]: 00 默认下拉
    30 *bit [13]: 0 kepper 功能
    31 *bit [12]: 1 pull/keeper 使能
    32 *bit [11]: 0 关闭开路输出
    33 *bit [7:6]: 10 速度 100Mhz
    34 *bit [5:3]: 110 R0/6 驱动能力
    35 *bit [0]: 0 低转换率
    36 */
    37 ldr r0, =0X020E02F4 /*寄存器 SW_PAD_GPIO1_IO03_BASE */
    38 ldr r1, =0X10B0
    39 str r1,[r0]
    40 /* 设置 GPIO1_IO03 为输出 */
    41 ldr r0, =0X0209C004 /*寄存器 GPIO1_GDIR */
    42 ldr r1, =0X0000008
    43 str r1,[r0]
    44 /* 点亮 LED0
    45 * 设置 GPIO1_IO03 输出低电平
    46 */
    47 ldr r0, =0X0209C000 /*寄存器 GPIO1_DR */
    48 ldr r1, =0
    49 str r1,[r0]
    50 /*
    51 * 描述: loop 死循环
    52 */
    53 loop:
    54 b loop
    第 2 行我们定义了全局标号_start,程序就是从_start 标号处开始顺序往下执行的。
    第 8 行使用 ldr 向寄存器 r0 写入 0x20c4068,这是 CCM_CCGR0 的寄存器地址。
    第 9 行使用 ldr 向寄存器 r1 写入 0xffffffff,开启所有外设的时钟。
    第 10 行使用 str 命令把 r1 中的值写到 r0 所保存的地址中,相当于给 0x20c4068 这个地址写入 0xffffffff,
    也就是 CCM_CCGR0 寄存器设置成 0xffffffff,使能 CCM_CCGR0 寄存器控制的所有外设时钟。
    第 11 行到第 22 行是向 CCM_CCGR1-CCM_CCGR6 寄存器写入 0xffffffff,使能所有的外设时钟。
    第 24 行到第 26 行是设置 GPIO1_IO03 这个 IO 为 GPIO 模式,GPIO1_IO03 的复用寄存器是 0x20e0068,把改
    寄存器的 MUX_MODE 设置为 5(GPIO 模式)
    第 37 行到第 39 行设置 GPIO1_IO03 的 IOMUX_SW_PAD_CTL_PAD_GPIO1_IO03 配置寄存器
    第 40 行到第 43 行是设置 GPIO 为输出功能。
    第 47 到第 49 是设置 GPIO 输出 0(低电平)
    第 53 到第 54 行是死循环,使用 b 跳转指令,程序不断的跳转到 loop 执行。
    9.7  编译  LED 汇编程序 汇编程序
    我们在 Ubuntu 下通过 vim 编辑好 LED 的汇编程序(6.6 章节),然后保存并退出。然后我们使用 arm交叉编译器来编译该程序,我们在终端输入“arm-linux-gnueabihf-gcc -g -c led.s -o led.o”命令,把 led.s 编译成 led.o,其中的“-g”参数是产生调试信息,可以使用 GDB 来调试代码。“-c”参数是编译源文件,不链接。“-o”参数是指定产生的文件名称,我们指定生成 led.o,运行效果如下图所示所示:
    <ignore_js_op>
    我们可以看到通过 arm 交叉编译生成了 led.o 文件,这个文件相当于中间文件,我们还需要把编译生成的.o文件链接起来生成可执行文件(我们这里只有一个 led.o,对于有的工程可能会生成多个.o 文件)。
    接下来我们使用交叉编译器的arm-linux-gnueabihf-ld”命令来把“.o”文件链接起来。链接的目的就是把我们的程序固定到某个地址,这样 cpu 在运行的时候就可以通过链接地址找到我们的程序,并运行它。在链接之前我们需要先了解下 i.MX6ULL 的启动,i.MX6ULL 支持 SD 卡,EMMCNAND 等方式启动,i.MX6ULL启动的时候首先将代码从 SD 卡,EMMCNAND 中拷贝到运行地址,然后开始从运行地址处开始运行,i.MX6ULL
    芯片内部有 128K 的 RAM0X900000~0X91FFFF),另外外部扩展了 DDR,所以 i.MX6ULL 的链接地址可以是内部的 RAM,也可以是外部的 DDR。我们所有的例程都是链接到 DDR 中,其地址为 0X87800000i.MX6ULL终结者开发板的 DDR 有两种:256MB 和 512MB,其实地址都是 0X80000000256MB 的终止地址是 0X8FFFFFFF512M 的终止地址是 0X9FFFFFFF,之所以选择地址 0X87800000,是因为后面我们要学的 Uboot 链接地址也是0X87800000。所以为了学习方便,我们统一使用 0X87800000 地址。
    下面我们开始使用 arm-linux-gnueabihf_ld 命令将前面我们生成的“led.o”文件链接到 0X87800000 地址处,我们在终端输入“arm-linux-gnueabihf-ld -Ttext 0X87800000 led.o -o led.elf”,其中的“-Ttext
    指定链接地址(0X87800000),“-o”生成链接文件名,运行效果如下图所示:
    <ignore_js_op>
    我们需要把链接文件转换成.bin”文件,然后烧写到 EMMC,才能运行。
    接下来我们使用arm-linux-gnueabihf-objcopy”命令将链接文件 led.elf 转换成“led.bin”文件。我们在终端输入“arm-linux-gnueabihf-objcopy -O binary -S -g led.elf led.bin”命令,其中“-O”指定以什么格式输出(binary 表示二进制输出),“-S”表示不要赋值源文件中的重定位信息和符号信息,“-g”表示不复制源文件中的调试信息,运行效果如下图所示:
    <ignore_js_op>
    至此我们生成了最终的可执行程序led.bin”文件。
    我们可以总结下,为了生成 led.bin 文件,我们分别使用了命令:
    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
    为了编译方便,我们可以使用 Makefile 来编译我们的 led 汇编程序,首先我们在 led 工程目录下使用“touch
    Makefile”命令创建 Makefile 文件,如下图所示:
    <ignore_js_op>
    然后使用 vim 编辑器打开 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
    clean:
    rm -rf *.o led.bin led.elf
    添加完上面的命令,保存并退出,然后在 led 工程目录下执行“make”命令编译 led.S,过程如下图所示:
    <ignore_js_op>
    如果要清除工程,我们在终端执行make clean”即可。
    至此关于 arm 交叉编译器的使用,我们就先介绍到这里。编译生成了 led.bin 执行文件,下一步我们还需要给 led.bim 文件添加一些数据头才能执行。我们为用户提供了添加数据头的工具“create_imx”(光盘资料的“i.MX6UL 终结者光盘资料1_开发及烧写工具2.裸机镜像制作工具”目录下),我们通过 ssh工具拷贝改文件到 led 工程目录下,然后在终端输入命令“./create_imx led.bin”,生成 bare.imx 文件,如下图所示:
    <ignore_js_op>
    现在我们开始使用 MFG 烧写工具来烧写(光盘资料的“i.MX6UL 终结者光盘资料1_开发及烧写工具3.mfgtools_for_6ULL”文件夹),首先我们进到该文件夹,我们修改“cfg.ini”文件,如果您的板子是EMMC 版本(8G flash 容量),按照下图的方式修改:
    <ignore_js_op>
    如果您的板子是 NAND 版本(512MB flash 容量)(NAND 版本的裸机验证我们需要使用一张 TF 卡),按照下图所示修改:
    <ignore_js_op>
    修改完cfg.ini”配置文件,然后我们在 Ubuntu 系统生成的“bare.imx”文件通过 ssh 工具拷贝到 MFG烧写工具的“ProfilesLinuxOS Firmwarefileslinux”目录下,如下图所示:
    <ignore_js_op>
    然后我们鼠标双击打开 MFG 烧写工具,如下图所示:
    <ignore_js_op>
    MFG 烧写工具打开以后,我们使用开发板配带的 USB 数据线,连接开发板的 OTG 接口和 PC 的 USB 接口,使用开发板配带的电源连接到开发板的电源接口,然后开发板的拨码开关设置成 USB 启动,如下图所示:
    <ignore_js_op>
     如果我们使用的是 D NAND  版本的开发板,我们需要先拔掉 F TF  卡)然后按下开发板的电源开关,使开发板上电,此时我们会看到 MFG 烧写工具识别到开发板,如下图所示:
    <ignore_js_op>
     如果我们使用的是 D NAND  版本的开发板, , 我们需要插入 F TF  卡),然后我们点击 MFG 烧写工具的“Start”按钮,开始烧写镜像,如下图所示:
    <ignore_js_op>
    等到进度条显示绿色,烧写完成,如下图所示:
    <ignore_js_op>
    然后我们在按下开发板的电源按键给开发板断电,然后修改拨码开关设置正常启动。
    如果您的板子是 EMMC 版本(8GB Flash 存储),拨码开关如下图所示:
    <ignore_js_op>
    如果您的开发板是 NAND 版本(512M Flash 存储),拨码开关如下图所示(设置成 TF 卡启动模式):
    <ignore_js_op>
    最后我们在按下开发板的电源开关,给开发板上电,此时我们会看到开发板的 LED2 被点亮了,如下图
    所示:
    <ignore_js_op>
    本节我们详细的介绍了如何编译代码,并且如何使用 MFG 烧写生成
    更多内容关注:迅为电子
  • 相关阅读:
    根据条件把一个字符串拆分成几个字符串
    【SQLServer】SQL Server 2000的分页方法(SQL篇)
    【C#】NHibernate下实现SQL2000分页(SQL篇)
    【Oracle】仿Oracle Sequence的自定义年份Sequence(适合任何数据库)
    【Oracle】仿Oracle Sequence的自定义年份Sequence(适合任何数据库)(续)
    【C#】NHibernate下为SQL Server添加随机排序
    【LoadRunner】LoadRunner 9.5回放Windows Socket时CPU 100%
    【CSS】CSS Cookbook例子:创建水平导航菜单
    【CSS】CSS Cookbook例子:创建文字导航菜单和翻转特效
    【Flex】实现模块顺序执行
  • 原文地址:https://www.cnblogs.com/liyue3/p/13176835.html
Copyright © 2020-2023  润新知