Linux之ARM(MX6U)裸机之BSP工程管理实验

Linux之ARM(MX6U)裸机之BSP工程管理实验

  • 1.工程管理简介
  • 2.实验程序编写
    • 2.1创建 imx6ul.h 文件
    • 2.2创建个.vscode文件修改includePath
    • 2.3 编写 led 驱动代码
    • 2.4 编写时钟驱动代码
    • 2.5 编写延时驱动代码
    • 2.6 修改 main.c 文件并建立main.h文件
  • 3.编译下载验证
    • 3.1编写 Makefile
    • 3.2 编写脚本链接
    • 3.3 编译下载

1.工程管理简介

打开我们上一章的工程根目录,如图所示:
在这里插入图片描述

在图中我们将所有的源码文件都放到工程根目录下,即使这个工程只是完成了一个 简单的流水灯的功能,但是其工程根目录下的源码文件就已经不少了。如果在添加一些其他的 功能文件,那么文档就会更大,显得很混乱,所以我们需要对这个工程进行整理,将源码文件 分模块、分功能整理。我们可以打开一个 STM32 的例程,如图:Linux之ARM(MX6U)裸机之BSP工程管理实验_第1张图片
上图中工程目录就很美观,不同的功能模块文件放到不同的文件夹中,比如驱动文 件就放到 HARDWARE 文件夹中,ST 的官方库就放到 STM32F10x_FWLib 文件夹中,编译产 生的过程文件放到 OBJ 文件夹中,
我们参照(Linux之ARM(MX6U)裸机之使用官方SDK移植实验)来写。

我们也可以像这样建立工程目录,新建名为“5_ledc_bsp”的文件夹,在里面新建 bsp、imx6ul、obj 和 project 这 4 个文件夹, 完成以后如图 :
在这里插入图片描述
其中 bsp 用来存放驱动文件;imx6ul 用来存放跟芯片有关的文件,比如 NXP 官方的 SDK 库文件;obj 用来存放编译生成的.o 文件;project 存放 start.S 和 main.c 文件,也就是应用文件; 将十二章实验中的 cc.h、fsl_common.h、fsl_iomuxc.h 和 MCIMX6Y2.h 这四个文件拷贝到文件 夹 imx6ul 中;将 start.S 和 main.c 这两个文件拷贝到文件夹 project 中,,比如函数 clk_enable、led_init 和 delay,这三个函数 可以分为三类:时钟驱动、LED 驱动和延时驱动。因此我们可以在 bsp 文件夹下创建三个子文 件夹:clk、delay 和 led,分别用来存放时钟驱动文件、延时驱动文件和 LED 驱动文件,这样 main.c 函数就会清爽很多,程序功能模块清晰。

2.实验程序编写

使用 VScode 新建工程,工程名字为“ledc_bsp”。
Linux之ARM(MX6U)裸机之BSP工程管理实验_第2张图片

2.1创建 imx6ul.h 文件

新建文件 imx6ul.h,然后保存到文件夹 imx6ul 中,在 imx6ul.h 中输入如下内容:

#ifndef __IMX6UL_H
	#define __IMX6UL_H
	
	#include "cc.h"
	#include "MCIMX6Y2.h"
	#include "fsl_common.h"
	#include "fsl_iomuxc.h"
	
	#endif


2.2创建个.vscode文件修改includePath

是为了vscode解决找不到工程的头文件的问题
在终端创建“ .vscode文件夹 ”,打开c_cpp_properties.json文件
Linux之ARM(MX6U)裸机之BSP工程管理实验_第3张图片
修改includePath
Linux之ARM(MX6U)裸机之BSP工程管理实验_第4张图片
这样刷新一下,就可以包含所需的头文件了

2.3 编写 led 驱动代码

新建 bsp_led.h 和 bsp_led.c 两个文件,将这两个文件存放到 bsp/led 中,在 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" 
 
 * 初始化 LED 对应的 GPIO */
 
