IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 嵌入式 -> 第2期ARM裸机篇:【11】BSP工程管理实验 -> 正文阅读

[嵌入式]第2期ARM裸机篇:【11】BSP工程管理实验

简介

在前面的章节中,我们都是将所有的源码文件放到工程的根目录下,如果工程文件比较少的话这样做无可厚非。

如果工程源文件达到几十、甚至数百个的时候,这样一股脑全部放到根目录下就会使工程显得混乱不堪

另外我们也需要将源码文件中,所有完成同一个功能的代码提取出来放到一个单独的文件中,也就是对程序分功能理

所以我们必须对工程文件做管理,将不同功能的源码文件放到不同的目录中。本章我们就来学习一下如何对一个工程进行整理,使其美观、功能模块清晰、易于阅读。

目标

学习如何对一个工程进行整理,使其美观、功能模块清晰、易于阅读。

阅读基础

熟悉计算机。

环境说明

  • windows10

参考资料

  • 原子文档:I.MX6ULL开发指南第十三章
  • NXP官方文档:I.MX6ULL参考手册、数据手册

工程管理简介

打开上一章的工程根目录,如图所示:

BlogImage-20210927112956

在图中我们将所有的源码文件都放到工程根目录下,即使这个工程只是完成了一个简单的流水灯的功能,但是其工程根目录下的源码文件就已经不少了

如果在添加一些其他的功能文件,那么文档就会更大,显得很混乱,所以我们需要对这个工程进行整理,将源码文件分模块、分功能整理。我们可以打开一个 STM32 的例程,如图所示:

BlogImage-20210927113257

图中的工程目录就很美观,不同的功能模块文件放到不同的文件夹中,比如驱动文件就放到 HARDWARE文件夹中,ST 的官方库就放到 STM32F10x_FWLib文件夹中,编译产生的过程文件放到 OBJ文件夹中。我们可以参考这个工程目录结构来整理上面的的例程4_ledc_sdk工程,新建名为“5_ledc_bsp”的文件夹,如下图:

BlogImage-20210927113903

在里面新建 bspimx6ulobjproject这 4 个文件夹,完成以后如图所示:

BlogImage-20210927114046

其中

  • bsp用来存放驱动文件;

  • imx6ul用来存放跟芯片有关的文件,比如 NXP 官方的 SDK库文件;

  • obj用来存放编译生成的.o 文件;

  • project存放 start.Smain.c 文件,也就是应用文件;

  1. 4_ledc_sdk中的 cc.h、fsl_common.h、fsl_iomuxc.h 和 MCIMX6Y2.h 这四个文件拷贝到文件夹 imx6ul中;如下图:

    BlogImage-20210927115509

  2. 将 start.S 和 main.c 这两个文件拷贝到文件夹 project 中。如下图:

    BlogImage-20210927115701

  3. 在 bsp 文件夹下创建三个子文件夹:clk、delay 和 led,分别用来存放时钟驱动文件、延时驱动文件和 LED 驱动文件,这样main.c 函数就会清爽很多,程序功能模块清晰。其实就是将时钟驱动、LED 驱动和延时驱动相关的函数从 main.c 中提取出来做成一个独立的驱动文件

硬件原理分析

使用到的硬件资源就是一个 LED0。

参考文章:第2期ARM裸机篇:【6】 汇编LED驱动实验1_汇编LED代码编写_心飞的博客-CSDN博客

参考文章:第2期ARM裸机篇:【6】 汇编LED驱动实验1_汇编LED代码编写_心飞的博客-个人网站

实验程序编写

创建 imx6ul.h 文件

新建文件 imx6ul.h,然后保存到文件夹 imx6ul 中,如下图:

BlogImage-20210929115843

在 imx6ul.h 中输入如下内容:

#ifndef __IMX6UL_H
#define __IMX6UL_H
/***************************************************************
Copyright ? zuozhongkai Co., Ltd. 1998-2019. All rights reserved.
文件名	: 	 imx6ul.h
作者	   : 左忠凯
版本	   : V1.0
描述	   : 包含一些常用的头文件。
其他	   : 无
论坛 	   : www.openedv.com
日志	   : 初版V1.0 2019/1/3 左忠凯创建
***************************************************************/
#include "cc.h"
#include "MCIMX6Y2.h"
#include "fsl_common.h"
#include "fsl_iomuxc.h"

#endif

文件 imx6ul.h 很简单,就是引用了芯片相关的头文件,以后我们就可以方便的在其他文件中引用它们。

编写 led 驱动代码

