• 六.项目的BSP工程管理


    随着我们的代码功能完善,在一个文件夹下放置所有文件已经不太合适了,针对我们上一章使用NXP提供的库来说,简简单单一个点亮LED的试验,目录结构就很乱了

     在做复杂功能项目的时候,需要对目录结构进行优化,这里引入一个新概念——BSP(Board Support Package 板级支持包),目录的结构先这样做

    先按照下面结构建立目录

     其中,bsp用来放驱动文件,imx6u放和芯片有关的文件,obj编译以后生成的.o文件,project放C代码和汇编代码。先把前一章的几个头文件放在imx6u文件夹下,把start.s和main.c放在project里,然后有些代码,比方LED初始化,时钟初始化什么的,可以拆解出来写成独立的代码放在bsp根据功能不同可以放在bsp下几个按照功能建立的文件夹中。

    这次的试验还和前面一样,点亮LED。

    工程分解

    为了以后的驱动开发方便,我们把各个功能模块分开放,

    /bsp文件夹

    bsp文件夹下放下面的文件

    clk为时钟管理,delay为定时,led为led的驱动,代码直接放在下面

    clk文件夹下文件:

    #ifndef __BSP_CLK_H
    #define __BSP_CLK_H
    #include "imx6ul.h"
    
    void clk_enable(void);
    #endif
    bsp_clk.h
    #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_clk.c

    delay文件夹下文件

    #ifndef __BSP_DELAY_H
    #define __BSP_DELAY_H
    
    #include "imx6ul.h"
    
    void delay(volatile unsigned int n);
    
    #endif
    bsp_delay.h
    #include "bsp_delay.h"
    // 空操作,演示大约1ms
    void delay_short(volatile unsigned int n)
    {
        while(n--){}
    }
    
    void delay(volatile unsigned int n)
    {
        while(n--){delay_short(0x7ff);}
    }
    bsp_delay.c

    led文件夹下文件:

    #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
    bsp_led.h
    #include "bsp_led.h"
    
    /*初始化LED*/
    void led_init(void)
    {   
        // 复用、电气属性寄存器初始化
    
        IOMUXC_SetPinMux(IOMUXC_GPIO1_IO03_GPIO1_IO03,0);
        IOMUXC_SetPinConfig(IOMUXC_GPIO1_IO03_GPIO1_IO03,0x10B0);
        // GPIO1方向寄存器,
        GPIO1->GDIR = 0x8;
    }
    
    
    // 点亮LED
    void led_on(void)
    {
        GPIO1->DR &= ~(1<<3); //bit3清零
    }
    
    
    // 关闭LED
    void led_off(void)
    {
        GPIO1->DR |=(1<<3);  //bit3置一
    }
    
    
    void led_switch(int led, int status)
    {    
        switch(led)
        {
            case LED0:
                if(status == ON)
                    GPIO1->DR &= ~(1<<3);    /* 打开LED0 */
                else if(status == OFF)
                    GPIO1->DR |= (1<<3);    /* 关闭LED0 */
                break;
        }
    }
    bsp_led.c

    /project文件夹

    上面是基础的驱动,然后是project文件夹

    里面是主函数和汇编的环境配置

    .global _start
    
    _start:
        MRS R0,CPSR
        BIC R0,R0,#0x1f
        ORR R0,R0,#0x13
        MSR CPSR,R0
    
        ldr sp,=0x80200000
    
        b main
    start.s
    #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;
    }
    main.c

    /imx6ul文件夹

    imx6ul是芯片的库文件

     其中,cc.h是我们定义的数据类型,imx6ul.h是自己定义的头文件,这里定义这个头文件是简化了驱动库里导入头文件的方法,因为这里的几个库文件几乎在驱动的.h文件里几乎都要导入,定义了这个文件以后只用导入这个头文件就等于导入所有库文件了。

    #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
    cc.h
    #ifndef __IMX6UL_H
    #define __IMX6UL_H
    
    #include "cc.h"
    #include "MCIMX6Y2.h"
    #include "fsl_common.h"
    #include "fsl_iomuxc.h"
    
    #endif
    imx6ul.h

    Makefile文件

    这里的Makefile文件是个重要点,因为在工程目录里所有的文件是按照路径管理的,在根目录下单Makefile就找不到需要编译的文件了。先把Makefile放下来

    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
    
    # 利用patsubst进行字符串修改,在INCLUDIRS每个路径前加-I \
    $(patsubst <pattern>,<replacement>,<text>) \
    名称:模式字符串替换函数——patsubst。\
    功能:查找<text>中的单词(单词以“空格”、“Tab”或“回车”“换行”分隔)是否符\
    合模式<pattern>,如果匹配的话,则以<replacement>替换。这里,<pattern>可以包括通\
    配符“%”,表示任意长度的字串。如果<replacement>中也包含“%”,那么,<replacement>\
    中的这个“%”将是<pattern>中的那个“%”所代表的字串。\
    (可以用“\”来转义,以“\%”来表示真实含义的“%”字符)\
    返回:函数返回被替换过后的字符串
    INCLUDE            :=$(patsubst %, -I % ,$(INCLUDIRS))
    
    
    #获取项目中.c、.s文件 \
    foreach 类似BASH里的for循环,用法是 $(foreach <var>,<list>,<text>)    \
    就是把list里的单词逐一取出放在变量var中,然后执行text的表达式内,每次text会返回一个字符串。            \
    最后循环结束时,<text>返回值为每个字符串所组成的整个字符串,之间以空格分格,                \
    wildcard为展开指定对象下文件集合
    SFILES            := $(foreach dir ,$(SRCDIRS),$(wildcard $(dir)/*.s))
    CFILES            := $(foreach dir ,$(SRCDIRS),$(wildcard $(dir)/*.c))
    
    #获取不带路径的文件名,用来修改后缀生成.o文件的文件名
    SFILENDIR        := $(notdir $(SFILES))        # 不带路径的文件名,
    CFILENDIR        := $(notdir $(CFILES))        # 不带路径的文件名
    
    
    # 将不带路径的文件名转换成.o后缀名,对应编译后文件名
    SOBJS            := $(patsubst %, obj/%,$(SFILENDIR:.s=.o))    #.s=.o是把.s用.o替换
    COBJS            := $(patsubst %, obj/%,$(CFILENDIR:.c=.o))      #.c=.o是把.c用.o替换
    
    OBJS             := $(SOBJS) $(COBJS)
    
    VPATH            := $(SRCDIRS)            
    
    .PHONY: clean
    
    $(TARGET).bin : $(OBJS)
    
        $(LD) -Timx6ul.lds -o $(TARGET).elf $^                   #将所有依赖文件链接,生成.elf文件
        $(OBJCOPY) -O binary -S $(TARGET).elf $@                #将elf转换为依赖的目标集合
        $(OBJDUMP) -D -m arm $(TARGET).elf > $(TARGET).dis        #将elf文件反汇编
    
    
    # 静态模式 <Targets...>:<tatgets-pattern>:<prereq-patterns...>下面两天为自写
    $(SOBJS) :    obj/%.o    :    %.s  #将所有的.s文件编译成.o文件放在obj文件夹内
        $(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)

    大体的说明我都注释出来了,就是用了好几种函数

    包括但不限于替换字符串的patsubst,循环结构的foreach,静态模式等,这个Makefile文件就作为后期驱动开发用到的通用Makefile了。整个文件结构要比以前用到的Makefile复杂了好多,但是按照注释看应该好理解。调试的时候在一个地方卡了很久:

    SOBJS            := $(patsubst %, obj/%,$(SFILENDIR:.s=.o))    #.s=.o是把.s用.o替换

    patsubst后面第一个百分号后多了个空格,编译的时候一直报错

     并且后面用打印的伪目标调试也能打印出来对应的变量,一定要注意。

     链接脚本

    注意看一下Makefile里的链接,我们使用了一个叫做链接脚本的文件来替换链接地址0x87800000。这个脚本就是根目录下单一个文件,拷贝在路径下就可以了,大致作用就是用于规定如何把输入文件内的section放入输出文件内, 并控制输出文件内各部分在程序地址空间内的布局. 但也可以用连接命令做一些其他事情,具体作用以后有机会再讲。

    SECTIONS{
        . = 0X87800000;
        .text :
        {
            obj/start.o 
            *(.text)
        }
        .rodata ALIGN(4) : {*(.rodata*)}     
        .data ALIGN(4)   : { *(.data) }    
        __bss_start = .;    
        .bss ALIGN(4)  : { *(.bss)  *(COMMON) }    
        __bss_end = .;
    }
    imx6ul.lds
  • 相关阅读:
    汇编入门学习笔记 (十二)—— int指令、port
    c#List泛型数据扩展,把List&lt;&gt;型数据格式化成List&lt;SelectListItem&gt;,用来作dropdownlist的数据
    使用 Jersey 和 Apache Tomcat 构建 RESTful Web 服务
    Centos6.5 VNC 配置
    HP服务器更换主板前后的注意事项
    【转】BCSphere入门教程01:Immediate Alert--不错
    【转】命令行使用7zip
    【转】 Android BCM4330 蓝牙BT驱动调试记录
    【转】android-support-v7-appcompat.jar 的安装及相关问题解决 --- 汇总整理
    【转】如何在eclipse里关联查看android源码
  • 原文地址:https://www.cnblogs.com/yinsedeyinse/p/15747289.html
Copyright © 2020-2023  润新知