8 9 固件库

news2025/1/22 19:45:03

文章目录

  • 8.1 什么是固件库
  • 8.2 什么时候使用
  • 8.3 封装注意点
    • 8.3.1 fsl
  • 8.4 GPIO库函数定义
    • 8.4.1 初始化结构体 gpio_pin_config_t
    • 8.4.2 定义引脚模式的枚举类型
    • 8.4.3 初始化结构体
    • 8.4.4 定义中断配置函数
    • 8.4.5 定义GPIO初始化函数
    • 8.4.6 使用函数控制GPIO
    • 8.4.7 定义 IOMUXC 外设控制的寄存器位
    • 8.4.8 IOMUXC_SetPinMux ()
    • 8.4.9 IOMUXC_SetPinConfig ()
  • 8.5 使用函数控制LED
  • 9 Nxp的固件库
    • 9.1 获取 SDK 及固件库
    • 9.2 SDK包内容
      • 9.2.1 boards 文件夹
      • 9.2.2 CMSIS 文件夹
        • 9.2.2.1 CMSISDriver 目录:片上外设相关的驱动原型
        • 9.2.2.2 CMSISInclude 目录:内核相关头文件
        • 9.2.2.3 DSP 库
      • 9.2.3 devices 文件夹
      • 9.2.4 middleware 文件夹:

8.1 什么是固件库

固件库是指“RT1052 函数库”,是由 NXP 公司针对 RT1052 提供的函数接口,即
API (Application Program Interface)。

  • 开发者可调用这些函数接口来配置 RT1052 的寄存器,使开发人员得以脱离最底层的寄存器操作

8.2 什么时候使用

绝大部分时候,我们愿意牺牲一点 CPU 资源,选择库开发

一般只有在对代码运行时间要求极苛刻的地方,才用直接配置寄存器的方式代替,如频繁调用的中断服务函数。

8.3 封装注意点

6 /* volatile 表示易变的变量,防止编译器优化, */
7 #define __IO volatile /* 可读写,一般用于定义有可读写权限的寄存器 */
8 #define __I volatile const /* 只读,一般用于定义只读权限的寄存器 */

/* 使用更简短直观的方式来定义无符号 32 、 16 、 8 位变量 */
11 typedef unsigned int uint32_t;
12 typedef unsigned short uint16_t;
13 typedef unsigned char uint8_t;

15 /* GPIO 寄存器结构体 */
16 typedef struct {
17 __IO uint32_t DR; /* DR 数据寄存器, 地址偏移 : 0x0 */
18 __IO uint32_t GDIR; /* GDIR 方向寄存器, 地址偏移 : 0x4 */
19 __I uint32_t PSR; /* PSR 状态寄存器, 地址偏移 : 0x8 */
20 __IO uint32_t ICR1; /* ICR1 中断配置寄存器 1, 地址偏移 : 0xC */
21 __IO uint32_t ICR2; /* ICR2 中断配置寄存器 2, 地址偏移 : 0x10 */
22 __IO uint32_t IMR; /* IMR 中断掩码寄存器 , 地址偏移 : 0x14 */
23 __IO uint32_t ISR; /* ISR 中断状态寄存器 , 地址偏移 : 0x18 */
24 __IO uint32_t EDGE_SEL; /* EDGE_SEL 边沿选择寄存器, 地址偏移 : 0x1C */
25 } GPIO_Type;

“__IO”代表了 C 语言中的关键字“volatile”,在 C 语言中该关键字用于修饰易变的变量,要求编译器不要优化
“__I”则代表“volatile const”在“__IO”的基础上增加不可修改的属性

寄存器很多时候是由外设或 RT1052 芯片状态修改的,也就是说即使 CPU 不执行代码修改这些变量,变量的值也有可能被外设修改、更新。

  • 所以每次使用这些变量的时候,我们都要求 CPU 去该变量的地址重新访问。
  • 若没有这个关键字修饰,在某些情况下,编译器认为没有代码修改该变量,就直接从 CPU 的某个缓存获取该变量值,这时可以加快执行速度,但该缓存中的是陈旧数据,与我们要求的寄存器最新状态可能会有出入。

8.3.1 fsl

文件名中的 fsl 大概是飞思卡尔半导体(freescale)的缩写,nxp 公司收购了 freescale,在固件库中它们使用 fsl 这个名字

8.4 GPIO库函数定义

8.4.1 初始化结构体 gpio_pin_config_t

1 /* GPIO 引脚配置结构体定义 */
2 typedef struct _gpio_pin_config {
3
4 /* 指定引脚的方向 */
5 uint8_t direction;
6
7 /* 设置一个默认的输出电平,在输入方向时本设置无效 */
8 uint8_t outputLogic;
9
10 /* 设置引脚的中断模式 */
11 uint8_t interruptMode;
12
13 } gpio_pin_config_t;

结构体中包含了初始化 GPIO 所需要的信息,包括引脚输入输出方向、默认输出电平以及中断模式。

然后把这个结构体作为“GPIO 初始化函数”的输入参数,该函数能根据这个变量值中的内容去配置寄存器,从而实现 GPIO 的初始化。

8.4.2 定义引脚模式的枚举类型

1 /* GPIO 方向枚举定义 */
2 typedef enum _gpio_pin_direction {
3 kGPIO_DigitalInput = 0U, /* 设置引脚为输入方向 */
4 kGPIO_DigitalOutput = 1U, /* 设置引脚为输出方向 */
5 } gpio_pin_direction_t;
6
7 /* GPIO 中断模式枚举定义 */
8 typedef enum _gpio_interrupt_mode {
9 kGPIO_NoIntmode = 0U, /* 设置引脚为通用 IO 功能(不使用中断) */
10 kGPIO_IntLowLevel = 1U, /* 设置引脚低电平引起中断 */
11 kGPIO_IntHighLevel = 2U, /* 设置引脚高电平引起中断 */
12 kGPIO_IntRisingEdge = 3U, /* 设置引脚上升沿引起中断 */
13 kGPIO_IntFallingEdge = 4U, /* 设置引脚下降沿引起中断 */
14 kGPIO_IntRisingOrFallingEdge = 5U, /* 设置引脚上升沿和下降沿都引脚中断 */
15 } gpio_interrupt_mode_t

