一、BSP工程管理原理
BSP工程管理的目的就是为了模块化整理代码,同一个属性的文件存放在同一个目录里面。
1、新建所需的文件夹
创建bsp文件夹(存放驱动)、imx6ul文件夹(存放跟芯片有关的文件)、obj文件夹(存放编译过程中产生的文件)、project文件夹(存放启动文件(main.c、start.S),将同一属性的文件放到相应的文件夹中。
2、修改驱动
修改clk、led、delay驱动,创建对应的驱动文件,然后放置到对应的目录中
//bsp_clk.h
#ifndef __BSP_CLK_H
#define __BSP_CLK_H
#include "imx6ul.h"
void clk_enable(void);
#endif
//bsp_clk.c
#include "bsp_clk.h"
void clk_enable(void)
{
CCM->CCGR0 = 0XFFFFFFFF;
CCM->CCGR1 = 0XFFFFFFFF;
CCM->CCGR2 = 0XFFFFFFFF;
CCM->CCGR3 = 0XFFFFFFFF;
CCM->CCGR4 = 0XFFFFFFFF;
CCM->CCGR5 = 0XFFFFFFFF;
CCM->CCGR6 = 0XFFFFFFFF;
}
//bsp_led.h
#ifndef __BSP_LED_H
#define __BSP_LED_H
#include "imx6ul.h"
#define LED0 0
void led_init(void);
void led_switch(int led, int status);
#endif
//bsp_led.c
#include "bsp_led.h"
void led_init(void)
{
IOMUXC_SetPinMux(IOMUXC_GPIO1_IO03_GPIO1_IO03,0);
IOMUXC_SetPinConfig(IOMUXC_GPIO1_IO03_GPIO1_IO03,0X10B0);
GPIO1->GDIR |= (1 << 3);
GPIO1->DR &= ~(1 << 3);
}
void led_switch(int led, int status)
{
switch(led)
{
case LED0:
if(status == ON)
GPIO1->DR &= ~(1<<3);
else if(status == OFF)
GPIO1->DR |= (1<<3);
break;
}
}
//bsp_delay.h
#ifndef __BSP_DELAY_H
#define __BSP_DELAY_H
#include "imx6ul.h"
void delay(volatile unsigned int n);
#endif
//bsp_delay.c
#include "bsp_delay.h"
void delay_short(volatile unsigned int n)
{
while(n--){}
}
void delay(volatile unsigned int n)
{
while(n--)
{
delay_short(0x7ff);
}
}
3、修改main.c文件内容
根据编写的新驱动文件,修改main.c文件内容。
#include "bsp_clk.h"
#include "bsp_delay.h"
#include "bsp_led.h"
int main(void)
{
clk_enable(); /* 使能所有的时钟 */
led_init(); /* 初始化led */
while(1)
{
/* 打开LED0 */
led_switch(LED0,ON);
delay(500);
/* 关闭LED0 */
led_switch(LED0,OFF);
delay(500);
}
return 0;
}
4、设置Vscode头文件路径
创建.vscode文件夹,按住Ctrl+Shift+P,输入C/C++:Edit Configurations(JSON),会在.vscode目录下创建一个c_cpp_properties.json文件,在"includePath"内添加"${workspaceFolder}/**"
二、Makefile编写
Makefile指定头文件路径,需要-I。我们编译源码的时候需要指定头文件路径。比如
bsp/clk/bsp_clk.h
变为-I bsp/clk/bsp_clk.h
Makefile静态模式
<targets ...>: <target-pattern> : <prereq-patterns ...>
<commands>
...
targets定义了一系列目标文件
target-pattern指明了targets的模式
prereq-patterns是目标的依赖模式
$(OBJS): obj/%.o : %.S
表示将所有的.S文件编译为.o并且存放到obj目录下去。
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
#模式字符串替换函数——patsubst,让指定头文件时不用加-I
INCLUDE := $(patsubst %, -I %, $(INCDIRS))
#dir下保存的所有的.S和.c文件
#$(foreach <var>,<list>,<text>) 将参数<list>中的单词逐一取出放到<var>中,然后执行<text>
SFILES := $(foreach dir, $(SRCDIRS), $(wildcard $(dir)/*.S))
CFILES := $(foreach dir, $(SRCDIRS), $(wildcard $(dir)/*.c))
#不带路径的文件名
SFILENDIR := $(notdir $(SFILES))
CFILENDIR := $(notdir $(CFILES))
#带obj路径的文件
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)