linux(第十四期)--官方 SDK 移植实验-- Ubuntu20.04

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档

文章目录

一、前言

二、硬件原理

三、程序编写

[3.1 SDK文件移植](#3.1 SDK文件移植)

[3.2 创建cc.h文件](#3.2 创建cc.h文件)

[3.3、 编写实验代码](#3.3、 编写实验代码)

编译下载


一、前言

在上一章中,我们参考 ST 官方为 STM32 编写的stm32f10x.h,自行实现了 I.MX6U 的寄存器定义文件。不过这种手动编写的方式既耗时费力、缺乏实际意义,还容易出现错误。好在 NXP 官方已为 I.MX6ULL 提供了 SDK 包,其中已经封装好了完善的寄存器定义文件,我们可以直接移植这些文件来简化开发。需要说明的是,尽管该 SDK 包是针对 I.MX6ULL 开发的,I.MX6UL 同样可以兼容使用。本章将详细讲解如何移植 SDK 包中的核心文件,助力后续的开发工作。


二、硬件原理

本次实验还是实验led灯的闪烁。

三、程序编写

首先下载I.MX6ULL 的 SDK 包,从NXP官方下载

SDK包文件如下:

我们主要需要的是其中与寄存器定义相关的文件,需要如下文件:

3.1 SDK文件移植

使用 VSCode 新建工程,将 fsl_common.h、fsl_iomuxc.h 和 MCIMX6Y2.h 这三个文件拷贝

到工程中

3.2 创建cc.h文件

新建一个名为 cc.h 的头文件, cc.h 里面存放一些 SDK 库文件需要使用到的数据类型,在
cc.h 里面输入如下代码:

复制代码
#ifndef __CC_H
#define __CC_H

#define __I      volatile
#define __O     volatile 
#define __IO    volatile

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 signed long long            s64;
typedef unsigned char               u8;
typedef unsigned short              u16;
typedef unsigned int                u32;
typedef unsigned long long          u64;



#endif 

在 cc.h 文件中我们定义了很多的数据类型,因为有些第三方库会用到这些变量类型。

3.3、 编写实验代码

新建 start.S 和 main.c 这两个文件, start.S 文件的内容和之前led实验是一样,直接复制过来就可以
最终的文件目录如下:

在main.c中输入如下代码:

复制代码
/**************************************************************
Copyright © zuozhongkai Co., Ltd. 1998-2019. All rights reserved.
文件名	: 	 main.c
描述	   : I.MX6U开发板裸机实验2 C语言点灯
		 使用C语言来点亮开发板上的LED灯,学习和掌握如何用C语言来
		 完成对I.MX6U处理器的GPIO初始化和控制。
其他	   : 无
**************************************************************/
#include "fsl_iomuxc.h"
#include "fsl_common.h"
#include "MCIMX6Y2.h"
/*
 * @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;
}

/*
 * @description	: 初始化LED对应的GPIO
 * @param 		: 无
 * @return 		: 无
 */
void led_init(void)
{
	
	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 |= (1 << 3);	
	
	/* 4、设置GPIO1_IO03输出低电平,打开LED0 */
	GPIO1->DR &= ~(1 << 3);		
}

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

}

/*
 * @description	: 关闭LED灯
 * @param 		: 无
 * @return 		: 无
 */
void led_off(void)
{
	/*    
	 * 将GPIO1_DR的bit3置1
	 */
	GPIO1->DR |= (1<<3);
}

/*
 * @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);
	}
}

/*
 * @description	: mian函数
 * @param 	    : 无
 * @return 		: 无
 */
int main(void)
{
	clk_enable();		/* 使能所有的时钟		 	*/
	led_init();			/* 初始化led 			*/

	while(1)			/* 死循环 				*/
	{	
		led_off();		/* 关闭LED   			*/
		delay(500);		/* 延时大约500ms 		*/

		led_on();		/* 打开LED		 	*/
		delay(500);		/* 延时大约500ms 		*/
	}

	return 0;
}

和之前的一样,main.c 有7个函数,这7个函数的含义都一样,只是本例程我们使用的是

移植好的 NXP 官方 SDK 里面的寄存器定义。main.c 文件的这 7 个函数的内容都很简单,前面

都讲过很多次了,重点是看以下两行代码如下:

复制代码
IOMUXC_SetPinMux(IOMUXC_GPIO1_IO03_GPIO1_IO03, 0);
IOMUXC_SetPinConfig(IOMUXC_GPIO1_IO03_GPIO1_IO03, 0X10B0);

注意:
IOMUXC_SetPinMux 是用来设置 IO 复 用 功 能 的,

最 终 肯 定 设 置 的 是 寄 存 器"IOMUXC_SW_MUX_CTL_PAD_XX"。
IOMUXC_SetPinConfig 设置的是 IO 的上下拉、 速度等的,
也就是寄存器"IOMUXC_SW_ PAD CTL_PAD XX "。
所以上面两个函数实际就是之前的:

复制代码
IOMUX_SW_MUX->GPIO1_IO03 = 0X5;
IOMUX_SW_PAD->GPIO1_IO03 = 0X10B0;

函数 IOMUXC_SetPinMux 在文件 fsl_iomuxc.h 中定义,他有6个参数:

  • muxRegister :IO 复用寄存器地址,例:GPIO1_IO03 的复用寄存器SW_MUX_CTL_PAD_GPIO1_IO03地址为 0X020E0068。
  • muxMode:IO 复用值(对应 ALT0~ALT8,数字 0~8),例:GPIO1_IO03 设为 GPIO 功能时,该参数为 5。
  • inputRegister :外设输入 IO 选择寄存器地址,例:GPIO1_IO03 复用为 UART1_RX 时,需配置UART1_RX_DATA_SELECT_INPUT(地址 0X020E0624)。
  • inputDaisyinputRegister的配置值,例:GPIO1_IO03 作为 UART1_RX 引脚时,该参数为 1。
  • configRegister :未使用,由IOMUXC_SetPinConfig函数使用。
  • inputOnfield:IO 软件输入使能(对应复用寄存器的 SION 位,bit4),例:GPIO1_IO03 使能软件输入时设为 1,否则为 0。

所以这个IOMUXC_SetPinMux 的函数体很简单,就是根据参数对寄存器 muxRegister 和 inputRegister进行赋值。而下行代码的作用就是将GPIO1_IO03 的复用功能设置为 GPIO

复制代码
  IOMUXC_SetPinMux(IOMUXC_GPIO1_IO03_GPIO1_IO03, 0);

那为啥这里只有两个参数呢?
*

复制代码
  ​​​​​​​IOMUXC_GPIO1_IO03_GPIO1_IO03

NXP 的 SDK 库将一个 IO 的所有复用功能都定义了一个宏,比如GPIO1_IO03 就有如下 9 个宏定义:
*

复制代码
  IOMUXC_GPIO1_IO03_I2C1_SDA
  IOMUXC_GPIO1_IO03_GPT1_COMPARE3
  IOMUXC_GPIO1_IO03_USB_OTG2_OC
  IOMUXC_GPIO1_IO03_USDHC1_CD_B
  IOMUXC_GPIO1_IO03_GPIO1_IO03
  IOMUXC_GPIO1_IO03_CCM_DI0_EXT_CLK
  IOMUXC_GPIO1_IO03_SRC_TESTER_ACK
  IOMUXC_GPIO1_IO03_UART1_RX
  IOMUXC_GPIO1_IO03_UART1_TX
  • 上面 9 个宏定义分别对应着 GPIO1_IO03 的九种复用功能,比如复用为 GPIO 的宏定义就
    是IOMUXC_GPIO1_IO03_GPIO1_IO03,定义如下

    #define IOMUXC_GPIO1_IO03_GPIO1_IO03 0x020E0068U, 0x5U, 0x00000000U, 0x0U, 0x020E02F4U

带入到之前哪个函数:

复制代码
IOMUXC_SetPinMux(0x020E0068U, 0x5U, 0x00000000U, 0x0U, 0x020E02F4U, 0);

这样就与6个参数对应起来了。
函数 IOMUXC_SetPinConfig同样也有6个参数,其中前五个参数和函数 IOMUXC_SetPinMux 一样

复制代码
static inline void IOMUXC_SetPinConfig(uint32_t muxRegister,
                                       uint32_t muxMode,
                                       uint32_t inputRegister,
                                       uint32_t inputDaisy,
                                       uint32_t configRegister,
                                       uint32_t configValue)

但是此函数只使用了参数 configRegister 和 configValue , cofigRegister 参数是 IO 配置寄存
器地址,参数 configValue 就是要写入到寄存器 configRegister 的值

复制代码
IOMUXC_SetPinConfig(IOMUXC_GPIO1_IO03_GPIO1_IO03, 0X10B0);

所以上面函数就是将寄存器 0x020E02F4 的值设置为 0X10B0

编译下载

复制代码
chmod 777 imxdownload  //给予imxdownload可执行权限,一次即可
./imxdownload ledc.bin /dev/sdb
相关推荐
范纹杉想快点毕业2 小时前
欧几里得算法与扩展欧几里得算法,C语言编程实现(零基础全解析)
运维·c语言·单片机·嵌入式硬件·算法
云qq2 小时前
x86操作系统23——进程相关系统调用
linux·c语言·汇编·ubuntu
小猪佩奇TONY2 小时前
Linux 内核学习(16) --- linux x86-64 虚拟地址空间和区域
linux·运维·学习
L1624762 小时前
Docker 安装部署全流程使用指南(Linux 通用版)
linux·docker·容器
cngm1102 小时前
记录两个网卡同时访问两个网段的调试方法route print
服务器·网络·windows
杰克崔2 小时前
kprobe及kretprobe的基于例子来调试分析其原理
linux·运维·服务器·车载系统
小北方城市网2 小时前
微服务架构设计实战指南:从拆分到落地,构建高可用分布式系统
java·运维·数据库·分布式·python·微服务
开开心心_Every2 小时前
离线黑白照片上色工具:操作简单效果逼真
java·服务器·前端·学习·edge·c#·powerpoint
咕噜签名-铁蛋2 小时前
给服务器穿件“智能防弹衣“
服务器