“U”表示该数字是无符号类型,在这里其实不写也可以,是一种编程习惯。

8.4.3 初始化结构体

1 /* 定义 gpio_pin_config_t 类型的结构体变量 */
2 gpio_pin_config_t led_config;
3 /* 配置方向为输出模式 */
4 led_config.direction = kGPIO_DigitalOutput;
5 /* 配置默认输出高电平 */
6 led_config.outputLogic = 1;
7 /* 配置不使用中断 */
8 led_config.interruptMode = kGPIO_NoIntmode;

8.4.4 定义中断配置函数

GPIO 初始化中涉及到众多的中断配置寄存器,为此我们定义一个 GPIO_PinSetInterruptConfig 中断模式配置函数专门处理这些事情

/*
2 * 设置指定引脚的中断模式
3 * base: GPIO_Type 类型的指针,如 GPIO1 、 GPIO2 等宏
4 * pin: 要控制引脚的编号
5 * pininterruptMode: gpio_interrupt_mode_t 类型的指针
6 * 该结构体包含中断配置的信息
7 */
8 void GPIO_PinSetInterruptConfig(GPIO_Type* base, uint32_t pin,
9 gpio_interrupt_mode_t pinInterruptMode)
10 {
11 volatile uint32_t *icr;
12 uint32_t icrShift;
13
14 /* icrShift 初值为引脚号,后面用来定位引脚对应的寄存器配置位
15 * 如 pin0 的配置位为 bit0 、 bit1 , pin1 的配置位为 bit2 、 bit3
16 */
17 icrShift = pin;
18
19 /* 编号小于 16 的使用 ICR1 寄存器控制,其它在 ICR2 控制 */
20 if (pin < 16) {
21 /* icr 指针指向 ICR1 */
icr = &(base->ICR1);
23 } else {
24 /* icr 指针指向 ICR2 */
25 icr = &(base->ICR2);
26 /* 对应引脚配置位跟引脚号的关系要减 16
27 * 如 pin16 的配置位为 bit0 、 bit1 , pin17 的配置位为 bit2 、 bit3
28 */
29 icrShift -= 16;
30 }
31
32 /* 先对 EDGE_SEL 寄存器相应引脚的控制位清零,
33 因为 EDGE_SEL 非零的话 ICR 寄存器的配置无效,
34 引脚会被直接配置为双边沿模式 */
35 base->EDGE_SEL &= ~(1U << pin);
36
37 /* 根据中断模式配置寄存器 */
38 switch (pinInterruptMode) {
39 /* 高低电平或单边沿触发配置 ICR 寄存器 */
40 case (kGPIO_IntLowLevel):
41 /* 对应 ICR 寄存器位清零: 0b00 ,低电平触发 */
42 *icr &= ~(3U << (2 * icrShift));
43 break;
44 case (kGPIO_IntHighLevel):
45 /* 对应 ICR 寄存器位清零后赋值为 1 : 0b01 ,高电平触发 */
46 *icr = (*icr & (~(3U << (2 * icrShift)))) | (1U << (2 * icrShift));
47 break;
48 case (kGPIO_IntRisingEdge):
49 /* 对应 ICR 寄存器位清零后赋值为 2 : 0b10 ,上升沿触发 */
50 *icr = (*icr & (~(3U << (2 * icrShift)))) | (2U << (2 * icrShift));
51 break;
52 case (kGPIO_IntFallingEdge):
53 /* 对应 ICR 寄存器位赋值为 3 : 0b11 ,下降沿触发 */
54 *icr |= (3U << (2 * icrShift));
55 break;
56
57 /* 双边沿触发配置 EDGE_SEL 寄存器 */
58 case (kGPIO_IntRisingOrFallingEdge):
59 /* 对应 EDGE_SEL 寄存器位置 1 ,配置为双边沿触发 */
60 base->EDGE_SEL |= (1U << pin);
61 break;
62 default:
63 break;
64 }
65 }

《IMXRT1050RM》(参考手册)GPIO 章节中对这些寄存器进行了说明,以下是简要说明:

在这里插入图片描述
使用 GPIO 中断时

  • 使用中断控制寄存器 ICR1、ICR2 或中断双边沿选择寄存器EDGE_SEL 中选择触发中断的模式,分别有高电平、低电平、上升沿、下降沿以及双边沿触发模式
  • 选择好模式后控制中断屏蔽寄存器 IMR 使能中断。
  • 当 GPIO 引脚出现触发模式对应的电气状态时,在中断状态寄存器 ISR 可检测到中断事件标志。

pinInterruptMode 就是前面定义的中断模式枚举类型,用来指定要选择高电平、低电平、上升沿、下降沿还是双边沿触发模式。

  • 函数体中使用 icr 及 icrShift 两个变量用于运算缓冲
  • 因为 ICR1 寄存器用于配置编号0-15 引脚,ICR2 寄存器用于配置编号 16~31 的引脚
    • 对于 0~15 号引脚,icr 指向 ICR1 寄存器
    • 对于 16~31 号引脚,icr 指向 ICR2 寄存器

ICR1 与 ICR2 寄存器的说明:
在这里插入图片描述
35 行,它对引脚在 EDGE_SEL 寄存器的配置位进行清零,以确保后续对ICR 寄存器的配置能生效。

  • 引脚在 EDGE_SEL 寄存器中的配置位为 1 时,无论引脚在 ICR1 或 ICR2 寄存器中配置成什么模式都会被覆盖成 EDGE_SEL 寄存器配置的双边沿模式触发。

第 38~55 行,根据输入的枚举变量 pinInterruptMode 参数使用 switch 分出不同的分支给 ICR寄存器赋予对应模式的控制值。

第 57~61 行,这是 pinInterruptMode 变量等于 kGPIO_IntRisingOrFallingEdge 的处理分支,即输入要求配置为双边沿触发,所以在处理的时候是对 EDGE_SEL 寄存器进行赋值的。