新建 bsp_led.hbsp_led.c 两个文件,将这两个文件存放到 bsp/led 中,

BlogImage-20210929143414

bsp_led.h 中输入如下内容:

#ifndef __BSP_LED_H
#define __BSP_LED_H
#include "imx6ul.h"
/***************************************************************
Copyright ? zuozhongkai Co., Ltd. 1998-2019. All rights reserved.
文件名	: 	 bsp_led.h
作者	   : 左忠凯
版本	   : V1.0
描述	   : LED驱动头文件。
其他	   : 无
论坛 	   : www.openedv.com
日志	   : 初版V1.0 2019/1/4 左忠凯创建
***************************************************************/

#define LED0	0

/* 函数声明 */
void led_init(void);
void led_switch(int led, int status);
#endif

bsp_led.h 的内容很简单,就是一些函数声明,在 bsp_led.c 中输入如下内容:

/**************************************************************
Copyright ? zuozhongkai Co., Ltd. 1998-2019. All rights reserved.
文件名 : bsp_led.c
作者 : 左忠凯
版本 : V1.0
描述 : LED驱动文件。
其他 : 无
日志 : 初版 V1.0 2021/9/29 左忠凯创建
**************************************************************/

#include "bsp_led.h"


/*

 * @description : 初始化 LED 对应的 GPIO
 * @param : 无
 * @return : 无
   */

void led_init(void)
{
    /* 1、初始化 IO 复用, 复用为 GPIO1_IO03 */
    IOMUXC_SetPinMux(IOMUXC_GPIO1_IO03_GPIO1_IO03,0);

    /* 2、配置 GPIO1_IO03 的 IO 属性 
    *bit 16:0 HYS 关闭
    *bit [15:14]: 00 默认下拉
    *bit [13]: 0 kepper 功能
    *bit [12]: 1 pull/keeper 使能
    *bit [11]: 0 关闭开路输出
    *bit [7:6]: 10 速度 100Mhz
    *bit [5:3]: 110 R0/6 驱动能力
    *bit [0]: 0 低转换率
    */
    IOMUXC_SetPinConfig(IOMUXC_GPIO1_IO03_GPIO1_IO03,0X10B0);
    
    /* 3、设置 GPIO1_IO03 为输出 */
    GPIO1->GDIR |= (1<<3);
    
    /* 4、设置 GPIO1_IO03 输出低电平,打开 LED0 */
    GPIO1->DR &= ~(1<<3);


}

/*

 * @description : LED 控制函数,控制 LED 打开还是关闭

 * @param led 要控制的 LED 灯编号

 * @param status

 * @return : 无
   */
   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_clk.h 和 bsp_clk.c 两个文件,将这两个文件存放到 bsp/clk 中,如下图:

BlogImage-20210929112413

在 bsp_clk.h 中输入输入如下内容:

#ifndef __BSP_CLK_H
#define __BSP_CLK_H

/**************************************************************
Copyright ? zuozhongkai Co., Ltd. 1998-2019. All rights reserved.
文件名 : bsp_clk.h
作者 : 左忠凯
版本 : V1.0
描述 :  系统时钟驱动头文件。
其他 : 无
日志 : 初版 V1.0 2021/9/29 左忠凯创建
**************************************************************/

#include "imx6ul.h"

void clk_enable(void);

#endif /* __BSP_CLK_H */

bsp_clk.h 很简单,在 bsp_clk.c 中输入内容:

#include "bsp_clk.h"

/***************************************************************
   Copyright ? zuozhongkai Co., Ltd. 1998-2019. All rights reserved.
   文件名	: 	 bsp_clk.c
   作者	   : 左忠凯
   版本	   : V1.0
   描述	   : 系统时钟驱动。
   其他	   : 无
   论坛 	   : www.openedv.com
日志	   : 初版V1.0 2019/1/4 左忠凯创建
***************************************************************/

/*

 * @description	: 使能I.MX6U所有外设时钟
 * @param 		: 无
 * @return 		: 无
   */
   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 函数,用来使能所有的外设时钟。

编写延时驱动代码

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

#ifndef __BSP_DELAY_H
#define __BSP_DELAY_H

/**************************************************************
Copyright ? zuozhongkai Co., Ltd. 1998-2019. All rights reserved.
文件名 : bsp_delay.h
作者 : 左忠凯
版本 : V1.0
描述 : 延时头文件。
其他 : 无
日志 : 初版 V1.0 2021/9/29 左忠凯创建
**************************************************************/

#include "imx6ul.h"

