BSP工程管理之前的两讲视频分别是模仿stm32驱动开发和官方SDK移植实验,这两讲的内容比较好理解。
模仿stm32驱动开发实验中,主要是在.s文件中添加了清除.bss段数据(未初始化的数据段)的代码。在.h文件下对时钟,IO寄存器组的基地址进行宏定义,并构造了对应的结构体(注意寄存器地址的连续性),最后将各个外设的寄存器组基地址强转为对应的结构体指针并进行宏定义,这样在主函数中就能像stm32寄存器版本一样使用结构体进行编写了。下面是一个简单的例子:
#define CCM_BASE (0X020C4000) //定义外设寄存器组基地址
typedef struct //寄存器结构体定义
{
volatile unsigned int CCR;
volatile unsigned int CCDR;
volatile unsigned int CSR;
...... //此处省略
}CCM_Type;
#define CCM ((CCM_Type *)CCM_BASE) //外设指针
如果定义全部的寄存器组,那就要写非常多的代码,stm32系列有官方定义的头文件供开发者使用,这款MX6ULL也有NXP提供的SDK包,这里可以参考视频进行移植。
进行BSP工程管理,目的是为了模块化整理代码,将同一属性的文件存放在同一目录里面。具体步骤如下:
1、新建所需文件夹,将同一属性的文件存放在相应文件中。
2、在不同驱动文件下编写驱动代码。(相当于stm32中一个外设有一个.h和一个.c文件,它们存放在一个文件夹里面)
3、根据编写的新驱动文件,修改main.c的内容
这里可能会出现调用头文件报错的问题,需要在工作区新建.vscode目录,然后打开C/C++配置器,.vscode目录下会生成一个c_cpp_properties.json的文件,打开,根据以下格式,写出所有带有头文件的目录。
Makefile的编写是这次实验里最重要的内容,可以通用于上述格式的代码,以后的实验只需要修改其中的小部分内容即可。先上代码,再具体说明:
CROSS_COMPILE ?= arm-linux-gnueabihf- # 变量定义
TARGET ?= ledc
CC := $(CROSS_COMPILE)gcc
LD := $(CROSS_COMPILE)ld
objcopy := $(CROSS_COMPILE)objcopy
objdump := $(CROSS_COMPILE)objdump
INCUDIRS := imx6u \ #包含有.h文件的目录
bsp/clk \
bsp/delay \
bsp/led
SRCDIRS := project \ #包含有.s,.c文件的目录
bsp/clk \
bsp/delay \
bsp/led
INCLUDE := $(patsubst %, -I %, $(INCUDIRS)) #调用patsubst函数在所有.h文件前+-I
SFILES := $(foreach dir, $(SRCDIRS), $(wildcard $(dir)/*.s)) #调用foreach函数保存目录下的所有.s文件,在变量中用到通配符要加wildcard
CFILES := $(foreach dir, $(SRCDIRS), $(wildcard $(dir)/*.c)) #调用foreach函数保存目录下的所有.c文件
SFILENDIR := $(notdir $(SFILES)) #去除所有.s文件路径,只保留文件名
CFILENDIR := $(notdir $(CFILES)) #去除所有.c文件路径,只保留文件名
SOBJS := $(patsubst %, obj/%, $(SFILENDIR:.s=.o)) #将文件中所有的.s替换为.o并放在放在obj目录下(属于变量的高级用法)
COBJS := $(patsubst %, obj/%, $(CFILENDIR:.c=.o)) #将文件中所有的.c替换为.o并放在放在obj目录下
OBJS := $(SOBJS)$(COBJS) #将所有待链接文件放在同一个变量中
VPATH := $(SRCDIRS) #指定搜索目录,编译.s,.c文件是会在SRCDIRS中寻找
.PHONY:clean #指定伪目标clean
$(TARGET).bin : $(OBJS) #生成bin文件和反汇编文件
$(LD) -Timx6u.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 $(OBJS)
基本格式$(patsubst “pattern”,“replacement”,“text”)
查找test中的单次是否符合模式pattern,如果匹配的话,则以replacement替换。pattern可以包括通配符“%”,表示任意长度的字串。如果replacement中也包含“%”,那么,replacement中的这个“%”将是pattern中的那个“%”所代表的字串。
(个人理解:该处函数中的pattern仅为%,代表该变量中的所有文件,替换为obj/%,相当于在所有文件前加上了obj/。text只会替换掉pattern部分,其他部分不会改变,可以具体操作尝试一下。)
基本格式$(foreach “var”,“list”,“text”)
这个函数的意思是,把参数list中的单词逐一取出放到参数var所指定的变量中,然后再执行text所包含的表达式。每一次text会返回一个字符串,循环过程中,text的所返回的每个字符串会以空格分隔,最后当整个循环结束时,text所返回的每个字符串所组成的整个字符串(以空格分隔)将会是foreach函数的返回值。
所以,var最好是一个变量名,list可以是一个表达式,而text中一般会使用var这个参数来依次枚举list中的单词。
这两个函数非常容易理解,notdir是去除文件前目录的显示,dir是在文件前显示目录。
…
targets定义了一系列的目标文件,可以有通配符。是目标的一个集合。
target-parrtern是指明了targets的模式,也就是目标集模式。
prereq-parrterns是目标的依赖模式,它对target-parrtern形成的模式再进行一次依赖目标的定义。(具体参考《跟我一起写Makefile》中的静态模式)
1、在.h所属的目录前加上-I ,是为了将目录添加到搜索路径中。
2、伪目标的作用是防止目录中定义了相同名称的文件。
上述内容参考了《跟我一起写Makefile》,具体深入学习请查阅更多资料。