这个函数并没有到中断屏蔽寄存器 IMR 进行配置,要使中断开始工作,需要对这个 IMR 寄存器引脚对应的位置 1 进行使能

8.4.5 定义GPIO初始化函数

定义 GPIO 初始化函数

9 void GPIO_PinInit(GPIO_Type* base, uint32_t pin,
10 const gpio_pin_config_t* Config)
11 {
12 /* 对相应引脚 IMR 寄存器的控制位清零,先关闭中断 */
13 base->IMR &= ~(1U << pin);
14
15 /* 配置 GPIO 引脚的方向 */
16 if (Config->direction == kGPIO_DigitalInput) {
17 /* 输入模式 */
18 base->GDIR &= ~(1U << pin);
19 } else {
20 /* 输出模式 */
21 /* 先对 DR 寄存器赋值默认电平 */
22 GPIO_PinWrite(base, pin, Config->outputLogic);
23 /* 配置为输出模式 */
24 base->GDIR |= (1U << pin);
25 }
26
27 /* 配置 GPIO 引脚的中断模式 */
28 GPIO_PinSetInterruptConfig(base, pin, Config->interruptMode);
29 }

这个函数有 base、pin 以及 Config 三个输入参数,分别是 GPIO 外设指针、引脚编号和 GPIO 初始化结构体指针。分别用来指定要初始化的 GPIO 端口、引脚号和引脚的工作模式。

该函数的实现说明:

  • 对引脚在中断屏蔽寄存器 IMR 中的配置位清零,即关闭中断。

  • 根据输入参数初始化结构体 Config 中的 direction 成员的值,分成输入方向配置分支和输出方向配置分支。

    • 要设置为输入方向时对方向寄存器 GDIR 对应的位清零。
    • 要设置为输出方向时先调用GPIO_PinWrite 函数根据初始化结构体 Config 中的outputLogic成员设置引脚默认要输出高电平还是低电平,设置好后再对方向寄存器GDIR对应的位置 1,这样的配置顺序能保证引脚初始化成功后立即输出 outputLogic 表示的电平值。
  • 调用前面讲解的 GPIO_PinSetInterruptConfig 中断模式配置函数,该函数接收初始化结构体Config 中 interruptMode 成员的值,根据它配置中断模式。

8.4.6 使用函数控制GPIO

