参考教程:
正点原子【第二期】手把手教你学Linux之ARM(MX6U)裸机篇_哔哩哔哩_bilibili
一、SDK移植
1、SDK包说明
(1)在上一章进行驱动开发时,外设寄存器组结构体需要自己根据数据手册定义,当寄存器的数量越来越多时,这种开发方式就显得非常低效了。
(2)NXP官方其实提供了一个SDK包,包内有所有寄存器的定义,程序员在开发的时候,可以直接将包内的定义移植到工程中,这样就不需要重复定义了。
(3)SDK包可直接在NXP官网下载。
2、SDK包移植方式
(1)在NXP官网上下载的是一个.exe可执行程序,运行它之后,可以在指定目录生成所需要的配置文件,如下图所示。
(2)SDK包中有非常多的文件,如果只是针对裸机开发,那么真正有用的文件只有如下3个:
①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
(3)以上三个文件中的内容仍然非常冗余,对于裸机开发,只需要保留IOMUXC引脚复用、PAD配置结构体及宏定义、GPIO等外设寄存器结构体和地址宏,其余内容(如CMSIS、SDK驱动、多芯片兼容代码、无关及缺失的头文件等)全部删除,由于改动的代码量较大,此处不详细展开。
二、程序编写与验证
1、启动配置文件编写
在Board_Drivers文件夹中新建文件夹“4_ledc_sdk”,然后将上一章的start.s文件拷贝至该文件夹中
2、外设配置文件编写
(1)在文件夹4_ledc_sdk中新建cc.h文件,里面存放一些SDK库文件需要使用到的数据类型别名,内容如下:
#ifndef __CC_H #define __CC_H #define __I volatile #define __O volatile #define __IO volatile typedef signed char int8_t; typedef signed short int int16_t; typedef signed int int32_t; typedef unsigned char uint8_t; typedef unsigned short int uint16_t; typedef unsigned int uint32_t; typedef unsigned long long uint64_t; typedef signed char s8; typedef signed short int s16; typedef signed int s32; typedef signed long long int s64; typedef unsigned char u8; typedef unsigned short int u16; typedef unsigned int u32; typedef unsigned long long int u64; #endif(2)将上一小节提到的3个SDK包中的文件拷贝到文件夹4_ledc_sdk中,并做裁剪(裁剪的具体内容这里不详细展开)。
(3)原本cc.h文件中的定义在标准库stdint.h文件中已有实现,但裸机工程在编译时带参数“-nostdlib”,不链接C标准库,所以需要另行定义,并在SDK文件中原本包含stdint.h的地方包含cc.h文件。
3、C语言点灯程序编写
(1)将上一章的main.c文件拷贝至该文件夹中,因为点灯的业务代码和LED外设初始化的代码与上一章在功能上基本等价,只是初始化寄存器所调用的接口有变化。
(2)修改main.c文件中的内容:
①包含的头文件需要替换为:
#include "fsl_common.h" #include "fsl_iomuxc.h" #include "MCIMX6Y2.h"②LED的初始化函数需要更改,使用SDK提供的函数和宏完成GPIO初始化:
/* * @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、初始化 GPIO, GPIO1_IO03 设置为输出 */ GPIO1->GDIR = 0X0000008; /* 4、设置 GPIO1_IO03 输出低电平,打开 LED0 */ GPIO1->DR &= ~(1 << 3); }(3)两个SDK初始化配置函数说明:
①IOMUXC_SetPinMux函数用于设置引脚的复用功能,其函数参数定义如下所示(按定义顺序说明)。
参数名 | 用途 |
muxRegister | IO引脚MUX寄存器地址 |
muxMode | IO复用值,也就是ALT值,决定该引脚复用何种功能 |
inputRegister | 外设输入IO选择寄存器地址(IO复用为某个功能时可能需要设置外设多路输入IO选择寄存器,如串口RX功能,需要选择数据输入源) |
inputDaisy | 外设输入IO选择寄存器配置值(不配置或者是配置为输出引脚,则写0) |
configRegister | 未使用参数 |
inputOnfield | IO软件输入使能标志 |
②IOMUXC_SetPinConfig函数用于设置引脚的电气属性。
参数名 | 用途 |
muxRegister | 未使用参数 |
muxMode | 未使用参数 |
inputRegister | 未使用参数 |
inputDaisy | 未使用参数 |
configRegister | IO引脚PAD寄存器地址 |
configValue | IO引脚PAD寄存器配置值 |
③这两个函数都有6个函数参数,但SDK提供的宏定义已经将IO引脚复用寄存器地址、复用值、外设输入IO寄存器地址、外设输入IO寄存器配置值、IO配置寄存器地址这5个参数集成在一起了。
[1]对上层来说,使用IOMUXC_SetPinMux函数,只需要指定想要配置的引脚功能和引脚的IO软件输入使能与否,SDK就能精确匹配要操作的MUX寄存器的地址,并将配置值写入。
[2]对上层来说,使用IOMUXC_SetPinConfig函数,只需要指定想要配置的引脚功能和要写入寄存器的值,SDK就能精确匹配要操作的PAD寄存器的地址,并将配置值写入。
4、Makefile文件与链接脚本编写
(1)由于本章例程的架构与上一章类似,故可直接复用上一章的Makefile,将其复制到本工程的根目录下即可,不过之前编写的Makefile通用性较差,如果有些变量产生变化,就需要改很多处地方,非常麻烦,对此可以进行优化,如下所示。
# 如果外部没有定义,才赋值(方便命令行覆盖:make CROSS_COMPILE=xxx) CROSS_COMPILE ?= arm-linux-gnueabihf- NAME ?= ledc CC := $(CROSS_COMPILE)gcc LD := $(CROSS_COMPILE)ld OBJCOPY := $(CROSS_COMPILE)objcopy OBJDUMP := $(CROSS_COMPILE)objdump # 需要编译的目标文件列表 OBJS := start.o main.o $(NAME).bin: $(OBJS) # 使用链接脚本 imx6ul.lds,链接输出 elf $(LD) -T imx6ul.lds -o $(NAME).elf $^ # 从 elf 提取纯二进制 bin;-S:去掉重定位、符号信息 $(OBJCOPY) -O binary -S $(NAME).elf $@ # 反汇编,生成 dis 汇编查看文件 $(OBJDUMP) -D -m arm $(NAME).elf > $(NAME).dis %.o: %.s $(CC) -Wall -nostdlib -c -O2 -o $@ $< %.o: %.S $(CC) -Wall -nostdlib -c -O2 -o $@ $< %.o: %.c $(CC) -Wall -nostdlib -c -O2 -o $@ $< .PHONY: clean clean: rm -rf *.o $(NAME).bin $(NAME).elf $(NAME).dis(2)除了Makefile以外,链接脚本也可直接复用,将上一章的imx6u.lds复制到本工程的根目录下即可。
5、程序烧写验证
(1)将imxdownload拷贝到工程的根目录下,也就是和ledc.bin处于同一个文件夹下,并赋予其可执行权限。
(2)将SD卡接入虚拟机,然后在当前目录运行命令“./imxdownload ledc.bin /dev/sdb”即可将固件刷入SD卡(设备名需要核对,与/dev下的设备名一致),然后在开发板上验证即可。