欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  网络运营

基于linux平台的嵌入式开发每日一练(四)

程序员文章站 2022-06-25 17:37:45
今天是2020.08.03 星期六 雨。该节使用纯汇编的形式编写LED驱动(即驱动芯片的GPIO,控制其GPIO输出高低电平)。...

今天是2020.08.03 星期六 雨。
该节使用纯汇编的形式编写LED驱动(即驱动芯片的GPIO,控制其GPIO输出高低电平)。
首先查看电路板上与LED相关的原理图,确定LED工作条件。
基于linux平台的嵌入式开发每日一练(四)
由原理图可知道到两个信息:

1)LED0和PWR连个LED灯共阳极,只有发光二极管的另一端接地或者输出低电平发光二极管才能被点亮,若输出高电平则发光二极管会熄灭。
2)用于驱动LED0的引脚IO是GPIO1_IO3。

第二步:类比基于STM32芯片上的LED驱动编写可知,要想使用芯片上的一个引脚成功驱动一个LED灯需要具备以下几个条件:

  • 开启这个引脚对应的外设时钟
  • 设置这个引脚的功能为作为普通输入输出功能
  • 设置这个引脚的相关电气特性包括上下拉、速度、摆率、迟滞器等等
  • 设置这个引脚的方向
  • 设置这个引脚的输出电平

第三步:啃芯片手册,找出与第二步相关的所有寄存器

  • 参考IMX6UL参考手册,找到第18章节( Clock Controller Module (CCM))、第26章节(General Purpose Input/Output (GPIO))、第30章节(IOMUX Controller (IOMUXC))等三章与第二步骤相关设置有关。

  • 第18章节主要是时钟控制,通过设置相关寄存器实现对外设时钟的控制,与该节有关的寄存器是:CCM Clock Gating Register 1 (CCM_CCGR1)
    寄存器地址:Address: 20C_4000h base + 6Ch offset = 20C_406Ch
    寄存器具体内容:
    基于linux平台的嵌入式开发每日一练(四)
    与该节相关的具体字段:
    基于linux平台的嵌入式开发每日一练(四)
    第30章节主要是介绍相关引脚复用功能选择(普通输入输出功能还是其他功能),相关寄存器1是:SW_MUX_CTL_PAD_GPIO1_IO03 SW MUX Control
    Register (IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO03)、
    寄存器地址:20E_0000h base + 68h offset = 20E_0068h
    寄存器具体内容:
    基于linux平台的嵌入式开发每日一练(四)
    与该节相关的具体字段:
    基于linux平台的嵌入式开发每日一练(四)
    相关寄存器2是:SW_PAD_CTL_PAD_GPIO1_IO03 SW PAD Control
    Register (IOMUXC_SW_PAD_CTL_PAD_GPIO1_IO03)
    寄存器地址:20E_0000h base + 2F4h offset = 20E_02F4h
    寄存器具体内容:
    基于linux平台的嵌入式开发每日一练(四)
    与该节相关的具体字段:
    HYS(bit16):对应图 8.1.4.2 中 HYS,用来使能迟滞比较器,当 IO 作为输入功能的时候有效,用于设置输入接收器的施密特触发器是否使能。如果需要对输入波形进行整形的话可以使能此位。此位为 0 的时候禁止迟滞比较器,为 1 的时候使能迟滞比较器。
    PUS(bit15:14): 对应图 8.1.4.2 中的 PUS,用来设置上下拉电阻的,一共有四种选项可以选择,如表所示:
    基于linux平台的嵌入式开发每日一练(四)
    PUE(bit13): 图 8.1.4.2 没有给出来,当 IO 作为输入的时候,这个位用来设置 IO 使用上下拉还是状态保持器。当为 0 的时候使用状态保持器,当为 1 的时候使用上下拉。状态保持器在IO 作为输入的时候才有用,顾名思义,就是当外部电路断电以后此 IO 口可以保持住以前的状态。
    PKE(bit12): 对应图 8.1.4.2 中的 PKE,此为用来使能或者禁止上下拉/状态保持器功能,为0 时禁止上下拉/状态保持器,为 1 时使能上下拉和状态保持器。
    ODE(bit11):对应图 8.1.4.2 中的 ODE,当 IO 作为输出的时候,此位用来禁止或者使能开路输出,此位为 0 的时候禁止开路输出,当此位为 1 的时候就使能开路输出功能。
    SPEED(bit7:6): 对应图 8.1.4.2 中的 SPEED,当 IO 用作输出的时候,此位用来设置 IO 速度,设置如表所示:
    基于linux平台的嵌入式开发每日一练(四)
    DSE(bit5:3):对应图 8.1.4.2 中的 DSE,当 IO 用作输出的时候用来设置 IO 的驱动能力,总共有 8 个可选选项,如表所示:
    基于linux平台的嵌入式开发每日一练(四)
    SRE(bit0): 对应图 8.1.4.2 中的 SRE,设置压摆率,当此位为 0 的时候是低压摆率,当为 1的时候是高压摆率。这里的压摆率就是 IO 电平跳变所需要的时间,比如从 0 到 1 需要多少时间,时间越小波形就越陡,说明压摆率越高;反之,时间越多波形就越缓,压摆率就越低。如果你的产品要过 EMC 的话那就可以使用小的压摆率,因为波形缓和,如果你当前所使用的 IO做高速通信的话就可以使用高压摆率。
    寄存器 IOMUXC_SW_PAD_CTL_PAD_GPIO1_IO00 是用来配置 GPIO1_IO00 的, 包括速度设置、驱动能力设置、压摆率设置等等。

     注:IOMUXC_SW_MUX_CTL_PAD_XX_XXIOMUXC_SW_PAD_CTL_PAD_XX_XX 这两种寄存器都是配置 IO 的,注意是 IO!不是 GPIO, GPIO 是一个 IO 众多复用功能中的一种。比如 GPIO1_IO00 这个 IO 可以复用为: I2C2_SCL、GPT1_CAPTURE1、 ANATOP_OTG1_ID、ENET1_REF_CLK 、MQS_RIGHT 、 GPIO1_IO00 、 ENET1_1588_EVENT0_IN 、SRC_SYSTEM_RESET 和 WDOG3_WDOG_B 这 9 个功能, GPIO1_IO00 是其中的一种,我们想要把 GPIO1_IO00 用作哪个外设就复用为哪个外设功能即可。如果我们要用GPIO1_IO03 来点个灯、作为按键输入啥的就是使用其 GPIO(通用输入输出)的功能。将其复用为 GPIO 以后还需要对其 GPIO 的功能进行配置。
    