4 int main(void)
5 {
6 /* 使用 GPIO 初始化结构体定义一个变量用于配置 GPIO */
7 gpio_pin_config_t led_config;
8 /* 开启 GPIO1 端口的时钟 */
9
10 /* 清空控制 GPIO1 端口时钟的 bit26 、 bit27 */
11
12 CCM_CCGR1 &= ~(unsigned int)(3<<26);
13
14 /* 把 bit26 、 bit27 设置为 0b01 ,即开启 GPIO1 时钟 */
15 CCM_CCGR1 |= (unsigned int)(1<<26);
16
17 /* 设置 MUX 寄存器为 0x05 ,表示把引脚用于普通 GPIO */
18 IOMUXC_MUX_GPIO_AD_B0_09 = (unsigned int)0x05;
19
20 /* 设置 PAD 寄存器控制引脚的属性 */
21 IOMUXC_PAD_GPIO_AD_B0_09 = (unsigned int)0x000B0;
48 led_config.direction = kGPIO_DigitalOutput; // 输出模式
49 led_config.outputLogic = 1; // 默认高电平
50 led_config.interruptMode = kGPIO_NoIntmode; // 不使用中断
51
52 /* 使用 led_config 初始化 GPIO1_IO09*/
53 GPIO_PinInit(GPIO1,9,&led_config);
54
55 /* 控制 GPIO1_IO09 为低电平,点亮 LED 灯 */
56 GPIO_PinWrite(GPIO1,9,0);

8.4.7 定义 IOMUXC 外设控制的寄存器位

1 /* MUX 寄存器各个配置域的掩码、偏移及设置宏 */
2 /* MUX_MODE 配置 */
3 #define IOMUXC_SW_MUX_CTL_PAD_MUX_MODE_MASK (0x7U)
4 #define IOMUXC_SW_MUX_CTL_PAD_MUX_MODE_SHIFT (0U)
5 #define IOMUXC_SW_MUX_CTL_PAD_MUX_MODE(x) \
6 (((uint32_t)(((uint32_t)(x)) << IOMUXC_SW_MUX_CTL_PAD_MUX_MODE_SHIFT))\
7 & IOMUXC_SW_MUX_CTL_PAD_MUX_MODE_MASK)

IOMUXC_SW_MUX_CTL_PAD_MUX_MODE_MASK 表示是 MUX 寄存器中的 MUX_MODE 配置域的 MASK(掩码),所谓掩码是用位值 1 来表示配置域在寄存器中占据的位置,使用掩码可以方便后续的寄存器位运算。

5-7 行比较复杂,这几行代码实际是一个整体,它其实就是一个带参数的宏,我们把第 5-7 行和第 12~14 行的宏使用同功能的函数实现:

 1 //MUX_MODE 与 IOMUXC_SW_MUX_CTL_PAD_MUX_MODE(x) 功能等效的函数实现
2 uint32_t IOMUXC_SW_MUX_CTL_PAD_MUX_MODE(uint32_t x)
3 {
4 uint32_t x_shift;
5 uint32_t config;
6 /* 把配置值偏移到对应的寄存器位置 */
7 x_shift = (uint32_t)x << IOMUXC_SW_MUX_CTL_PAD_MUX_MODE_SHIFT;
8 /* 与掩码做 & 运算确保其它无关位均为 0 不受影响 */
9 config = (uint32_t)(x_shift & IOMUXC_SW_MUX_CTL_PAD_MUX_MODE_MASK);
10 /* 返回 config , config 中包含 MUX_MODE 位配置为 x, 其余位均为 0 的数值 */
11 return config;
12 }
13
14 //SION 与 IOMUXC_SW_MUX_CTL_PAD_SION(x) 功能等效的函数实现
15 uint32_t IOMUXC_SW_MUX_CTL_PAD_SION(uint32_t x)
16 {
17 uint32_t x_shift;
18 uint32_t config;
19 /* 把配置值偏移到对应的寄存器位置 */
20 x_shift = (uint32_t)x << IOMUXC_SW_MUX_CTL_PAD_SION_SHIFT;
21 /* 与掩码做 & 运算确保其它无关位均为 0 不受影响 */
22 config = (uint32_t)(x_shift & IOMUXC_SW_MUX_CTL_PAD_SION_MASK);
23 /* 返回 config , config 中包含 SION 位配置为 x, 其余位均为 0 的数值 */
24 return config;
25 }

根据输入参数 x 生成一个 32 位的数值,这个 32 位数中仅相关的配置域为 x,其余位为 0,各个配置域利用这样的函数(带参宏),使用“|”运算组合出一个最终要赋予给寄存器的值

1 /* 给 GPIO_AD_B0_09 的 MUX 寄存器赋值 */
2 /* 赋值结果为 MUX_MODE 配置域为 5 , SION 配置域为 1 */
3 IOMUXC_MUX_GPIO_AD_B0_09 = IOMUXC_SW_MUX_CTL_PAD_MUX_MODE(5)| IOMUXC_SW_MUX_CTL_PAD_SION(1);

在 NXP 的库函数代码中这些宏命名大体遵照这样的格式:寄存器类型名 _ 配置域名 _ 宏功能,如前面介绍的 IOMUXC_SW_MUX_CTL_PAD_MUX_MODE_MASK

  • IOMUXC_SW_MUX_CTL_PAD 表示它是 MUX 类型寄存器
  • MUX_MODE 表示这个宏用于控制 MUX_MODE 配置域
  • 宏的功能则是 MASK(掩码)。

8.4.8 IOMUXC_SetPinMux ()

此函数将IO复用为GPIO。

IOMUXC_SetPinMux(IOMUXC_GPIO1_IO03_GPIO1_IO03,0);  /* 复用为GPIO1_IO03 */
//参数说明
31 * muxRegister: 本引脚 MUX 寄存器的地址
32 * muxMode: 要配置的复用模式
33 * inputRegister: 可选的要设置的寄存器地址
34 * inputDaisy: 要给上述可选的寄存器赋予的值
35 * configRegister: 本引脚 PAD 属性配置寄存器的地址
36 * inputOnfield:SION 输入回路配置域的值, 10
37 */
38 static inline void IOMUXC_SetPinMux(uint32_t muxRegister,
39 uint32_t muxMode,
40 uint32_t inputRegister,
41 uint32_t inputDaisy,
42 uint32_t configRegister,
43 uint32_t inputOnfield)
44 {
45 /* 设置 MUX_MODE 及 SION */
46 *((volatile uint32_t *)muxRegister) =
47 IOMUXC_SW_MUX_CTL_PAD_MUX_MODE(muxMode) |
48 IOMUXC_SW_MUX_CTL_PAD_SION(inputOnfield);
49
50 /* 若可选寄存器非 0 ,则向它赋值 */
51 if (inputRegister) {
52 *((volatile uint32_t *)inputRegister) = inputDaisy;
53 }
54 }

第 47~49 行仍然是使用 muxMode 和 inputOnfield 生成寄存器的配置值然后赋予给 muxRegister 参数指定的地址中。
第 50~53 行是增加的代码,它判断增加的参数 inputRegister 非 0 后,就向 inputRegister 指向的寄存器赋予参数 inputDaisy 的值。

**

特别地,在这个函数中并没有使用 configRegister 参数

**

IOMUXC_GPIO1_IO03_GPIO1_IO03在iomuxc.h 中的宏定义

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

配置IOMUXC_SetPinMux()的6个参数为

uint32_t muxRegister,		0x020E0068U,
uint32_t muxMode,			0x5U, 
uint32_t inputRegister,		0x00000000U,
uint32_t inputDaisy, 		0x0U, 
uint32_t configRegister,	0x020E02F4U,
uint32_t inputOnfield 		0,

1.IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO03的寄存器地址为020E 0068h
2.0101 ALT5 — Select mux mode: ALT5 mux port: GPIO1_IO03 of instance: gpio1
配置为GPIO1,所以向020E0068h,中写入0x05
3.The select input register选择输入寄存器 选择信号线等,有的外设没有,没有就是0。
4.The input daisy 同上外设没有不设置。如果inputRegister不为0,就写入inputDaisy
5.The config register
6.寄存器bit4,SION位 Software input on field

8.4.9 IOMUXC_SetPinConfig ()

在main.c中的表现为

IOMUXC_SetPinConfig(IOMUXC_GPIO1_IO03_GPIO1_IO03,0X10B0);

IOMUXC_GPIO1_IO03_GPIO1_IO03在iomuxc.h 中的宏定义

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

由以上三段代码可知,配置IOMUXC_SetPinConfig () 的6个参数为

uint32_t muxRegister,		0x020E0068U,
uint32_t muxMode,			0x5U, 
uint32_t inputRegister,		0x00000000U,
uint32_t inputDaisy, 		0x0U, 
uint32_t configRegister,	0x020E02F4U,
uint32_t configValue		0x10B0,

1.IOMUXC_SW_PAD_CTL_PAD_GPIO1_IO03的寄存器地址为020E 0068h
2.0101 ALT5 — Select mux mode: ALT5 mux port: GPIO1_IO03 of instance: gpio1 配置为GPIO1,所以向020E0068h,中写入0x05
3.The select input register选择输入寄存器 选择信号线等,有的外设没有,没有就是0。
4.The input daisy 同上外设没有不设置。如果inputRegister不为0,就写入inputDaisy
5.The config register配置寄存器 IOMUXC_SW_PAD_CTL_PAD_GPIO1_IO03的地址为020E 02F4h P1793
6.The pin config value配置数值10B0h=0001 0000 1011 0000

源码:

static inline void IOMUXC_SetPinConfig(uint32_t muxRegister,
                                       uint32_t muxMode,
                                       uint32_t inputRegister,
                                       uint32_t inputDaisy,
                                       uint32_t configRegister,
                                       uint32_t configValue)
{
    if (configRegister)
    {
        *((volatile uint32_t *)configRegister) = configValue;
    }
}

这个函数在函数的主体,只是针对 configRegister 参数指定的寄存器赋予了 configValue 参数的值,完全没有使用前面 4 个参数,所以这 4 个参数也是为了与前面定义的宏对齐,配合使用。

  • configRegister 参数,用于指定 PAD 属性配置寄存器的地址。
  • configValue 参数,用于指定要给 PAD 属性配置寄存器赋予的值。
/* SRE 压摆率选择 */
2 #define SRE_0_SLOW_SLEW_RATE IOMUXC_SW_PAD_CTL_PAD_SRE(0)
3 #define SRE_1_FAST_SLEW_RATE IOMUXC_SW_PAD_CTL_PAD_SRE(1)
/* 驱动能力配置,配置阻值的大小 */
6 #define DSE_0_OUTPUT_DRIVER_DISABLED IOMUXC_SW_PAD_CTL_PAD_DSE(0)
7 /* R0 260 Ohm @ 3.3V, 150Ohm@1.8V, 240 Ohm for DDR */
8 #define DSE_1_R0_1 IOMUXC_SW_PAD_CTL_PAD_DSE(1)
9 /* R0/2 */
10 #define DSE_2_R0_2 IOMUXC_SW_PAD_CTL_PAD_DSE(2)
11 /* R0/3 */
12 #define DSE_3_R0_3 IOMUXC_SW_PAD_CTL_PAD_DSE(3)
13 /* R0/4 */
14 #define DSE_4_R0_4 IOMUXC_SW_PAD_CTL_PAD_DSE(4)
15 /* R0/5 */
16 #define DSE_5_R0_5 IOMUXC_SW_PAD_CTL_PAD_DSE(5)
17 /* R0/6 */
18 #define DSE_6_R0_6 IOMUXC_SW_PAD_CTL_PAD_DSE(6)
19 /* R0/7 */
20 #define DSE_7_R0_7 IOMUXC_SW_PAD_CTL_PAD_DSE(7)
21
22 /* SPEED 带宽配置 */
23 #define SPEED_0_LOW_50MHz IOMUXC_SW_PAD_CTL_PAD_SPEED(0)
24 #define SPEED_1_MEDIUM_100MHz IOMUXC_SW_PAD_CTL_PAD_SPEED(1)
25 #define SPEED_2_MEDIUM_100MHz IOMUXC_SW_PAD_CTL_PAD_SPEED(2)
26 #define SPEED_3_MAX_200MHz IOMUXC_SW_PAD_CTL_PAD_SPEED(3)
27
28 /* ODE 是否使用开漏模式 */
29 #define ODE_0_OPEN_DRAIN_DISABLED IOMUXC_SW_PAD_CTL_PAD_ODE(0)
30 #define ODE_1_OPEN_DRAIN_ENABLED IOMUXC_SW_PAD_CTL_PAD_ODE(1)
31
32 /* PKE 是否使能保持器或上下拉功能 */
33 #define PKE_0_PULL_KEEPER_DISABLED IOMUXC_SW_PAD_CTL_PAD_PKE(0)
34 #define PKE_1_PULL_KEEPER_ENABLED IOMUXC_SW_PAD_CTL_PAD_PKE(1)
36 /* PUE 选择使用保持器还是上下拉 */
37 #define PUE_0_KEEPER IOMUXC_SW_PAD_CTL_PAD_PUE(0)
38 #define PUE_1_PULL IOMUXC_SW_PAD_CTL_PAD_PUE(1)
39
40 /* PUS 上下拉配置 */
41 #define PUS_0_100K_OHM_PULL_DOWN IOMUXC_SW_PAD_CTL_PAD_PUS(0)
42 #define PUS_1_47K_OHM_PULL_UP IOMUXC_SW_PAD_CTL_PAD_PUS(1)
43 #define PUS_2_100K_OHM_PULL_UP IOMUXC_SW_PAD_CTL_PAD_PUS(2)
44 #define PUS_3_22K_OHM_PULL_UP IOMUXC_SW_PAD_CTL_PAD_PUS(3)
45
46 /* HYS 滞后功能 */
47 #define HYS_0_HYSTERESIS_DISABLED IOMUXC_SW_PAD_CTL_PAD_HYS(0)
48 #define HYS_1_HYSTERESIS_ENABLED IOMUXC_SW_PAD_CTL_PAD_HYS(1)

引脚属性设置:

1 /* 设置引脚属性 */
2 IOMUXC_SetPinConfig(IOMUXC_GPIO_AD_B0_09_GPIO1_IO09,
3 IOMUXC_SW_PAD_CTL_PAD_SRE(0)|
4 IOMUXC_SW_PAD_CTL_PAD_DSE(0x6)|
5 IOMUXC_SW_PAD_CTL_PAD_SPEED(0x2)|
6 IOMUXC_SW_PAD_CTL_PAD_ODE(0)|
7 IOMUXC_SW_PAD_CTL_PAD_PKE(0)|
8 IOMUXC_SW_PAD_CTL_PAD_PUE(0)|
9 IOMUXC_SW_PAD_CTL_PAD_PUS(0)|
10 IOMUXC_SW_PAD_CTL_PAD_HYS(0)
11 );
12
13/* bit0: SRE: 0b0 压摆率 : 慢压摆率
14 bit3~bit5: DSE: 0b110 驱动强度 : R0/6 (仅作为输出时有效 )
15 bit6~bit7: SPEED:0b10 带宽 : medium(100MHz)
16 bit11: ODE: 0b0 开漏配置 : 关闭
17 (开漏高阻态常用于总线配置,如 I2C )
18 bit12: PKE: 0b0 拉 / 保持器配置 : 关闭
19 bit13: PUE: 0b0 拉 / 保持器选择 : 关闭了上下拉及保持器,任意值无效
20 bit14~bit15: PUS: 0b00 上拉 / 下拉选择 : 关闭了上下拉及保持器,任意值无效
21 bit16: HYS: 0b0 滞回器配置 : 关闭
22 (仅输入时有效,施密特触发器,使能后可以过滤输入噪声)

8.5 使用函数控制LED

4 int main(void)
5 {
6 /* 使用 GPIO 初始化结构体定义一个变量用于配置 GPIO */
7 gpio_pin_config_t led_config;
* 开启 GPIO1 端口的时钟 */
10
11 /* 清空控制 GPIO1 端口时钟的 bit26 、 bit27 */
CCM_CCGR1 &= ~(unsigned int)(3<<26);
14
15 /* 把 bit26 、 bit27 设置为 0b01 ,即开启 GPIO1 时钟 */
16 CCM_CCGR1 |= (unsigned int)(1<<26);
17 /* 设置引脚为 MUX_MODE 及 SION
18 IOMUXC_GPIO_AD_B0_09_GPIO1_IO09 宏表示的五个参数:
19 0x401F80E0U, GPIO_AD_B0_09 的 MUX 寄存器的地址
20 0x5U, 选择 ATL5, 即 GPIO 功能
21 0, 可选的要同时配置的寄存器,为 0 表示不配置
22 0, 可选寄存器要赋予的值
23 0x401F82D0U GPIO_AD_B0_09 的 PAD 属性配置寄存器的地址
24 */
25 /* 设置复用为 GPIO1_IO09 功能
26 不使用 SION 功能
27 */
28 IOMUXC_SetPinMux(IOMUXC_GPIO_AD_B0_09_GPIO1_IO09,
29 0 );
30
31
32
33 /* 设置引脚属性 */
34 IOMUXC_SetPinConfig(IOMUXC_GPIO_AD_B0_09_GPIO1_IO09,
35 SRE_0_SLOW_SLEW_RATE|
36 DSE_6_R0_6|
37 SPEED_2_MEDIUM_100MHz|
38 ODE_0_OPEN_DRAIN_DISABLED|
39 PKE_0_PULL_KEEPER_DISABLED|
40 PUE_0_KEEPER_SELECTED|
41 PUS_0_100K_OHM_PULL_DOWN|
42 HYS_0_HYSTERESIS_DISABLED
43 );
45 led_config.direction = kGPIO_DigitalOutput; // 输出模式
46 led_config.outputLogic = 1; // 默认高电平
47 led_config.interruptMode = kGPIO_NoIntmode; // 不使用中断
48
49 /* 使用 led_config 初始化 GPIO1_IO09*/
50 GPIO_PinInit(GPIO1,9,&led_config);
51
52 /* 控制 GPIO1_IO09 为低电平,点亮 LED 灯 */
53 GPIO_PinWrite(GPIO1,9,0);
54
55 while (1);
56
57 }

