With the improvement of our code functions, it is not appropriate to place all files in one folder. For our use of the library provided by NXP in the previous chapter, the directory structure is very disordered after a simple LED lighting test
When making complex function projects, the directory structure needs to be optimized. Here, a new concept - BSP(Board Support Package) is introduced. This is the directory structure first
First, create a directory according to the following structure
Among them, bsp is used to put driver files, imx6u chip related files, which are generated after obj compilation o file, project C code and assembly code. First, put the header files of the previous chapter in the imx6u folder and put start S and main C is placed in the project, and then some codes, such as LED initialization and clock initialization, can be disassembled and written into independent codes and placed in bsp. According to different functions, they can be placed in several folders established according to functions under bsp.
This test also lights the LED as before.
Engineering decomposition
For the convenience of future driver development, we open each functional module,
/bsp folder
The following files are placed in the bsp folder
clk is clock management, delay is timing, and LED is led driver. The code is directly placed below
Files in clk folder:
#ifndef __BSP_CLK_H #define __BSP_CLK_H #include "imx6ul.h" void clk_enable(void); #endif
#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; }
Files in the delay folder
#ifndef __BSP_DELAY_H #define __BSP_DELAY_H #include "imx6ul.h" void delay(volatile unsigned int n); #endif
#include "bsp_delay.h" // Empty operation, demonstration about 1 ms void delay_short(volatile unsigned int n) { while(n--){} } void delay(volatile unsigned int n) { while(n--){delay_short(0x7ff);} }
Files under led folder:
#ifndef __BSP_LED_H #define __BSP_LED_H #include "imx6ul.h" #define LED0 0 void led_init(void); void led_on(void); void led_off(void); void led_switch(int led, int status); #endif
#include "bsp_led.h" /*Initialize LED*/ void led_init(void) { // Reuse, electrical attribute register initialization IOMUXC_SetPinMux(IOMUXC_GPIO1_IO03_GPIO1_IO03,0); IOMUXC_SetPinConfig(IOMUXC_GPIO1_IO03_GPIO1_IO03,0x10B0); // GPIO1 Direction register, GPIO1->GDIR = 0x8; } // Light up LED void led_on(void) { GPIO1->DR &= ~(1<<3); //bit3 Clear } // close LED void led_off(void) { GPIO1->DR |=(1<<3); //bit3 Set one } void led_switch(int led, int status) { switch(led) { case LED0: if(status == ON) GPIO1->DR &= ~(1<<3); /* Open LED0 */ else if(status == OFF) GPIO1->DR |= (1<<3); /* Close LED0 */ break; } }
/project folder
The above is the basic driver, and then the project folder
Inside is the main function and assembly environment configuration
.global _start _start: MRS R0,CPSR BIC R0,R0,#0x1f ORR R0,R0,#0x13 MSR CPSR,R0 ldr sp,=0x80200000 b main
#include "bsp_led.h" #include "bsp_delay.h" #include "bsp_clk.h" int main(void) { clk_enable(); led_init(); while(1) { led_switch(LED0,ON); delay(200); led_switch(LED0,OFF); delay(200); } return 0; }
/imx6ul folder
imx6ul is the library file of the chip
Where, CC h is the data type we define, imx6ul h is the header file defined by yourself. Defining this header file here simplifies the method of importing header files from the driver library, because several library files here are almost driven Almost all h files need to be imported. After defining this file, only importing this header file is equivalent to importing all library files.
#ifndef __CC_H #define __CC_H #define __I volatile #define __O volatile #define __IO volatile #define ON 1 #define OFF 0 typedef signed char int8_t; typedef signed short int16_t; typedef signed int int32_t; typedef unsigned char uint8_t; typedef unsigned short uint16_t; typedef unsigned int uint32_t; typedef unsigned long long uint64_t; typedef signed char s8; typedef signed short s16; typedef signed int s32; typedef long long s64; typedef unsigned char u8; typedef unsigned short u16; typedef unsigned int u32; typedef unsigned long long u64; #endif
#ifndef __IMX6UL_H #define __IMX6UL_H #include "cc.h" #include "MCIMX6Y2.h" #include "fsl_common.h" #include "fsl_iomuxc.h" #endif
Makefile file
The Makefile file here is an important point, because all files in the project directory are managed according to the path. If you place an order in the root directory, Makefile will not find the file to be compiled. Put the Makefile down first
CROSS_COMPILE ?= arm-linux-gnueabihf- TARGET ?= bsp CC := $(CROSS_COMPILE)gcc LD := $(CROSS_COMPILE)ld OBJCOPY := $(CROSS_COMPILE)objcopy OBJDUMP := $(CROSS_COMPILE)objdump INCLUDIRS := imx6ul \ bsp/clk \ bsp/led \ bsp/delay SRCDIRS := project \ bsp/clk \ bsp/led \ bsp/delay # Use patsubst to modify the string and add before each path of includers-I \ $(patsubst <pattern>,<replacement>,<text>) \ name:Pattern string replacement function—— patsubst. \ function:lookup<text>Words in(Words with "space"“ Tab"Or "enter" and "line feed" separation)Whether or not\ Combined mode<pattern>,If it matches,Then<replacement>Replace. here,<pattern>It can include communication\ Match“%",Represents a string of arbitrary length. If<replacement>Also included in“%",that,<replacement>\ This in“%"will be<pattern>The one in the picture“%"The string represented.\ (Can use“\"To escape,With“\%"To express the true meaning“%"character)\ return:Function returns the replaced string INCLUDE :=$(patsubst %, -I % ,$(INCLUDIRS)) #Get in project c,. s file\ foreach similar BASH Inside for Loop, usage is $(foreach <var>,<list>,<text>) \ Just put list Take out the words in one by one and put them in the variable var , and then execute text Within the expression, each time text A string is returned. \ At the end of the last cycle,<text>The return value is the whole string composed of each string, separated by spaces, \ wildcard File collection under the specified object for expansion SFILES := $(foreach dir ,$(SRCDIRS),$(wildcard $(dir)/*.s)) CFILES := $(foreach dir ,$(SRCDIRS),$(wildcard $(dir)/*.c)) #Get the file name without path, which is used to modify the suffix generation o file name of the file SFILENDIR := $(notdir $(SFILES)) # File name without path, CFILENDIR := $(notdir $(CFILES)) # File name without path # Convert file names without paths to o suffix, corresponding to the compiled file name SOBJS := $(patsubst %, obj/%,$(SFILENDIR:.s=.o)) #.s=.o yes S use o replacement COBJS := $(patsubst %, obj/%,$(CFILENDIR:.c=.o)) #.c=.o yes C use o replacement OBJS := $(SOBJS) $(COBJS) VPATH := $(SRCDIRS) .PHONY: clean $(TARGET).bin : $(OBJS) $(LD) -Timx6ul.lds -o $(TARGET).elf $^ #Link all dependent files to generate elf file $(OBJCOPY) -O binary -S $(TARGET).elf $@ #Convert elf to dependent target set $(OBJDUMP) -D -m arm $(TARGET).elf > $(TARGET).dis #Disassemble elf file # Static mode < targets... >:< tatgets-pattern>:<prereq-patterns...> The next two days are self writing $(SOBJS) : obj/%.o : %.s #Put all the s file compiled into o files are placed in obj folder $(CC) -Wall -nostdlib -c -O2 $(INCLUDE) -o $@ $< $(COBJS) : obj/%.o : %.c $(CC) -Wall -nostdlib -c -O2 $(INCLUDE) -o $@ $< clean: rm -rf $(TARGET).elf $(TARGET).bin $(TARGET).dis $(OBJS) print: @echo INCLUDE = $(INCLUDE) @echo OBJS = $(OBJS)
I have annotated the general description, that is, several functions are used
Including but not limited to patsubst of replacement string, foreach of circular structure, static mode, etc. This Makefile file is used as a general Makefile for later driver development. The whole file structure is much more complex than the Makefile used before, but it should be easy to understand according to the comments. Stuck in one place for a long time during debugging:
SOBJS := $(patsubst %, obj/%,$(SFILENDIR:.s=.o)) #.s=.o yes S use o replacement
There is more space after the first percent sign after patsubst, and errors are always reported during compilation
And the corresponding variables can also be printed by the pseudo target debugging printed later. We must pay attention to it.
Link script
Notice the link in Makefile. We used a file called link script to replace the link address 0x87800000. This script is to place a single file in the root directory and copy it in the path. Its general function is to specify how to put the section in the input file into the output file and control the layout of each part in the output file in the program address space But you can also use the connection command to do some other things. The specific role will be discussed later.
SECTIONS{ . = 0X87800000; .text : { obj/start.o *(.text) } .rodata ALIGN(4) : {*(.rodata*)} .data ALIGN(4) : { *(.data) } __bss_start = .; .bss ALIGN(4) : { *(.bss) *(COMMON) } __bss_end = .; }