Vi BSP engineering management of the project

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);
#include "bsp_clk.h"

void clk_enable(void)

Files in the delay folder

#ifndef __BSP_DELAY_H
#define __BSP_DELAY_H

#include "imx6ul.h"

void delay(volatile unsigned int n);

#include "bsp_delay.h"
// Empty operation, demonstration about 1 ms
void delay_short(volatile unsigned int n)

void delay(volatile unsigned int n)

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);

#include "bsp_led.h"

/*Initialize LED*/
void led_init(void)
    // Reuse, electrical attribute register initialization

    // 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)
        case LED0:
            if(status == ON)
                GPIO1->DR &= ~(1<<3);    /* Open LED0 */
            else if(status == OFF)
                GPIO1->DR |= (1<<3);    /* Close LED0 */

/project folder

The above is the basic driver, and then the project folder



Inside is the main function and assembly environment configuration

.global _start

    BIC R0,R0,#0x1f
    ORR R0,R0,#0x13

    ldr sp,=0x80200000

    b main
#include "bsp_led.h"
#include "bsp_delay.h"
#include "bsp_clk.h"

int main(void)

    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;
#ifndef __IMX6UL_H
#define __IMX6UL_H

#include "cc.h"
#include "MCIMX6Y2.h"
#include "fsl_common.h"
#include "fsl_iomuxc.h"



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 \

SRCDIRS            := project \
                    bsp/clk    \
                    bsp/led \

# 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) -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 $@ $<

    rm -rf $(TARGET).elf $(TARGET).bin $(TARGET).dis $(OBJS)

    @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.

    . = 0X87800000;
    .text :
    .rodata ALIGN(4) : {*(.rodata*)}     
    .data ALIGN(4)   : { *(.data) }    
    __bss_start = .;    
    .bss ALIGN(4)  : { *(.bss)  *(COMMON) }    
    __bss_end = .;


Added by foreverhex on Mon, 03 Jan 2022 02:16:31 +0200