9 Nxp的固件库

9.1 获取 SDK 及固件库

SDK(Software Development Kit)是 NXP 针对其官方评估版的软件开发包,可以在 NXP 的官网下载到。

  • SDK 中包含了各种程序范例,我们心心念念的固件库也包含在它里边。

官网下载:
访问 NXP 的 MCUXpresso 平台的链接
未登录的用户需要先登录 NXP 官网
在“SDK Dashboard”页面,点击“Select Development Board”

  • NXP 官方的 SDK 是针对 NXP 自己的 RT1050-EVK 开发板写的,所以在选择 Boards 的时候选择 NXP 官方的 RT1052 开发板,如果需要下载 NXP 其他
    型号的 MCU SDK 的时候就选择相应的 Boards
    在这里插入图片描述跳转到
    在这里插入图片描述进一步配置 SDK,比如开发主机系统:是 windows 还是 linux?所使用的 IDE 环境:是 KEIL、IAR 还是 GCC?是否需要第三方组件?都需要些啥组件等等
    这里我们直接选择“All toolchains”
    在这里插入图片描述点击“Add software component”按钮,确认需要增加的组件

可以根据自己的需要添加 SDK 中包含的组件,例如 CMSIS DSP 库、FatFs 文件系统、USB、lwIP 协议栈、emwin 图形界面库、FreeRTOS 实时系统等。有些库占用的空间比较大,且初学的时候不需要那么多的组件,我们在默认的 FatFs、USB Stack、lwIP 之上增加选项即可
在这里插入图片描述

