【 I.MX6U-ALPHA 】嵌入式Linux 裸机开发系列(一)汇编LED灯

目录

 

1、硬件原理图

2、实验程序编写

3、编译代码

4、创建 Makefile 文件

5、代码烧写

6、代码验证


1、硬件原理图

从图可以看出,LED0 接到了 GPIO_3 上,GPIO_3 就是 GPIO1_IO03,当 GPIO1_IO03输出低电平(0)的时候发光二极管 LED0 就会导通点亮,当 GPIO1_IO03 输出高电平(1)的时候发光二极管 LED0 不会导通,因此 LED0 也就不会点亮。所以 LED0 的亮灭取决于 GPIO1_IO03的输出电平,输出 0 就亮,输出 1 就灭。

2、实验程序编写

led.s汇编程序如下所示:

/**************************************************************
文件名  :led.s
作者    :hanhui
版本    :V1.0
描述    :裸机实验 1 汇编点灯
其他    :无
日志    :初版V1.0 2020/8/31 hanhui创建
 **************************************************************/

 .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, =0x00000008
    str r1, [r0]

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

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

3、编译代码

3.1、arm-linux-gnueabihf-gcc  编译文件

arm-linux-gnueabihf-gcc -g -c led.s -o led.o

上述命令就是将 led.s 编译为 led.o,其中“-g”选项是产生调试信息,GDB 能够使用这些调试信息进行代码调试。“-c”选项是编译源文件,但是不链接。“-o”选项是指定编译产生的文件名字,这里我们指定 led.s 编译完成以后的文件名字为 led.o。执行上述命令以后就会编译生成一个 led.o 文件。

3.2、arm-linux-gnueabihf-ld 链接文件

使用 arm-linux-gnueabihf-ld 来将前面编译出来的 led.o 文件链接到 0X87800000 这个地址,使用如下命令:

arm-linux-gnueabihf-ld -Ttext 0X87800000 led.o -o led.elf

上述命令中-Ttext 就是指定链接地址,“-o”选项指定链接生成的 elf 文件名,这里我们命名为 led.elf。上述命令执行完以后就会在工程目录下多一个 led.elf 文件。

led.elf 文件也不是我们最终烧写到 SD 卡中的可执行文件,我们要烧写的.bin 文件,因此还需要将 led.elf 文件转换为.bin 文件,这里我们就需要用到 arm-linux-gnueabihf-objcopy 这个工具了。

3.3、arm-linux-gnueabihf-objcopy  格式转换

arm-linux-gnueabihf-objcopy 更像一个格式转换工具,我们需要用它将 led.elf 文件转换为led.bin 文件,命令如下:

arm-linux-gnueabihf-objcopy -O binary -S -g led.elf led.bin

上述命令中,“-O”选项指定以什么格式输出,后面的“binary”表示以二进制格式输出,选项“-S”表示不要复制源文件中的重定位信息和符号信息,“-g”表示不复制源文件中的调试信息。

3.4、arm-linux-gnueabihf-objdump  反汇编

大多数情况下我们都是用 C 语言写试验例程的,有时候需要查看其汇编代码来调试代码,因此就需要进行反汇编,一般可以将 elf 文件反汇编,比如如下命令:

arm-linux-gnueabihf-objdump -D led.elf > led.dis

总结一下我们为了编译 ARM 开发板上运行的 led.o 这个文件使用了如下命令:

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

4、创建 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

创建好 Makefile 以后我们就只需要执行一次“make”命令即可完成编译

如果我们要清理工程的话执行“make clean”即可

5、代码烧写

专门编写了一个软件来将编译出来的.bin 文件烧写到 SD 卡中,这个软件叫做“imxdownload”。

将 imxdownload 拷贝到工程根目录下,也就是和 led.bin 处于同一个文件夹下,要不然烧写会失败的。

准备一张新的 SD(TF)卡,确保 SD 卡里面没有数据,因为我们在烧写代码的时候可能会格式化 SD 卡!!!

在输入命令“ls /dev/sd*”来查看当前 Ubuutu 下的存储设备,确定好SD 卡以后我们就可以使用软件 imxdownload 向 SD 卡烧写 led.bin 文件了。

使用 imxdownload 向 SD 卡烧写 led.bin 文件,命令格式如下:

./imxdownload <.bin file> <SD Card>

 其中.bin 就是要烧写的.bin 文件,SD Card 就是你要烧写的 SD 卡,比如我的电脑使用如下命令烧写 led.bin 到/dev/sdb 中:

 ./imxdownload led.bin /dev/sdb

烧写的最后一行会显示烧写大小、用时和速度,比如 led.bin 烧写到 SD 卡中的大小是 3.2KB,用时 0.0130468s,烧写速度是 248KB/s。注意这个烧写速度,如果这个烧写速度在几百 KB/s 以下那么就是正常烧写。
注:如果这个烧写速度大于几十 MB/s、甚至几百 MB/s 那么肯定是烧写失败了!

