硬件开发2-ARM裸机开发2-IMX6ULL
一、利用main函数调用外设接口 - led
1、配置好启动文件:start.S;
- 其内部包含(按顺序记录):
- 配置异常向量表,并封装跳转异常向量表情况的函数
- 模式切换与栈指针初始化
- 切换到IRQ模式并设置其栈指针
- 切回SYS/USER模式并设置其栈指针
- 调b main
2、main函数
- 封装寄存器地址封装、灯初始化、灯亮、灯暗、灯延时的函数
- 在main函数内部调用函数接口
关键字:volatile:
防止被修饰的变量会被 “意外修改”,禁止编译器对该变量进行优化
3、编译:
//定义交叉编译工具链的前缀和工具
COPLITE=arm-linux-gnueabihf-
CC=$(COPLITE)gcc
LD=$(COPLITE)ld
OBJCOPY=$(COPLITE)objcopy
OBJDUMP=$(COPLITE)objdump
//列出目标与依赖文件target
OBJS=start.o main.o
TARGET=led
//
.S
(汇编)和.c
(C语言)文件编译为.o
目标文件(后者源文件,前者目标文件)
%.o : %.S$(CC) -c -g $^ -o $@ //$^表示:所有依赖文件(%.S %.c) $@表示:目标文件(%.o)
%.o : %.c
$(CC) -c -g $^ -o $@
//链接->二进制文本->反汇编
$(TARGET).bin:$(OBJS)$(LD) -Ttext 0x87800000 $(OBJS) -o $(TARGET).elf
$(OBJCOPY) -O binary -S -g $(TARGET).elf $(TARGET).bin
$(OBJDUMP) -D $(TARGET).elf > $(TARGET).dis
clean:rm $(OBJS) $(TARGET).elf $(TARGET).bin $(TARGET).dis -f
load:
./imxdownload $(TARGET).bin /dev/sdb
4、小点:
- sp寄存器
- 概念:
- ARM架构中,SP寄存器(Stack Pointer,栈指针寄存器):是用于管理函数调用、中断处理等场景中栈操作的核心寄存器;
- 有效RAM范围内(如0x80000000~0x90000000)
- 功能:
- SP寄存器指向当前栈顶的内存地址,能够动态进行处理压栈和弹栈
- 属于满减栈,保存函数调用的返回地址、局部变量、中断现场信息等
- 概念:
5、代码实现:
start.S
main.c
makefile
6、优化1.0 - 配置时钟
改动:在main.c中配置了时钟寄存器
7、优化2.0 - 添加硬件寄存器定义和驱动库文件
改动:在main.c中,添加硬件寄存器定义和驱动库文件,
(1)GPIO方向寄存器
- ARM架构中,GPIO方向寄存器(GDIR)的每个bit控制一个引脚(bit3对应GPIO1_IO03)。
|= (1 << 3)
将bit3置1,配置为输出模式,符合硬件要求的原子性位操作(避免影响其他引脚)
(2)GPIO1->DR
位操作注释:
开漏/推挽输出:
DR
寄存器bit3直接驱动引脚电平:
DR &= ~(1 << 3)
输出低电平(LED点亮,假设共阳极接法)DR |= (1 << 3)
输出高电平(LED熄灭)
8、优化3.0 将功能性函数分离
改动:将有关led的函数封装,放入 led.c led.h
9、makefile
二、唤醒蜂鸣器
操作类似:进行优化,进行了BSP工程管理
1、BSP工程管理
1.project :存放必要程序
2.imx6ull :存放NXP提供的i.mx6ull头文件
3.bsp :存放硬件外设相关功能模块
4.Makefile: 需要遍目录
如下图所示
2、链接脚本(.lds)
(1)概要
使用BSP进行工程管理时,makefile就要升级了,同时也需要写一个链接脚本,保证插电启动时,首先运行的是start.S。
明确链接器:代码段、数据段、BSS 段的存放地址和顺序(为 I.MX6ULL 启动做准备)
start.S(
启动代码)放在最前面,且需初始化BSS段
(未初始化全局变量清 0)
(2)规则
1)内存布局定义核心结构
链接脚本的核心是SECTIONS
命令块,用于定义程序各段在内存中的布局:
SECTIONS {/* 各段定义 */
}
2)关键要素分类说明
- 定位计数器与起始地址
. = 0x87800000;
- 使用定位计数器(.)设置起始链接地址
- 示例中设置为I.MX6ULL的SD启动地址
- 后续段将从这个地址开始依次排列
- 代码段(.text)处理
.text : {obj/start.o /* 必须首先放置启动文件 */*(.text) /* 收集所有目标文件的.text段 */
}
- 确保启动代码(start.o)位于最前
- 通配符
*(.text)
收集所有.text段
- 数据段组织
段类型 | 语法示例 | 作用 | 对齐要求 |
---|---|---|---|
只读数据段 | .rodata ALIGN(4) : {*(.rodata*)} | 存放常量数据(如字符串) | 4字节对齐 |
已初始化数据 | .data ALIGN(4) : {*(.data)} | 存放已初始化全局/静态变量 | 4字节对齐 |
未初始化数据 | .bss ALIGN(4) : {*(.bss)} | 存放未初始化全局/静态变量 | 4字节对齐 |
- BSS段特殊处理
__bss_start = .; /* 定义BSS起始符号 */
.bss ALIGN(4) : {*(.bss) /* 标准BSS段 */*(COMMON) /* 公共块数据 */
}
__bss_end = .; /* 定义BSS结束符号 */
- 需要显式定义起止符号供启动代码使用
- 必须包含COMMON段
- 通常需要4字节对齐
- 对齐控制
ALIGN(4)
指令确保段起始地址4字节对齐- 对齐操作对32位处理器至关重要
- 可防止内存访问越界和性能下降
3)完整要素流程图
SECTIONS
│
├─ 定位计数器设置(.=0x87800000)
│
├─ .text段
│ ├─ 强制包含start.o
│ └─ 收集所有.text段
│
├─ .rodata段(ALIGN4)
│
├─ .data段(ALIGN4)
│
├─ BSS段处理
│ ├─ __bss_start标记
│ ├─ .bss段(ALIGN4)
│ │ ├─ 标准.bss
│ │ └─ COMMON块
│ └─ __bss_end标记