配置好以后点击下面的“Request Build”
在这里插入图片描述SDK包下载
在这里插入图片描述

9.2 SDK包内容

在这里插入图片描述NXP 官方的 SDK 包一共有 7 个文件夹和 3 个其他文件
在这里插入图片描述

9.2.1 boards 文件夹

NXP 针对 RT1050 系列 MCU 写的一些例程
在这里插入图片描述NXP 提供的例程共有 8 种,有 USB 的、emiwn 的、基础例程的和RTOS 操作系统的等等。学习 RT1052 重点就是参考官方 SDK 包里面提供的这些例程。

  • cmsis_driver_examples 提供了一些按照 CMSIS 标准编写的驱动范例。CMSIS 是 ARM 提出的一个编程标准。
  • demo_apps 包含了一些应用范例,如串口打印“hello world”、使用 lwip 协议栈进行网络通讯等内容
    在这里插入图片描述
  • driver_example 包 含 了 RT1052 每 种 片 上 外 设 的 使 用 范 例, 非 常 详 细。
    在这里插入图片描述
    其中的“gpio”目录下又包含了使用 gpio 外设点亮 LED 灯和中断检测的例子
  • emwin_examples 包含了使用 emWin 图形软件库编写的图形界面示例,使用 emWin 可以编
    写出漂亮的界面程序。
  • project_template 包含了官方示例使用的一些必备文件,这些文件主要是针对官方评估板做
    了一些引脚定义、时钟配置等功能
    在这里插入图片描述
  • rtos_examples 包含了使用 FreeRTOS 实时操作系统的应用范例
    在这里插入图片描述
  • usb_examples 包含了各种 USB 程序示例
    在这里插入图片描述
    USB 设备种类繁多且驱动复杂