void delay(volatile unsigned int n);


#endif /* __BSP_DELAY_H */

在 bsp_delay.c 中输入内容:

 /***************************************************************
 Copyright ? zuozhongkai Co., Ltd. 1998-2019. All rights reserved.
 文件名	: 	 bsp_delay.c
	作者	   : 左忠凯
	版本	   : V1.0
	描述	   : 延时文件。
	其他	   : 无
 论坛 	   : www.openedv.com
 日志	   : 初版V1.0 2019/1/4 左忠凯创建
 ***************************************************************/
 #include "bsp_delay.h"
 
 /*
 
  * @description	: 短时间延时函数
  * @param - n	: 要延时循环次数(空操作循环次数,模式延时)
  * @return 		: 无
    */
    void delay_short(volatile unsigned int n)
    {
    while(n--){}
    }
 
 /*
 
  * @description	: 延时函数,在396Mhz的主频下
  * 延时时间大约为1ms
  * @param - n	: 要延时的ms数
  * @return 		: 无
    */
    void delay(volatile unsigned int n)
    {
    while(n--)
    {
    	delay_short(0x7ff);
    }
    }

修改 main.c 文件

在上一篇实验的main.c中,led 驱动、延时驱动和时钟驱动相关的函数全部都写到了 main.c 中,本章我们在前几节已经将这些驱动根据功能模块放置到相应的地方,所以 main.c 里面的内容就得修改,将 main.c 里面的内容改为如下所示代码:

/**************************************************************

Copyright ? zuozhongkai Co., Ltd. 1998-2019. All rights reserved.

文件名	: 	 mian.c
作者	   : 左忠凯
版本	   : V1.0
描述	   : I.MX6U开发板裸机实验5 BSP形式的LED驱动
其他	   : 本实验学习目的:
		 1、将各个不同的文件进行分类,学习如何整理工程、就
		 和学习STM32一样创建工程的各个文件夹分类,实现工程文件
		 的分类化和模块化,便于管理。
		 2、深入学习Makefile,学习Makefile的高级技巧,学习编写	
		 通用Makefile。
论坛 	   : www.openedv.com
在线教育	: www.yuanzige.com
日志	   : 初版V1.0 2019/1/4 左忠凯创建

**************************************************************/

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


/*

 * @description	: mian函数
 * @param 		: 无
 * @return 		: 无
 */
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;

}


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

编译下载验证

编写 Makefile

在工程根目录下新建 Makefile 和 imx6ul.lds 这两个文件,创建完成以后的工程如所示:

BlogImage-20210929161649

Makefile 文件的内容基本和第前一章的 Makefile 一样,如下:

1 CROSS_COMPILE ?= arm-linux-gnueabihf-
2 TARGET ?= bsp
3 
4 CC := $(CROSS_COMPILE)gcc
5 LD := $(CROSS_COMPILE)ld
6 OBJCOPY := $(CROSS_COMPILE)objcopy
7 OBJDUMP := $(CROSS_COMPILE)objdump
8 
9 INCDIRS := imx6ul \
10 bsp/clk \
11 bsp/led \
12 bsp/delay 
13 
14 SRCDIRS := project \
15 bsp/clk \
16 bsp/led \
17 bsp/delay 
18 
19 INCLUDE := $(patsubst %, -I %, $(INCDIRS))
20
21 SFILES := $(foreach dir, $(SRCDIRS), $(wildcard $(dir)/*.S))
22 CFILES := $(foreach dir, $(SRCDIRS), $(wildcard $(dir)/*.c))
23
24 SFILENDIR := $(notdir $(SFILES))
25 CFILENDIR := $(notdir $(CFILES))
26
27 SOBJS := $(patsubst %, obj/%, $(SFILENDIR:.S=.o))
28 COBJS := $(patsubst %, obj/%, $(CFILENDIR:.c=.o))
29 OBJS := $(SOBJS) $(COBJS)
30
31 VPATH := $(SRCDIRS)
32
33 .PHONY: clean
34 
35 $(TARGET).bin : $(OBJS)
36 $(LD) -Timx6ul.lds -o $(TARGET).elf $^
37 $(OBJCOPY) -O binary -S $(TARGET).elf $@
38 $(OBJDUMP) -D -m arm $(TARGET).elf > $(TARGET).dis
39
40 $(SOBJS) : obj/%.o : %.S
41 $(CC) -Wall -nostdlib -c -O2 $(INCLUDE) -o $@ $<
42
43 $(COBJS) : obj/%.o : %.c
44 $(CC) -Wall -nostdlib -c -O2 $(INCLUDE) -o $@ $<
45 
46 clean:
47 rm -rf $(TARGET).elf $(TARGET).dis $(TARGET).bin $(COBJS) $(SOBJS)

可以看出本章实验的 Makefile 文件要比前面的实验复杂很多,因为上面的 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同样的,后面的裸机例程中我们也要根据实际情况在变量 SRCDIRS 中添加相应的文件目录

第 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 行的变量 SFILENDIRCFILENDIR 包含所有的.S 汇编文件和.c 文件,相比变量 SFILESCFILESSFILENDIRCFILNDIR只是文件名,不包含文件的绝对路径。使用函数 notdirSFILESCFILES中的路径去掉即可,SFILENDIRCFILENDIR如下:SFILENDIR = start.SCFILENDIR = main.c bsp_clk.c bsp_led.c bsp_delay.c

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

第 29 行变量 OBJS是变量 SOBJSCOBJS的集合,如下:OBJS = obj/start.o obj/main.o obj/bsp_clk.o obj/bsp_led.o obj/bsp_delay.o编译完成以后所有的.o 文件就全部存放到了 obj 目录下,如图所示:

BlogImage-20210930114555

第 31 行的 VPATH是指定搜索目录的,这里指定的搜素目录就是变量 SRCDIRS所保存的
目录,这样当编译的时候所需的.S 和.c 文件就会在 SRCDIRS中指定的目录中查找

第 33 行指定了一个伪目标 clean,伪目标前面讲解 Makefile 的时候已经讲解过了。

第 35~47 行就很熟悉了,前几章都已经详细的讲解过了。

**上面的 Makefile 文件内容重点工作是找到要编译哪些文件?编译的.o文件存放到哪里?**使用到的编译命令和前面实验使用的一样,其实 Makefile 的重点工作就是解决“从哪里来到哪里去的”问题,也就是找到要编译的源文件、编译结果存放到哪里?真正的编译命令很简洁。

BlogImage-20210930114710

编写链接脚本

链接脚本 imx6ul.lds 的内容基本和上一章一样,主要是start.o 文件路径不同,本章所使用的 imx6ul.lds链接脚本内容如下所示:

1 SECTIONS{ 
2 	. = 0X87800000; 
3 	.text : 
4 	{ 
5 		obj/start.o 
6 		*(.text) 
7	 } 
8 	.rodata ALIGN(4) : {*(.rodata*)} 
9 	.data ALIGN(4) : { *(.data) } 
10 	__bss_start = .; 
11 	.bss ALIGN(4) : { *(.bss) *(COMMON) } 
12	__bss_end = .;
13 }

注意第 5 行设置的 start.o 文件路径,这里和上一篇的链接脚本不同。

编译下载

参考文章:第2期ARM裸机篇:【6】 汇编LED驱动实验1_汇编LED代码编写_心飞的博客-CSDN博客

参考文章:第2期ARM裸机篇:【6】 汇编LED驱动实验1_汇编LED代码编写_心飞的博客-个人网站

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

chmod 777 imxdownload //给予 imxdownload 可执行权限,一次即可
./imxdownload bsp.bin /dev/sdc //烧写到 SD 卡中,不能烧写到/dev/sda 或 sda1 设备里面!

烧写成功以后将 SD 卡插到开发板的 SD 卡槽中,然后复位开发板,如果代码运行正常的话 LED0 就会以 500ms 的时间间隔亮灭,实验现象和上一篇一样。

其他

相关资源下载

I.MX6ULL SDK包.rar-嵌入式文档类资源-CSDN下载

I.MX6ULL官方SDK包移植头文件.rar-嵌入式文档类资源-CSDN下载

小有收获

有收获记得三连哦:😄

有收获记得三连哦

最近更新

查看本文最近更新请点击

欢迎关注微信公众号

weixingognzhonghaoerweima

  嵌入式 最新文章
基于高精度单片机开发红外测温仪方案
89C51单片机与DAC0832
基于51单片机宠物自动投料喂食器控制系统仿
《痞子衡嵌入式半月刊》 第 68 期
多思计组实验实验七 简单模型机实验
CSC7720
启明智显分享| ESP32学习笔记参考--PWM(脉冲
STM32初探
STM32 总结
【STM32】CubeMX例程四---定时器中断(附工
上一篇文章      下一篇文章      查看所有文章
加:2021-10-01 17:03:16  更:2021-10-01 17:04:54 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 4:38:49-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码