由上述的注意中的内容可知,还需要对GPIO的功能进行设置,这就自然引出了第26章节通用输入输出设置,涉及到的寄存器是:GPIO direction register (GPIOx_GDIR)
寄存器地址:209_C004
寄存器具体内容:
基于linux平台的嵌入式开发每日一练(四)
与该节相关的具体字段:
基于linux平台的嵌入式开发每日一练(四)
设置对应引脚输出低电平点亮LED0,涉及到的寄存器是GPIO data register (GPIOx_DR)
寄存器地址:209_C000
寄存器具体内容:
基于linux平台的嵌入式开发每日一练(四)
DR:Data bits. This register defines the value of the GPIO output when the signal is configured as an output(GDIR[n]=1). Writes to this register are stored in a register. Reading GPIO_DR returns the value stored inthe register if the signal is configured as an output (GDIR[n]=1), or the input signal’s value if configured asan input (GDIR[n]=0)。

note:The I/O multiplexer must be configured to GPIO mode for the GPIO_DR value to connect with thesignal. Reading the data register with the input path disabled always returns a zero value.

第四步:编写汇编代码

  • 创建并打开汇编文件:vim led.s
  • 编写汇编代码,具体内容如下:
.global _start /* 全局标号 */
 _start:

//打开GPIO1_IO03对应外设时钟
ldr r0, =0X020C406C /* 寄存器 CCGR1 */
str r1, [r0]
 
//设置 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]

 /* 配置 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]

//设置 GPIO1_IO03 为输出
ldr r0, =0X0209C004 /*寄存器 GPIO1_GDIR */
ldr r1, =0X0000008
str r1,[r0]

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

//loop 死循环
loop:
	b  loop

第五步:编译程序
编译方式有两种:使用命令行编译、使用MakeFile文件编译

使用命令行编译:

  • led.s 编译为对应的.o 文件
arm-linux-gnueabihf-gcc -g -c led.s -o led.o
	 注:其中“-g”选项是产生调试信息, GDB 能够使用这些调试信息进行代调试。“-c”选项是编译源文件,但是不链接。“-o”选项是指定编译产生的文件名字
  • 将前面编译出来的 led.o 文件链接到 0X87800000 这个地址
 arm-linux-gnueabihf-ld -Ttext 0X87800000 led.o -o led.elf
	注:命令中-Ttext 就是指定链接地址,“-o”选项指定链接生成的 elf 文件名
	注:I.MX6U 的内部 boot rom 程序会将可执行文件拷贝到链接地址处,这个链接地址可以在 I.MX6U 的内部 128KB RAM 中(0X900000~0X91FFFF),也可以在外部的 DDR 中。本节实验的链接地址都在 DDR中,链接起始地址0X87800000。 I.MX6U-ALPHA 开发板的 DDR 容量有两种: 512MB 和
	256MB,起始地址都为 0X80000000,只不过 512MB 的终止地址0X9FFFFFFF,而 256MB 容量的终止地址为 0X8FFFFFFF。之所以选择 0X87800000 这个地址是因为后面要讲的 Uboot 其链接地址就是 0X87800000,这样我们统一使用 0X87800000 这个链接地址,不容易记混。	
  • arm-linux-gnueabihf-objcopy 格式转换
    将 led.elf 文件转换为led.bin 文件,命令如下:
arm-linux-gnueabihf-objcopy -O binary -S -g led.elf led.bin
注:上述命令中,“-O”选项指定以什么格式输出,后面的“binary”表示以二进制格式输出,选项“-S”表示不要复制源文件中的重定位信息和符号信息,“-g”表示不复制源文件中的调试信息。
  • arm-linux-gnueabihf-objdump 反汇编
    需要查看其汇编代码来调试代码,因此就需要进行反汇编,一般可以将 elf 文件反汇编,比如如下命令:
arm-linux-gnueabihf-objdump -D led.elf > led.dis
注:-D”选项表示反汇编所有的段。

使用MakeFile文件编译:
创建并打开MakeFile文件:vim MakeFile
编写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
arm-linux-gnueabihf-objdump -D led.elf > led.dis
clean:
rm -rf *.o led.bin led.elf led.dis

编译程序:
make
清除编译生成的文件:
make clean

第六步:使用使用软件 imxdownload 向 SD 卡烧写 led.bin 文件
格式入下:
./imxdownload <.bin file>
具体实现如下:
./imxdownload led.bin /dev/sdd

注1:在进行烧炉前imxdownload软件必须与可执行文件led.bin处于同一目录下,并且软件必须有可执行权限
注2:/dev/sdd是挂在的SD卡的路径,可视具体路径定。
注3:执行完上述操作后,会生成一个load.imx文件,load.imx就是实际烧录到SD卡的文件,而不是led.bin文件。

本文地址:https://blog.csdn.net/cainiaoxiakexing/article/details/107933850