9.2.2 CMSIS 文件夹

CMSIS 全称: Cortex Microcontroller SoftwareInterface Standard,叫做 Cortex 微控制器软件接口标准。

为了解决不同的芯片厂商生产的 Cortex 微控制器软件的兼容性问题,ARM 与芯片厂商建立了 CMSIS 标准 (Cortex MicroController SoftwareInterface Standard)。
在这里插入图片描述此文件夹里面有一些重要的跟 Cortex-M 架构有关的头文件,在 include 文件夹里面,创建工程需要用到!此文件夹还有重要的 DSP 库,在 Lib 文件夹里面。

9.2.2.1 CMSISDriver 目录:片上外设相关的驱动原型

CMSISDriver 和 CMSISInclude 目录,它们分别对应 CMSI 核心层和设备外设函数层的内容。

  • CMSISDriver 目录,打开后发现它又包含两个文件夹
    在这里插入图片描述它们分别包含了一些关于片上外设的 C 源文件和 C 头文件,如 CAN、I2C、USART 等外设
    在这里插入图片描述在这两个目录下的 Driver_USART.c 和 Driver_USART.h 文件就是 ARM 官方基于 CMSIS 标准针对 USART 外设编写的原型文件

在源文件中,可以看到它定义了一些串口可能会使用的函数原型,如 - -

  • ARM_USART_Send 用来发送数据
  • ARM_USART_Receive 用来接收串口数据

这些函数都是空函数,,所以 ARM 也就是提供一个原型,具体代码还是由芯片厂商根据自己的外设来实现。

在头文件中,定义了一些使用串口外设时可能会产生的事件,例如串口外设发送完成后会在寄存器的标志位置 1,以告诉用户产生了该事件。

从这两个文件可以了解到,ARM 针对核外外设定义了 CMSIS 标准,相当于完成了软件架构师的工作

9.2.2.2 CMSISInclude 目录:内核相关头文件

在这里插入图片描述这就是 CMSIS 核心层,与前面只有架构的外设驱动不同,它们是由 ARM 公司提供的直接可用的内核驱动文件。

  • 包含了针对编译环境差异屏蔽的 core_compiler.h、cmsis_armcc.h 等文件
  • 包含了定义 CMSIS 版本号的文件 cmsis_version.h 文件
  • 以及针对不同内核寄存器定义的 core_cm3.h、core_cm4、core_cm7.h 等文件。

对于采用同样内核架构的芯片,芯片厂一般不会进行改动,由 ARM 根据自己内核定义出来的 CMSIS 核心层文件就是直接针对内核可用的文件。

  • 例如,分别由 NXP 和 ST 公司生产的 RT1052 和 STM32F7 芯片,它们都使用 ARM 的 Cortex-M7 内核,所以它们使用的内核驱动文件都是 ARM 针对 Cortex-M7 提供的 core_cm7.h 内核文件,是完全一样的
9.2.2.3 DSP 库

ARM 还针对自己的芯片提供了 DSP 处理的运算库函数,例如定点运算、傅利叶变换、PID 算法等。

  • 本教程讲解的内容不包含 DSP 库,有需要的话请按照前面《9.1 获取 SDK 及固件库》小节下载 SDK,且在组件中勾选“CMSIS DSP Library”项。这样下载得的 SDK 在“CMSISDSP Lib”目录下可找到 DSP 相关的文件。

9.2.3 devices 文件夹

此文件夹是 RT1052 相关的东西,包括 FSL 库。
在这里插入图片描述FSL 库就在 drivers 文件夹里面,我们创建库函数工程模板的时候就需要 FSL 库,还有一些其他的跟 RT1052 有关的.c 和.h 文件。

9.2.4 middleware 文件夹:

此文件夹包含了一些常用的第三方组件,比如 fatfs、lijpeg 库、usb、emwi 等。
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1279738.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

开源软件license介绍与检测

开源License介绍 通俗来讲&#xff0c;开源许可证就是一种允许软件使用者在一定条件内按照需要自由使用和修改软件及其源代码的的法律条款。借此条款&#xff0c;软件作者可以将这些权利许可给使用者&#xff0c;并告知使用限制。这些许可条款可以由个人、商业公司或非赢利组织…

Session 与 JWT 的对决:谁是身份验证的王者? (下)

&#x1f90d; 前端开发工程师&#xff08;主业&#xff09;、技术博主&#xff08;副业&#xff09;、已过CET6 &#x1f368; 阿珊和她的猫_CSDN个人主页 &#x1f560; 牛客高级专题作者、在牛客打造高质量专栏《前端面试必备》 &#x1f35a; 蓝桥云课签约作者、已在蓝桥云…

vue3请求代理proxy中pathRewrite失效

问题引入 在vue3配置请求代理proxy的时候pathRewrite失效。 有这样一个例子&#xff0c;作用是为了把所有以/api开头的请求代理到后端的路径和端口上&#xff0c;在vue.config.js配置文件中 设置了代理跨域和默认端口。但是重新运行之后发现端口是改了&#xff0c;但是路径仍然…

maven篇---第一篇

系列文章目录 文章目录 系列文章目录前言一、什么是maven?二、Maven能为我们解决什么问题?三、说说maven有什么优缺点?前言 前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站,这篇文章男女通用,看懂了就去分享给你的码…

CyclicBarrier实战应用——批量数据多线程协调异步处理(主线程执行事务回滚)

&#x1f60a; 作者&#xff1a; 一恍过去 &#x1f496; 主页&#xff1a; https://blog.csdn.net/zhuocailing3390 &#x1f38a; 社区&#xff1a; Java技术栈交流 &#x1f389; 主题&#xff1a; CCyclicBarrier实战应用——批量数据多线程协调异步处理(主线程执行事务…

关于抓取明文密码的探究

基础知识 SSP&#xff08;Security Support Provider&#xff09;是windows操作系统安全机制的提供者。简单的说&#xff0c;SSP就是DLL文件&#xff0c;主要用于windows操作系统的身份认证功能&#xff0c;例如NTLM、Kerberos、Negotiate、Secure Channel&#xff08;Schanne…

