本文主要是介绍SDK 移植及BSP工程管理,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
NXP 官方为 I.MX6ULL 编写了 SDK 包,在 SDK 包里面 NXP 已经编写好了寄存器定义文件,
所以我们可以直接移植 SDK 包里面的文件来用
1 I.MX6ULL 官方 SDK 包简介NXP 针对 I.MX6ULL 编写了一个 SDK 包,这个 SDK 包就类似于 STM32 的 STD 库或者HAL 库,这个 SDK 包提供了 Windows 和 Linux 两种版本,分别针对主机系统是 Windows 和 Linux。在 NXP 的 定位里面,I.MX6ULL 就是一个 Cotex-A 内核的高端单片机,定位类似 ST 的 STM32H7。I.MX6ULL 的 SDK 包在 NXP 官网下载,下载界面如图双击 SDK_2.2_MCIM6ULL_RFP_Win.exe 安装 SDK 包,安装的时候需要设置好安装位置,安装完成以后的 SDK 包如图我们重点是需要 SDK 包里面与寄存器定义相关的文件,一共需要如下三个文件:fsl_common.h:位置SDK_2.2_MCIM6ULL\devices\MCIMX6Y2\drivers\fsl_common.h。fsl_iomuxc.h: 位置为 SDK_2.2_MCIM6ULL\devices\MCIMX6Y2\drivers\fsl_iomuxc.h。MCIMX6Y2.h: 位置为 SDK_2.2_MCIM6ULL\devices\MCIMX6Y2\MCIMX6YH2.h。整个 SDK 包我们就需要上面这三个文件,把这三个文件准备好,我们后面移植要用。SDK 文件移植
使用 VSCode 新建工程,将 fsl_common.h 、 fsl_iomuxc.h 和 MCIMX6Y2.h 这三个文件拷贝到工程中,这三个文件直接编译的话肯定会出错的!需要对其做删减,因为这三个文件里面的 代码都比较大,所以就不详细列出这三个文件删减以后的内容了创建 cc.h 文件新建一个名为 cc.h 的头文件, cc.h 里面存放一些 SDK 库文件需要使用到的数据类型,在cc.h 里面输入如下代码:1 #ifndef __CC_H 2 #define __CC_H14 * 自定义一些数据类型供库文件使用 15 */ 16 #define __I volatile 17 #define __O volatile 18 #define __IO volatile 19 20 #define ON 1 21 #define OFF 0 22 23 typedef signed char int8_t; 24 typedef signed short int int16_t; 25 typedef signed int int32_t; 26 typedef unsigned char uint8_t; 27 typedef unsigned short int uint16_t; 28 typedef unsigned int uint32_t; 29 typedef unsigned long long uint64_t; 30 typedef signed char s8; 31 typedef signed short int s16; 32 typedef signed int s32; 33 typedef signed long long int s64; 34 typedef unsigned char u8; 35 typedef unsigned short int u16; 36 typedef unsigned int u32; 37 typedef unsigned long long int u64; 38 39 #endif
编写实验代码新建 start.S 和 main.c 这两个文件,start.S 文件的内容和上一章一样,直接复制过来就可以, 创建完成以后工程目录如图 在 main.c 中输入如下所示代码:1 #include "fsl_common.h" 2 #include "fsl_iomuxc.h" 3 #include "MCIMX6Y2.h" 4 5 /* 6 * @description : 使能 I.MX6U 所有外设时钟 7 * @param : 无 8 * @return : 无 9 */ 10 void clk_enable(void) 11 { 12 CCM->CCGR0 = 0XFFFFFFFF; 13 CCM->CCGR1 = 0XFFFFFFFF; 14 15 CCM->CCGR2 = 0XFFFFFFFF; 16 CCM->CCGR3 = 0XFFFFFFFF; 17 CCM->CCGR4 = 0XFFFFFFFF; 18 CCM->CCGR5 = 0XFFFFFFFF; 19 CCM->CCGR6 = 0XFFFFFFFF; 20 21 } 22 23 /* 24 * @description : 初始化 LED 对应的 GPIO 25 * @param : 无 26 * @return : 无 27 */ 28 void led_init(void) 29 { 30 /* 1、初始化 IO 复用 */ 31 IOMUXC_SetPinMux(IOMUXC_GPIO1_IO03_GPIO1_IO03,0); 32 33 /* 2、、配置 GPIO1_IO03 的 IO 属性 34 *bit 16:0 HYS 关闭 35 *bit [15:14]: 00 默认下拉 36 *bit [13]: 0 kepper 功能 37 *bit [12]: 1 pull/keeper 使能 38 *bit [11]: 0 关闭开路输出 39 *bit [7:6]: 10 速度 100Mhz 40 *bit [5:3]: 110 R0/6 驱动能力 41 *bit [0]: 0 低转换率 42 */ 43 IOMUXC_SetPinConfig(IOMUXC_GPIO1_IO03_GPIO1_IO03,0X10B0); 44 45 /* 3、初始化 GPIO,设置 GPIO1_IO03 设置为输出 */ 46 GPIO1->GDIR |= (1 << 3); 47 48 /* 4、设置 GPIO1_IO03 输出低电平,打开 LED0 */ 49 GPIO1->DR &= ~(1 << 3); 50 } 51 52 /* 53 * @description : 打开 LED 灯 54 * @param : 无 55 * @return : 无 56 */ 57 void led_on(void) 58 { 59 /* 将 GPIO1_DR 的 bit3 清零 */ 60 GPIO1->DR &= ~(1<<3); 61 } 62 63 /* 64 * @description : 关闭 LED 灯 65 * @param : 无 66 * @return : 无 67 */ 68 void led_off(void) 69 { 70 /* 将 GPIO1_DR 的 bit3 置 1 */ 71 GPIO1->DR |= (1<<3); 72 } 73 74 /* 75 * @description : 短时间延时函数 76 * @param - n : 要延时循环次数(空操作循环次数,模式延时) 77 * @return : 无 78 */ 79 void delay_short(volatile unsigned int n) 80 { 81 while(n--){} 82 } 83 84 /* 85 * @description : 延时函数,在 396Mhz 的主频下 86 * 延时时间大约为 1ms 87 * @param - n : 要延时的 ms 数 88 * @return : 无 89 */ 90 void delay(volatile unsigned int n) 91 { 92 while(n--) 93 { 94 delay_short(0x7ff); 95 } 96 } 97 98 /* 99 * @description : main 函数 100 * @param : 无 101 * @return : 无 102 */ 103 int main(void) 104 { 105 clk_enable(); /* 使能所有的时钟 */ 106 led_init(); /* 初始化 led */ 107 108 while(1) /* 死循环 */ 109 { 110 led_off(); /* 关闭 LED */ 111 delay(500); /* 延时 500ms */ 112 113 led_on(); /* 打开 LED */ 114 delay(500); /* 延时 500ms */ 115 } 116 117 return 0; 118 }
编译下载验证编写 Makefile 和链接脚本Makefile 文件内容如下:1 CROSS_COMPILE ?= arm-linux-gnueabihf- 2 NAME ?= ledc 3 4 CC := $(CROSS_COMPILE)gcc 5 LD := $(CROSS_COMPILE)ld 6 OBJCOPY := $(CROSS_COMPILE)objcopy 7 OBJDUMP := $(CROSS_COMPILE)objdump 8 9 OBJS := start.o main.o 10 11 $(NAME).bin:$(OBJS) 12 $(LD) -Timx6ul.lds -o $(NAME).elf $^ 13 $(OBJCOPY) -O binary -S $(NAME).elf $@ 14 $(OBJDUMP) -D -m arm $(NAME).elf > $(NAME).dis 15 16 %.o:%.s 17 $(CC) -Wall -nostdlib -c -O2 -o $@ $< 18 19 %.o:%.S 20 $(CC) -Wall -nostdlib -c -O2 -o $@ $< 21 22 %.o:%.c 23 $(CC) -Wall -nostdlib -c -O2 -o $@ $< 24 25 clean: 26 rm -rf *.o $(NAME).bin $(NAME).elf $(NAME).dis
编译下载使用 Make 命令编译代码,编译成功以后使用软件 imxdownload 将编译完成的 ledc.bin 文件下载到 SD 卡中,命令如下:烧写成功以后将 SD 卡插到开发板的 SD 卡槽中,然后复位开发板,如果代码运行正常的话 LED0 就会以 500ms 的时间间隔亮灭,实验现象和上一章一样
BSP工程管理原理
目的就是为了模块化整理代码,同一个属性的文件存放在同一个目录里面
1.修建所需的文件夹,将同一属性的文件放到相应的文件夹中
2.修改clk,led,delay驱动,创建对应的驱动文件,然后放置到对应的目录中
3.根据编写的驱动新文件。修改main.c文件内容
设置vs code头文件路径。先创建.vscode目录,然后打开C/C++配置器,会在.vscode目录下生成一个叫做c_cpp_properties.json的文件
新建名为“ 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 中。我们前面的实验中所有 的驱动相关的函数都写到了 main.c 文件中,比如函数 clk_enable 、 led_init 和 delay ,这三个函数 可以分为三类:时钟驱动、LED 驱动和延时驱动。因此我们可以在 bsp 文件夹下创建三个子文 件夹:clk 、 delay 和 led ,分别用来存放时钟驱动文件、延时驱动文件和 LED 驱动文件,这样 main.c 函数就会清爽很多,程序功能模块清晰。工程文件夹都创建好了,接下来就是编写代码 了,其实就是将时钟驱动、LED 驱动和延时驱动相关的函数从 main.c 中提取出来做成一个独立 的驱动文件 。实验程序编写创建 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
编写 led 驱动代码新建 bsp_led.h 和 bsp_led.c 两个文件,将这两个文件存放到 bsp/led 中,在 bsp_led.h 中输入 输入如下内容:1 #ifndef __BSP_LED_H 2 #define __BSP_LED_H 3 #include "imx6ul.h" 15 #define LED0 0 16 17 /* 函数声明 */ 18 void led_init(void); 19 void led_switch(int led, int status); 20 #endif
bsp_led.h 的内容很简单,就是一些函数声明,在 bsp_led.c 中输入如下内容:1 #include "bsp_led.h" 18 void led_init(void) 19 { 20 /* 1、初始化 IO 复用 */ 21 IOMUXC_SetPinMux(IOMUXC_GPIO1_IO03_GPIO1_IO03,0); 22 23 /* 2、、配置 GPIO1_IO03 的 IO 属性 */ 24 IOMUXC_SetPinConfig(IOMUXC_GPIO1_IO03_GPIO1_IO03,0X10B0); 25 26 /* 3、初始化 GPIO,GPIO1_IO03 设置为输出*/ 27 GPIO1->GDIR |= (1 << 3); 28 29 /* 4、设置 GPIO1_IO03 输出低电平,打开 LED0*/ 30 GPIO1->DR &= ~(1 << 3); 31 } 33 /* 34 * @description : LED 控制函数,控制 LED 打开还是关闭 35 * @param - led : 要控制的 LED 灯编号 36 * @param - status : 0,关闭 LED0,1 打开 LED0 37 * @return : 无 38 */ 39 void led_switch(int led, int status) 40 { 41 switch(led) 42 { 43 case LED0: 44 if(status == ON) 45 GPIO1->DR &= ~(1<<3); /* 打开 LED0 */ 46 else if(status == OFF) 47 GPIO1->DR |= (1<<3); /* 关闭 LED0 */ 48 break; 49 } 50 }
bsp_led.c 里面就两个函数 led_init 和 led_switch , led_init 函数用来初始化 LED 所使用的IO , led_switch 函数是控制 LED 灯的打开和关闭,这两个函数都很简单。编写时钟驱动代码新建 bsp_clk.h 和 bsp_clk.c 两个文件,将这两个文件存放到 bsp/clk 中,在 bsp_clk.h 中输入 输入如下内容:1 #ifndef __BSP_CLK_H 2 #define __BSP_CLK_H14 #include "imx6ul.h" 15 16 /* 函数声明 */ 17 void clk_enable(void); 18 19 #endif
bsp_clk.h 很简单,在 bsp_clk.c 中输入内容:1 #include "bsp_clk.h" 14 /* 15 * @description : 使能 I.MX6U 所有外设时钟 16 * @param : 无 17 * @return : 无 18 */ 19 void clk_enable(void) 20 { 21 CCM->CCGR0 = 0XFFFFFFFF; 22 CCM->CCGR1 = 0XFFFFFFFF; 23 CCM->CCGR2 = 0XFFFFFFFF; 24 CCM->CCGR3 = 0XFFFFFFFF; 25 CCM->CCGR4 = 0XFFFFFFFF; 26 CCM->CCGR5 = 0XFFFFFFFF; 27 CCM->CCGR6 = 0XFFFFFFFF; 28 }
bsp_clk.c 只有一个 clk_enable 函数,用来使能所有的外设时钟。编写延时驱动代码新建 bsp_delay.h 和 bsp_delay.c 两个文件,将这两个文件存放到 bsp/delay 中,在 bsp_delay.h 中输入输入如下内容:1 #ifndef __BSP_DELAY_H 2 #define __BSP_DELAY_H 13 #include "imx6ul.h" 14 15 /* 函数声明 */ 16 void delay(volatile unsigned int n); 17 18 #endif
在 bsp_delay.c 中输入内容:1 #include "bsp_delay.h" 2 3 /* 4 * @description : 短时间延时函数 5 * @param - n : 要延时循环次数(空操作循环次数,模式延时) 6 * @return : 无 7 */ 8 void delay_short(volatile unsigned int n) 9 { 10 while(n--){} 11 } 12 13 /* 14 * @description : 延时函数,在 396Mhz 的主频下 15 * 延时时间大约为 1ms 16 * @param - n : 要延时的 ms 数 17 * @return : 无 18 */ 19 void delay(volatile unsigned int n) 20 { 21 while(n--) 22 { 23 delay_short(0x7ff); 24 } 25 }
修改 main.c 文件1 #include "bsp_clk.h" 2 #include "bsp_delay.h" 3 #include "bsp_led.h" 4 5 /* 6 * @description : main 函数 7 * @param : 无 8 * @return : 无 9 */ 10 int main(void) 11 { 12 clk_enable(); /* 使能所有的时钟 */ 13 led_init(); /* 初始化 led */ 14 15 while(1) 16 { 17 /* 打开 LED0 */ 18 led_switch(LED0,ON); 19 delay(500); 20 21 /* 关闭 LED0 */ 22 led_switch(LED0,OFF); 23 delay(500); 24 } 25 26 return 0; 27 }
编译下载验证编写 Makefile 和链接脚本在工程根目录下新建 Makefile 和 imx6ul.lds 这两个文件,创建完成以后的工程如图在文件 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)
链接脚本 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 }
编译下载使用 Make 命令编译代码,编译成功以后使用软件 imxdownload 将编译完成的 bsp.bin 文件下载到 SD 卡中,命令如下:烧写成功以后将 SD 卡插到开发板的 SD 卡槽中,然后复位开发板,如果代码运行正常的话 LED0 就会以 500ms 的时间间隔亮灭wink成功
这篇关于SDK 移植及BSP工程管理的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!