void led_init(void)
{
     /* 1、初始化 IO 复用, 复用为 GPIO1_IO03 */ 
     IOMUXC_SetPinMux(IOMUXC_GPIO1_IO03_GPIO1_IO03,0);

      /* 2、配置 GPIO1_IO03 的 IO 属性 */
     IOMUXC_SetPinConfig(IOMUXC_GPIO1_IO03_GPIO1_IO03,0X10B0);

      /* 3、初始化 GPIO, GPIO1_IO03 设置为输出 */ 
      GPIO1->GDIR = 0x8;

       /* 4、设置 GPIO1_IO03 输出低电平,打开 LED0 */ 
       GPIO1->DR = 0x0;


}

/* 打开 LED 灯 */
void led_on(void)
{ 
    /*将 GPIO1_DR 的 bit3 清零 */
    GPIO1->DR &= ~(1<<3);

}

void led_off(void)
{

   /* 将 GPIO1_DR 的 bit3 置 1 */
   GPIO1->DR |= (1<<3);

}

/*LED灯控制开关*/
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_led.c 里面就两个函数 led_init 和 led_switch,led_init 函数用来初始化 LED 所使用的 IO,led_switch 函数是控制 LED 灯的打开和关闭

2.4 编写时钟驱动代码

新建 bsp_clk.h 和 bsp_clk.c 两个文件,将这两个文件存放到 bsp/clk 中,在 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" 
*使能 I.MX6U 所有外设时钟 */
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 只有一个 clk_enable 函数,用来使能所有的外设时钟。

2.5 编写延时驱动代码

新建 bsp_delay.h 和 bsp_delay.c 两个文件,将这两个文件存放到 bsp/delay 中,在 bsp_delay.h 中输入输入如下内容:

 #include "imx6ul.h" 
 #ifndef __BSP_DELAY_H
 #define __BSP_DELAY_H

 /* 函数声明 */ 
void delay_short(volatile unsigned int n);
void delay(volatile unsigned int n);

#endif // !__BSP_DELAY_H

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

bsp_delay.c 里面就两个函数,delay_short 和 delay。

2.6 修改 main.c 文件并建立main.h文件

main.c文件:

#include "mian.h"
#include "bsp_clk.h"
#include "bsp_led.h"
#include "bsp_delay.h"


int main(void)
{
    clk_enable();     /* 使能所有的时钟     */ 
    led_init();        /* 初始化 led          */ 

    while (1)
    {
        led_off();    /* 关闭 LED            */ 
        delay(1000);
 
        led_on();     /* 打开 LED            */ 
        delay(1000);
    }
    
    return 0;
}

main.h文件:

#ifndef __MAIN_H
#define __MAIN_H

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


#endif // !__MAIN_H

在 main.c 中我们仅仅留下了 main 函数,至此,本例程跟程序相关的内容就全部编写好了。。

3.编译下载验证

3.1编写 Makefile

在文件 Makefile 中输入如下所示内容:

CROSS_COMPILE 	    ?= arm-linux-gnueabihf-
	TARGET		  	?= ledc
	
	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 
				   
	INCLUDE			:= $(patsubst %, -I %, $(INCDIRS))
	
	SFILES			:= $(foreach dir, $(SRCDIRS), $(wildcard $(dir)/*.S))
	CFILES			:= $(foreach dir, $(SRCDIRS), $(wildcard $(dir)/*.c))
	
	SFILENDIR		:= $(notdir  $(SFILES))
	CFILENDIR		:= $(notdir  $(CFILES))
	
	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)

可以看出实验的 Makefile 文件要比前面的实验复杂很多,因为这个Makefile 代码是一个通用 Makefile,我们以后所有的裸机例程都使用这个 Makefile。使用时候只要将所需要编译的源文件所在的目录添加到 Makefile 中即可。

第 1~7 行定义了一些变量,除了第 2 行以外其它的都是跟编译器有关的,如果使用其它编 译器的话只需要修改第 1 行即可。第 2 行的变量 TARGET 目标名字,不同的例程肯定名字不一样。

第 9 行的变量 INCDIRS 包含整个工程的.h 头文件目录,文件中的所有头文件目录都要添 加到变量INCDIRS中。比如本例程中包含.h头文件的目录有imx6ul、bsp/clk、bsp/delay和bsp/led, 所以就需要在变量 INCDIRS 中添加这些目录,即:

INCDIRS := imx6ul bsp/clk bsp/led bsp/delay

仔细观察的话会发现第 9~11 行后面都会有一个符号“\”,这个相当于“换行符”,表示本行和下一行属于同一行,一般一行写不下的时候就用符号“\”来换行。在后面的裸机例程中我们会根据实际情况来在变量 INCDIRS 中添加头文件目录。

第 14 行是变量 SRCDIRS,和变量 INCDIRS 一样,只是 SRCDIRS 包含的是整个工程的所有.c 和.S 文件目录。比如本例程包含有.c 和.S 的目录有 bsp/clk、 bsp/delay、 bsp/led 和 project,即:

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

第 19 行的变量 INCLUDE 是用到了函数 patsubst,通过函数 patsubst 给变量 INCDIRS 添加 一个“-I”,即:

 INCLUDE := -I imx6ul -I bsp/clk -I bsp/led -I bsp/delay 

加“-I”的目的是因为 Makefile 语法要求指明头文件目录的时候需要加上“-I”

第 21 行变量 SFILES 保存工程中所有的.s 汇编文件(包含绝对路径),变量 SRCDIRS 已经 存放了工程中所有的.c 和.S 文件,所以我们只需要从里面挑出所有的.S 汇编文件即可,这里借 助了函数 foreach 和函数 wildcard,最终 SFILES 如下:

SFILES := project/start.S 

第 22 行变量 CFILES 和变量 SFILES 一样,只是 CFILES 保存工程中所有的.c 文件(包含绝 对路径),最终 CFILES 如下:

 CFILES = project/main.c bsp/clk/bsp_clk.c bsp/led/bsp_led.c bsp/delay/bsp_delay.c 

第 24 和 25 行的变量 SFILENDIR 和 CFILENDIR 包含所有的.S 汇编文件和.c 文件,相比变 量 SFILES 和 CFILES,SFILENDIR 和 CFILNDIR 只是文件名,不包含文件的绝对路径。使用 函数 notdir 将 SFILES 和 CFILES 中的路径去掉即可,SFILENDIR 和 CFILENDIR 如下:

 SFILENDIR = start.S 
 CFILENDIR = main.c bsp_clk.c bsp_led.c bsp_delay.c 

第 27 和 28 行的变量 SOBJS 和 COBJS 是.S 和.c 文件编译以后对应的.o 文件目录,默认所有的文件编译出来的.o 文件和源文件在同一个目录中,这里我们将所有的.o 文件都放到 obj 文件夹下, SOBJS 和 COBJS 内容如下:

SOBJS = obj/start.o
COBJS = obj/main.o obj/bsp_clk.o obj/bsp_led.o obj/bsp_delay.o

第 29 行变量 OBJS 是变量 SOBJS 和 COBJS 的集合,如下:

OBJS = obj/start.o obj/main.o obj/bsp_clk.o obj/bsp_led.o obj/bsp_delay.o

编译完成以后所有的.o 文件就全部存放到了 obj 目录下,如图
在这里插入图片描述
第 31 行的 VPATH 是指定搜索目录的,这里指定的搜素目录就是变量 SR
CDIRS 所保存的 目录,这样当编译的时候所需的.S 和.c 文件就会在 SRCDIRS 中指定的目录中查找。

第 33 行指定了一个伪目标 clean,

第 35~47 行就很熟悉了。

3.2 编写脚本链接

imx6ul.lds 链接脚本内容如下所示:

SECTIONS{
    . = 0x87800000;
    .text :
    {
        obj/start.o
        *(.text)

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

}

3.3 编译下载

使用 Make 命令编译代码,编译成功以后使用软件 imxdownload 将编译完成的 bsp.bin 文件 下载到 SD 卡中,命令如下:

 chmod 777 imxdownload   //给予 imxdownload 可执行权限,一次即可
  ./imxdownload bsp.bin /dev/sdd  //烧写到 SD 卡中  

烧写成功以后将 SD 卡插到开发板的 SD 卡槽中,然后复位开发板,如果代码运行正常的 话 LED0 就会以 1000ms 的时间间隔亮灭,
具体步骤请看前面几篇博文的内容。

你可能感兴趣的:(IMX6ULL)