I.MX6U开发环境搭建
1. 交叉编译工具
编译工具的目录:
https://releases.linaro.org/components/toolchain/binaries/4.9-2017.01/arm-linux-gnueabihf/
光盘目录: 5. 开发工具->1、交叉编译器-> gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabihf.tar.xz
(1). 复制解压工具
sudo mkdir /usr/local/arm
sudo cp gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabihf.tar.xz /usr/local/arm/ -f
cd /usr/local/arm
sudo tar -vxf gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabihf.tar.xz
(2). 配置PATH环境变量
sudo vi /etc/profile
export PATH=$PATH:/usr/local/arm/gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabihf/bin
(3). 安装相关库
sudo apt-get install lsb-core lib32stdc++6
(4). 交叉编译器验证
<1> 查看版本号
arm-linux-gnueabihf-gcc -v
<2> 编译例程
光盘目录: 1、程序源码->1、裸机例程-> 1_leds
执行 make 生成 led.bin
2. Makefile
格式:
目标 : 依赖1 依赖2
命令
命令执行条件: 目标不存在 或者 依赖已更新
范例:
objs := start.o main.o
ledc.bin:$(objs)
arm-linux-gnueabihf-ld -Ttext 0X87800000 -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 -o $@ $<
%.o:%.S
arm-linux-gnueabihf-gcc -Wall -nostdlib -c -o $@ $<
%.o:%.c
arm-linux-gnueabihf-gcc -Wall -nostdlib -c -o $@ $<
clean:
rm -rf *.o ledc.bin ledc.elf ledc.dis
“$^”的意思是所有依赖文件的集合
“$@”的意思是目标集合
-Ttext 0X87800000 链接地址
3. 链接脚本
链接器的规则文件。
描述输入文件中的各个段(数据段,代码段,堆,栈,bss)如何被映射到输出文件中,并控制输出文件的各部分在程序地址空间(链接地址)内的布局。
SECTIONS{
. = 0X87800000;
.text :
{
start.o
main.o
*(.text)
}
.rodata ALIGN(4) : {*(.rodata*)}
.data ALIGN(4) : { *(.data) }
__bss_start = .;
.bss ALIGN(4) : { *(.bss) *(COMMON) }
__bss_end = .;
}
“.” 定位计数器:后面的文件或者段(start.o)的起始地址。
“*(.text)” 中的 * 是通配符,表示所有输入文件的.text段。
“.bss” 数据就是那些定义了但是没有被初始化的变量
__bss_start __bss_end .bss 段的起始地址和结束地址
可以直接在汇编或者 C 文件里面使用这两个符号,把BSS段清零。
87800000 <_start>:
87800000: e10f0000 mrs r0, CPSR
## ................
87800014: ea000077 b 878001f8 <__main_from_arm>
## ................
878001f8 <__main_from_arm>:
878001f8: e51ff004 ldr pc, [pc, #-4] ; 878001fc <__main_from_arm+0x4>
反编译可以看出, _start执行时的地址为87800000。
4. 汇编调用C
(1)ATPCS 规则
- 通过寄存器 R0~R3 来传递参数
- 通过寄存器 R4~R11 来保存局部变量
- R12(IP寄存器)R13(SP寄存器)R14(LR寄存器)R15(PC寄存器)
- 子函数返回结果通过寄存器 R0 / R1返回
(2) 如何调用C语言
_start:
//设置栈
ldr sp,=0x80200000
## 清 BSS 段
bl clean_bss
bl main
(1)设置栈指针
向上生长, 用于保护现场
(2)清 BSS 段
/* 清除 BSS 段 */
ldr r1, =__bss_start
ldr r2, =__bss_end
mov r3, #0
clean: @ 下面汇编指令相当于循环体,直到 R1 与 R2 相等
str r3, [r1]
add r1, r1, #4
cmp r1, r2
bne clean
mov pc, lr @ 函数执行完毕,返回
5. BSP 工程管理
将不同功能的源码文件放到不同的目录中。
所有完成同一个功能的代码提取出来放到一个单独的文件中。
makefile的改动
CROSS_COMPILE ?= arm-linux-gnueabihf-
TARGET ?= bsp
CC := $(CROSS_COMPILE)gcc
LD := $(CROSS_COMPILE)ld
OBJCOPY := $(CROSS_COMPILE)objcopy
OBJDUMP := $(CROSS_COMPILE)objdump
INCDIRS := imx6ul \ ## 头文件目录
bsp/clk \
bsp/led \
bsp/delay
SRCDIRS := project \ ## 源码目录
bsp/clk \
bsp/led \
bsp/delay
## 头文件位置
## INCLUDE := -I imx6ul -I bsp/clk -I bsp/led -I bsp/delay
INCLUDE := $(patsubst %, -I %, $(INCDIRS))
## 源文件
## CFILES = project/main.c bsp/clk/bsp_clk.c bsp/led/bsp_led.c bsp/delay/bsp_delay.c
SFILES := $(foreach dir, $(SRCDIRS), $(wildcard $(dir)/*.S))
CFILES := $(foreach dir, $(SRCDIRS), $(wildcard $(dir)/*.c))
## CFILENDIR = main.c bsp_clk.c bsp_led.c bsp_delay.c
SFILENDIR := $(notdir $(SFILES))
CFILENDIR := $(notdir $(CFILES))
## obj文件
## SOBJS = obj/start.o
## COBJS = obj/main.o obj/bsp_clk.o obj/bsp_led.o obj/bsp_delay.o
SOBJS := $(patsubst %, obj/%, $(SFILENDIR:.S=.o))
COBJS := $(patsubst %, obj/%, $(CFILENDIR:.c=.o))
OBJS := $(SOBJS) $(COBJS)
VPATH := $(SRCDIRS)
.PHONY: clean
$(TARGET).bin : $(OBJS)
$(LD) -Timx6ul.lds -o $(TARGET).elf $^
$(OBJCOPY) -O binary -S $(TARGET).elf $@
$(OBJDUMP) -D -m arm $(TARGET).elf > $(TARGET).dis
$(SOBJS) : obj/%.o : %.S
$(CC) -Wall -nostdlib -c -O2 $(INCLUDE) -o $@ $<
$(COBJS) : obj/%.o : %.c
$(CC) -Wall -nostdlib -c -O2 $(INCLUDE) -o $@ $<
clean:
rm -rf $(TARGET).elf $(TARGET).dis $(TARGET).bin $(COBJS) $(SOBJS)