倒计时 1 天,2023 IoTDB 用户大会期待与您相见!

终于&#xff01;就在明天&#xff0c;2023 IoTDB 用户大会即将在北京与大家见面&#xff01; 这场筹备已久的盛会&#xff0c;汇集了超 20 位大咖嘉宾带来的精彩议题&#xff0c;届时来自美国国家工程院、清华大学软件学院的产业大拿&#xff0c;与能源电力、钢铁冶炼、城轨运…

数据结构:堆的实现思路

我们之前写过堆的实现代码&#xff1a;数据结构&#xff1a;堆的实现-CSDN博客 这篇文章我们了解一下堆到底是如何实现的 1.堆向下调整算法 现在我们给出一个数组&#xff0c;逻辑上看做一颗完全二叉树。我们通过从根节点开始的向下调整算法可以把它调整成一个小堆 向下调…

CyclicBarrier实战应用——批量数据多线程协调异步处理(子线程执行事务回滚)

&#x1f60a; 作者&#xff1a; 一恍过去 &#x1f496; 主页&#xff1a; https://blog.csdn.net/zhuocailing3390 &#x1f38a; 社区&#xff1a; Java技术栈交流 &#x1f389; 主题&#xff1a; CountDownLatch实战应用——批量数据多线程协调异步处理(子线程执行事务…

时序预测 | Python实现LSTM长短期记忆神经网络时间序列预测(多图,多指标)

时序预测 | Python实现LSTM长短期记忆神经网络时间序列预测(多图,多指标) 目录 时序预测 | Python实现LSTM长短期记忆神经网络时间序列预测(多图,多指标)预测效果基本介绍环境准备程序设计参考资料预测效果 基本介绍 LSTM是一种递归神经网络(RNN)的变体

JVM之基本概念(一)

(1) 基本概念&#xff1a; JVM 是可运行 Java 代码的假想计算机 &#xff0c;包括一套字节码指令集、一组寄存器、一个栈、一个垃圾回收&#xff0c;堆 和 一个存储方法域。JVM 是运行在操作系统之上的&#xff0c;它与硬件没有直接的交互。 (2) 运行过程&#xff1a; 我们都…

2 文本分类入门:TextCNN

论文链接&#xff1a;https://arxiv.org/pdf/1408.5882.pdf TextCNN 是一种用于文本分类的卷积神经网络模型。它在卷积神经网络的基础上进行了一些修改&#xff0c;以适应文本数据的特点。 TextCNN 的主要思想是使用一维卷积层来提取文本中的局部特征&#xff0c;并通过池化操…

使用Python免费调用通义千问大模型

Qwen-72b开源模型 模型的主要用途是预测或描述一个系统或现象的行为模式。它可以帮助人们更好地理解这个系统或现象&#xff0c;例如预测股市变化、天气预报、地震预警、交通流量等。模型也常用于设计和优化产品和工艺。在科学研究中&#xff0c;模型也是一种方法&#xff0c;用…

Stm32F401RCT6内部FLASH数据擦除读写方法

Stm32F401RCT6内部FLASH数据的分区和F103的已经不一样了&#xff0c;读写格式化的方法网上内容不多&#xff0c;自己摸索了一下&#xff0c;基本可以&#xff0c;还存在一个问题 读取&#xff1a; uint16_t f[5];uint8_t tx[10];f[0] *(volatile uint16_t*)0x08020000; //ST…

同旺科技 USB TO SPI / I2C --- 调试W5500_读写网关地址

所需设备&#xff1a; 内附链接 1、USB转SPI_I2C适配器(专业版); 首先&#xff0c;连接W5500模块与同旺科技USB TO SPI / I2C适配器&#xff0c;如下图&#xff1a; 这里的网关地址设置为192.168.1.1 先将网关地址写入寄存器&#xff0c;然后再读取出来&#xff1a;

【SpringBoot】讲清楚日志文件lombok

文章目录 前言一、日志是什么&#xff1f;二、⽇志怎么⽤&#xff1f;三.自定义打印日志3.1在程序中得到日志对象3.2使用日志打印对象 四.⽇志级别4.1日志级别有什么用4.2 ⽇志级别的分类与使⽤ 五.日志持久化六.lombok6.1添加lobok依赖注意&#xff1a;使⽤ Slf4j 注解&#x…

Linux命令与shell脚本编程大全【读书笔记 + 思考总结】

Linux命令与shell脚本编程大全 第 1 章 初识Linux shellLinux的组成及关系结构图是什么&#xff1f;Linux系统内核的作用是什么&#xff1f;内核的主要功能是什么&#xff1f;&#xff08;4点&#xff09;物理内存和虚拟内存是什么关系&#xff1f;内核如何实现虚拟内存&#x…

idea不需安装插件,自动生成mybatis-plus对应的实体类entity,带注解@TableName、@TableId、@TableField

目录 1、修改Generate poJOs.groovy文件 2、idea中连接数据库 3、生成entity代码 4、查看生成的实体类 1、修改Generate poJOs.groovy文件 在项目下方点击Scratches and Consoles→ Extensions→ Database Tools and SQL箭头→schema→ Generate POJOs.groovy 替换为以下文…

ssl下载根证书和中间证书

为了保证客户端和服务端通过HTTPS成功通信&#xff0c;您在安装SSL证书时&#xff0c;也需要安装根证书和中间证书。本文介绍如何获取根证书和中间证书。 使用说明 如果您的业务用户通过浏览器访问您的Web业务&#xff0c;则您无需关注根证书和中间证书&#xff0c;因为根证书…

如何学习 Spring ?学习 Spring 前要学习什么?

整理了一下Spring的核心概念BeanDefinitionBeanDefinition表示Bean定义&#xff0c;BeanDefinition中存在很多属性用来描述一个Bean的特点。比如&#xff1a;class&#xff0c;表示Bean类型scope&#xff0c;表示Bean作用域&#xff0c;单例或原型等lazyInit&#xff1a;表示Be…