一、硬件平台:
正点原子I.MX6U阿尔法开发板
汇编驱动LED实验,我们将用到的寄存器进行封装,用宏定义替换,此处我直接使用正点原子的宏定义头文件:
先看一下开发板上LED的接口,GPIO1的3脚
然后我们编写 main.c 文件代码
先编写时钟使能代码
void CLK_ENA()
{
CCM_CCGR0 = 0xffffffff;
CCM_CCGR1 = 0xffffffff;
CCM_CCGR2 = 0xffffffff;
CCM_CCGR3 = 0xffffffff;
CCM_CCGR4 = 0xffffffff;
CCM_CCGR5 = 0xffffffff;
CCM_CCGR6 = 0xffffffff;
}
再编写 LED IO 口初始化代码
void led_init()
{
//设置寄存器 SW_MUX_GPIO1_IO03_BASE 的 MODE 为5
SW_MUX_GPIO1_IO03 = 0x5;
//模式配置
//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 低转换率
SW_PAD_GPIO1_IO03 = 0x10b0;
//设置GPIO为输出
GPIO1_GDIR = 0X0000008;
//初始化输出为0
GPIO1_DR = 0x0;
}
在开头添加一个宏定义用于控制 GPIO1的3脚电平,设置电平使用: 或置位,与清零
#define LED_ON() (GPIO1_DR &= ~(1<<3))
#define LED_OFF() (GPIO1_DR |= (1<<3))
编写延时函数
void delay(volatile unsigned int n)
{
while(n--)
{
volatile unsigned int i = 0x7ff;
while(i--);
}
}
编写主函数,初始化外设后,延时点亮LED灯
int main(void)
{
CLK_ENA();
led_init();
while(1)
{
LED_OFF();
delay(1000);
LED_ON();
delay(1000);
}
return 0;
}
代码编写完成,需要编写编译链接 Makefile 脚本
# 定义目标变量
objs := start.o main.o
# 生成bin文件
ledc.bin: $(objs)
# 依次读取第一个依赖文件进行链接
arm-linux-gnueabihf-ld -Timx6ul.lds -o ledc.elf $^
# 链接文件转二进制
arm-linux-gnueabihf-objcopy -O binary -S ledc.elf $@
# 链接文件生成反汇编文件
arm-linux-gnueabihf-objdump -D -m arm ledc.elf > ledc.dis
#生成编译文件
%.o:%.s
arm-linux-gnueabihf-gcc -Wall -nostdlib -c -O2 -o $@ $<
%.o:%.S
arm-linux-gnueabihf-gcc -Wall -nostdlib -c -O2 -o $@ $<
%.o:%.c
arm-linux-gnueabihf-gcc -Wall -nostdlib -c -O2 -o $@ $<、
#清除编译文件
clean:
rm -rf *.o ledc.bin ledc.elf ledc.dis
$ 表示执行一个 Makefile 函数, $@ 依次取出目标文件用于执行,$< 依次取出依赖文件用于执行
% 表示变量成员通配符
在上面代码进行链接的时候,使用到了imux6ul.lds 链接文件,使链接器按照其规则进行链接,我们一般编译出来的代码 都包含在 text、data、bss 和 rodata 这四个段内,链接规则就是定义如何链接代码具体的位置
链接规则如下
# 关键字
SECTIONS{
# “.”在链接脚本里面叫做定位计数器,默认的定位计数器为 0,此处我们定义起始地址为 0X87800000
. = 0X87800000;
# “.text”是代码段名,后面的冒号是语法要求
.text :
{
start.o
main.o
*(.text)
# “*(.text)”中的“*”是通配符,表示所有输入文件的.text段都放到“.text”
}
# 只读数据段 (4字节对齐)
.rodata ALIGN(4) : {*(.rodata*)}
# 数据段 (4字节对齐)
.data ALIGN(4) : { *(.data) }
# .bss 段是定义了但是没有被初始化的变量,我们需要手动
# 对.bss 段的变量清零的,因此我们需要知道 .bss 段的
# 起始和结束地址
__bss_start = .;