首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >arm(3)| 点亮led灯

arm(3)| 点亮led灯

作者头像
飞哥
发布2020-07-17 17:25:32
1.2K0
发布2020-07-17 17:25:32
举报

这里继续介绍arm裸机的编程,从点亮led灯开始,今天将会分别使用汇编和C语言来实现点亮led灯。里面涉及到的一些arm基础知识可以参考前面的文章arm(1)| 基础知识arm(2)| 汇编指令和伪指令

在点灯之前,要了解IO的复用功能,在这里应该设置为普通的GPIO模式,另外还要设置引脚的属性,例如驱动能力,是否使用上下拉电阻,是否使用保持器,是否使用开漏模式以及使用施密特模式还是CMOS模式等。不过这一部分对于点灯来说,使用默认即可。

然后还要从原理图上找出led对应的管脚,比如本次实验红色led对应的管脚是GPIO1_IO04

一、汇编方式

汇编方式点灯总结为以下几点:

(1) 开启 GPIO 时钟。

CCM_CCGR1(0x20c406c),用来开启时钟,比如要开启gpio1的时钟,就要配置CCM_CCGR1寄存器的bit27~bit26位,具体配置如下图:

(2) 设置引脚的复用功能

IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO04(0x20e006c),配置引脚为GPIO模式。从图上可以看出,将bit3~bit0配置为0101(二进制),就是gpio模式。

(3) 设置引脚属性。

IOMUXC_SW_PAD_CTL_PAD_GPIO1_IO04(0x20e02f8),用于配置引脚的属性,例如驱动能力,是否使用上下拉电阻,是否使用保持器,是否使用开漏模式以及使用施密特模式还是CMOS模式等。(暂时使用默认值,所以不配置这一项)

(4) 设置引脚方向

GPIO1_GDIR(0x209c004),0是输入,1是输出。在这里,设置bit4为1。

(5)设置输出电平。

GPIO1_DR(0x209c000),0是低电平,1是高电平。所以可以设置bit4为0。

实例代码:

.global _start
_start:
@寄存器宏定义
#define CCM_CCGR1                                 0x20c406c
#define IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO04        0x20e006c
#define GPIO1_GDIR                              0x209c004
#define GPIO1_DR                                0x209c000
@开启时钟
ldr r0,=CCM_CCGR1
ldr r1,=0xffffffff
str r1,[r0]
@设置引脚的复用功能
ldr r0,=IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO04
ldr r1,=0x5
str r1,[r0]
@设置引脚方向
ldr r0,=GPIO1_GDIR
ldr r1,=0x10
str r1,[r0]
@设置输出电平
ldr r0,=GPIO1_DR
ldr r1,=0x0
str r1,[r0]

loop:
    b loop

写好代码之后,就要进行编译、链接、格式转化工作,对于iMX.6ull芯片来说,还需要添加头,这里暂时使用现成脚本。

1、编译:

arm-none-eabi-gcc -g -c led.S -o led.o

2、链接:

arm-none-eabi-ld -Ttext 0x80000000 led.o -o led.elf

-Ttext 0x80000000 选项,设置程序代码段的起始地址为 0x80000000。0x80000000 是外部内存的起始地址。这个地址是由芯片本身决定的。

3、格式转化:

arm-none-eabi-objcopy -O binary -S -g led.elf led.bin

上一步链接生成的.elf 文件是带有地址信息的文件,不能放在存储器中执行,要使用格式转换命令转化为二进制文件。

编译成功后会在当前文件夹下生成.bin 文件,这个.bin 文件也不能直接放到开发板上运行,这次是因为需要在.bin 文件缺少启动相关信息。这一部分暂时使用现成的脚本文件来添加,暂时不深究。

最后,bin文件烧写到SD卡当中,然后将SD卡插在开发板上,通过拨码开关设置开发板的启动方式为SD卡启动,上电之后就可以看到led灯被点亮。

二、C语言方式

C语言点亮led灯和汇编差不多,只不过要添加一个启动文件和链接脚本,然后再写一个Makefile方便管理工程。

首先写一个启动文件start.S,这个启动文件用来设置栈指针,以及跳转到C代码的main函数中

.text
.align 2
.global _start
_start:
    ldr sp,=0x80001000
    b main

然后写一个led.c文件,内容和汇编差不多,只不过这里是用指针的方式来写寄存器。

#define      CCM_CCGR1   *(volatile unsigned long*)0x20c406c
#define     IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO04  \
*(volatile unsigned long*)0x20e006c
#define      GPIO1_GDIR  *(volatile unsigned long*)0x209c004
#define     GPIO1_DR    *(volatile unsigned long*)0x209c000

void delay(int i);

int main(void)
{
    CCM_CCGR1=0xffffffff;
    IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO04=5;
    GPIO1_GDIR=(1<<4);
    while (1)
    {
        GPIO1_DR=0;
        delay(5000000);
        GPIO1_DR=(1<<4);
        delay(5000000);
    }
    return 0;
}

void delay(int i)
{

    while (i--)
    {

    }

}

之后写一个链接脚本led.lds,用来指定链接的地址。链接脚本的作用就是告诉编译器怎么链接这些文件,比如那个文件放在最前面,程序的代码段、数据段、bss段分别放在什么位置等等。注意"."后面有空格,否则会报错。

ENTRY(_start)
SECTIONS
{
    . =0x80000000;
    .=ALIGN(4);
    .text :
    {
        start.o (.text)
        *(.text)
    }
    . =ALIGN(4);
    .data :
    {
        *(.data)
    }
    . =ALIGN(4);
    .bss :
    {
        *(.bss)
    }
}

最后写一个Makefile用来管理工程。关于Makefile内容,可以参考前面的文章Linux笔记(9)| 一步步深入Makefile

all:start.o led.o
    arm-none-eabi-ld -Tled.lds  $^ -o led.elf
    arm-none-eabi-objcopy -O binary -S -g led.elf led.bin

%.o:%.c
    arm-none-eabi-gcc -g -c $^ -o led.o
%.o:%.S 
    arm-none-eabi-gcc -g -c $^ -o start.o

.PHONY:clean
clean:
    rm *.o *.elf *.bin

最后将生成的bin文件烧录到SD卡当中,然后将SD卡插在开发板上,通过拨码开关设置开发板的启动方式为SD卡启动,上电之后就可以看到led灯闪烁。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2020-07-15,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 电子技术研习社 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档