一、BSP工程管理原理
BSP工程管理的目的就是为了模块化整理代码,同一个属性的文件存放在同一个目录里面。
1、新建所需的文件夹,将同一属性的文件放到相应的文件夹中。
2、修改clk、led、delay驱动,创建对应的驱动文件,然后放置到对应的目录中。
3、根据编写的新驱动文件,修改main.c文件内容。
二、Makefile编写
API函数说明:
patsubst函数:
格式:
$(patsubst pattern,replacement,text)
功能简述:
这是一个替换函数,将text的文本按照pattern规则,依次替换为replacement
替换时text的文本以“空格”‘TAB“”回车换行“分割来逐一匹配,是否符合pattern模式。如果匹配成功,则替换为replacement。其中pattern和replacement均可以使用%做为通配符(如需原本的%,则需要%进行转义)
举例:将INCLUDES变量中所有字符段,都加一个 - I。
$(patsubst %, -I %, $(INCLUDES))
foreach函数:
格式:
$(foreach <var>,<list>,<text> )
功能简述:
循环执行指定的功能,将list中的单词逐一取出,放到参数var指定的变量中,再执行text的功能。函数的返回值是text所有各段字符串的组合,var为局部临时变量,函数执行完就被释放了。
举例:
src := 1 2 3 4
out := $(foreach i, $(src), i.c)
此时的out为
1.c 2.c 3.c 4.c
wildcard函数:
格式:
$(wildcard PATTERN...)
功能简述:
将通配符展开。因为$引用变量时,通配符会失效,所以用这个展开通配符匹配的字符
举例:目录下有1.c 2.c 3.c 4.c 这四个C文件
obj := $(patsubst %.c, %o,$(wildcard *.c))
通配符*会依次配到这四个c文件,$(wildcard *.c)展开为1.c 2.c 3.c 4.c 字符串,然后由patsubst函数将.c替换为.o,返回替换结果。此时:obj为1.o 2.o 3.o 4.o
notdir函数
格式:
$(notdir <names...> )
功能简述:
去除文件路径的函数,保留后缀。
举例:
dir :=./led/led.c
src :=$(notdir $(dir))
去除路径,此时src结果为led.c
VPATH
Makefile文件中的特殊变量“VPATH”就是完成这个功能的,如果没有指明这个变量,make只会在当前的目录中去找寻依赖文件和目标文件。如果定义了这个变量,那么,make就会在当当前目录找不到的情况下,到所指定的目录中去找寻文件了。
静态模式
功能简述:更加容易地定义多目标的规则。
格式:
<targets ...>:<target-pattern>:<prereq-patterns>
<commands>
...
targets 定义了一系列的目标文件,是一个集合,可以有通配符。
target-pattern 指明了targets的模式,也就是目标集模式
prereq-patterns 是目标的依赖模式,对target-pattern 形成的模式再进行依次依赖目标的定义。
$(SOBJS) : obj/%.o : %.S表示将所有的.S编译成.o并存放到obj目录下。
工程文件结构
.
├── bsp # 板级支持包
│ ├── clk # 时钟驱动
│ │ ├── bsp_clk.c
│ │ └── bsp_clk.h
│ ├── delay # 延时驱动
│ │ ├── bsp_delay.c
│ │ └── bsp_delay.h
│ └── led # 链接驱动
│ ├── bsp_led.c
│ └── bsp_led.h
├── imx6ul # imx6ul官方库函数
│ ├── cc.h
│ ├── fsl_common.h
│ ├── fsl_iomuxc.h
│ ├── imx6ul.h
│ └── MCIMX6Y2.h
├── imx6ul.lds # 链接脚本
├── imxdownload # 下载脚本
├── ledc_bsp.code-workspace # vsc工程
├── load.imx
├── Makefile
├── obj # 存放obj文件
└── project # 工程main和start文件
├── main.c
└── start.S
链接脚本:
SECTIONS{
. = 0X87800000;
.text :
{
obj/start.o
*(.text)
}
.rodata ALIGN(4) : {*(.rodata*)}
.data ALIGN(4) : { *(.data) }
__bss_start = .;
.bss ALIGN(4) : { *(.bss) *(COMMON) }
__bss_end = .;
}
Makefile
编写步骤:
1.定义目标文件及交叉编译链的变量
2.定义源文件路径及头文件路径的变量
3.引用头文件,加入-I(patsubst)
4.找到相应路径下的源文件,c和S文件。(foreach wildcard)
5.转换为不带路径的源文件名
6.定义object文件
7.指定VPATH路径,及告诉make依赖文件和目标文件在哪里寻找
8.
9.编写clear清除编译文件。(.PHONY)
TARGET ?= test
CROSS_COMPILER ?= arm-linux-gnueabihf-
CC := $(CROSS_COMPILER)gcc
LD := $(CROSS_COMPILER)ld
OBJCOPY := $(CROSS_COMPILER)objcopy
OBJDUMP := $(CROSS_COMPILER)objdump
INCDIRS := imx6ul\
project\
bsp/led\
bsp/delay\
bsp/clk
SRCDIRS := imx6ul\
project\
bsp/led\
bsp/delay\
bsp/clk
INCLUDE := $(patsubst %, -I %,$(INCDIRS))
# 所有C、S文件的路径及文件名
CFILES := $(foreach dir, $(SRCDIRS), $(wildcard $(dir)/*.c))
SFILES := $(foreach dir, $(SRCDIRS), $(wildcard $(dir)/*.S))
# 所有C、S文件
CFILENDIR := $(notdir $(CFILES))
SFILENDIR := $(notdir $(SFILES))
# 所有C -> obj文件,放在obj目录下
COBJS := $(patsubst %, obj/%, $(CFILENDIR:.c=.o))
SOBJS := $(patsubst %, obj/%, $(SFILENDIR:.S=.o))
# 所有的.o文件
OBJS := $(SOBJS) $(COBJS)
VPATH := $(SRCDIRS)
$(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 $@ $<
.PHONY:clear
clear:
rm -rf $(OBJS) $(TARGET).bin $(TARGET).elf $(TARGET).dis
print:
@echo INCLUDE = $(INCLUDE)
@echo CFILES = $(CFILES) $(SFILES)
@echo CFILENDIR = $(CFILENDIR)
@echo SFILENDIR = $(SFILENDIR)
@echo ---OBJ = $(OBJS)
总结:
1.VPATH 用于指定源文件的目录。(当当前目录找不到,就VPATH目录下寻找)不能少。
2.-o问题,原本为 输入
-o输出
若将 输入输出写一块,只能这样写 -o 输出
输入
3.gcc参数说明:
-Wall编译后显示所有警告
-nostdlib 不链接标准库(启动文件)
-O2 优化编译及效率
4.静态模式
<targets ...>: <target-pattern>: <prereq-patterns ...>
$(OBJS): obj/%.o : %.S 表示将所有的.S文件编译为.o并且存放到obj目录下去。