解决方法就是重新插拔 SD 卡,一般出现这种情况,重新插拔 SD 卡基本没啥用,只有重启Ubuntu。

烧写完成以后会在当前工程目录下生成一个 load.imx 的文件,load.imx 这个文件就是软件 imxdownload 根据 NXP 官方启动方式介绍的内容,在 led.bin 文件前面添加了一些数据头以后生成的。最终烧写到 SD 卡里面的就是这个 load.imx 文件,而led.bin。

6、代码验证

代码已经烧写到了 SD 卡中了,接下来就是将 SD 卡插到开发板的 SD 卡槽中,然后设置拨码开关为 SD 卡启动,拨码开关设置如图所示:

设置好以后按一下开发板的复位键,如果代码运行正常的话 LED0 就会被点亮,如图所示:

 

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
typedef struct { ISRFunction_t handler; void *handler_param; int irq_type; } GpioIrqDesc_t; static GpioIrqDesc_t gpio_irq_descs[GPIO_NUM]; static __INLINE uint32_t gpio_get_regbase(int gpio) { int gpiox = (gpio >> 5) & 0x3; return REGS_GPIO_BASE + 0x80 * gpiox; } /* static __INLINE int GPIO_BANK(unsigned gpio) { return gpio >> 5; } */ static __INLINE int GPIO_OFFSET(unsigned gpio) { if (gpio == 96) return 2; else if (gpio == 97) return 0; else if (gpio == 98) return 3; else if (gpio == 99) return 1; else return gpio & 0x1F; } static __INLINE void *GPIO_MODREG(unsigned gpio) { return (void*)(gpio_get_regbase(gpio) + GPIO_SWPORTA_DDR); } static __INLINE void *GPIO_WDATAREG(unsigned gpio) { return (void*)(gpio_get_regbase(gpio) + GPIO_SWPORTA_DR); } static __INLINE void *GPIO_RDATAREG(unsigned gpio) { return (void*)(gpio_get_regbase(gpio) + GPIO_SWPORTA_EXT_PORTA); } static __INLINE void *GPIO_INTENREG(unsigned gpio) { return (void*)(gpio_get_regbase(gpio) + GPIO_SWPORTA_INTEN); } static __INLINE void *GPIO_INTMASKREG(unsigned gpio) { return (void*)(gpio_get_regbase(gpio) + GPIO_SWPORTA_INTMASK); } static __INLINE void *GPIO_INTLVLREG(unsigned gpio) { return (void*)(gpio_get_regbase(gpio) + GPIO_SWPORTA_INTTYPE_LEVEL); } static __INLINE void *GPIO_INTPOLREG(unsigned gpio) { return (void*)(gpio_get_regbase(gpio) + GPIO_SWPORTA_INT_POLARITY); } void gpio_request(unsigned gpio) { pinctrl_gpio_request(gpio); } void gpio_direction_output(unsigned gpio, int value) { configASSERT(gpio < GPIO_NUM); gpio_request(gpio); writel(readl(GPIO_MODREG(gpio)) | (1 << GPIO_OFFSET(gpio)), GPIO_MODREG(gpio)); if (value) writel(readl(GPIO_WDATAREG(gpio)) | (1 << GPIO_OFFSET(gpio)), GPIO_WDATAREG(gpio)); else writel(readl(GPIO_WDATAREG(gpio)) & ~(1 << GPIO_OFFSET(gpio)), GPIO_WDATAREG(gpio)); } void gpio_direction_input(unsigned gpio) { configASSERT(gpio < GPIO_NUM); gpio_request(gpio); writel(readl(GPIO_MODREG(gpio)) & ~(1 << GPIO_OFFSET(gpio)), GPIO_MODREG(gpio)); } void gpio_set_value(unsigned gpio, int value) { configASSERT(gpio < GPIO_NUM); if (value) writel(readl(GPIO_WDATAREG(gpio)) | (1 << GPIO_OFFSET(gpio)), GPIO_WDATAREG(gpio)); else writel(readl(GPIO_WDATAREG(gpio)) & ~(1 << GPIO_OFFSET(gpio)), GPIO_WDATAREG(gpio)); } int gpio_get_value(unsigned gpio) { configASSERT(gpio < GPIO_NUM); return !!(readl(GPIO_RDATAREG(gpio)) & (1 << GPIO_OFFSET(gpio))); } static void gpio_toggle_trigger(unsigned gpio) { u32 pol; pol = readl(GPIO_INTPOLREG(gpio)); if (pol & (1 << GPIO_OFFSET(gpio))) pol &= ~(1 << GPIO_OFFSET(gpio)); else pol |= (1 << GPIO_OFFSET(gpio)); writel(pol, GPIO_INTPOLREG(gpio)); } 根据上述函数配置一个输出模 频率为24mhz的io口】
07-15

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值