硬件原理图分析
本章使用到的硬件资源和第六章一样,LED的原理。
SDK程序编写
我们在Ubuntu系统下建立文件夹“3_led_sdk”,然后将fsl_common.h、fsl_iomuxc.h和MCIMX6Y2.h这三个文件拷贝到“3_led_sdk”文件夹下面,这个三个文件需要做下删减修改,否则编译会报错,由于三个文件里面的代码都比较大,我这里就不详细的列出修改后的内容了。大家可以参考我们提供的裸机例程来修改这三个文件,修改完成后的工程目录如图 1所示:
然后我们在工程目录下创建“cc.h”头文件,里面存放SDK文件用到的数据类型,在“cc.h”里面输入下面的代码:
1 #ifndef __CC_H
2 #define __CC_H
3
4
5 /*
6 * 自定义一些数据类型供库文件使用
7 */
8 #define __I volatile
9 #define __O volatile
10 #define __IO volatile
11
12 typedef signed char int8_t;
13 typedef signed short int int16_t;
14 typedef signed int int32_t;
15 typedef unsigned char uint8_t;
16 typedef unsigned short int uint16_t;
17 typedef unsigned int uint32_t;
18 typedef unsigned long long uint64_t;
19 typedef signed char s8;
20 typedef signed short int s16;
21 typedef signed int s32;
22 typedef signed long long int s64;
23 typedef unsigned char u8;
24 typedef unsigned short int u16;
25 typedef unsigned int u32;
26 typedef unsigned long long int u64;
27
28
29 #endif
该文件主要是定义了很多数据类型。然后新建start.S和main.c两个文件,其中的start.S文件和上一章的内容一样,直接复制过来就可以,创建完成后的工程目录如图 2所示:
然后在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); /* 复用为GPIO1_IO0 */
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_IO
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 : mian函数
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 }
main.c文件中有7个函数,这7个函数的含义和上一章节的一样,只是本例程我们使用的是移植的NXP官方SDK里面的寄存器定义,main.c文件中的这7个函数都很简单,我们在前一章节也讲过了,这里我们重点看一下led_init函数中的31行和43行,代码如下:
IOMUXC_SetPinMux(IOMUXC_GPIO1_IO03_GPIO1_IO03,0);
IOMUXC_SetPinConfig(IOMUXC_GPIO1_IO03_GPIO1_IO03,0X10B0);
这里使用了SDK的两个函数IOMUXC_SetPinMux和IOMUXC_SetPinConfig,其中函数IOMUXC_SetPinMux是用来设置IO复用功能的,最终设置的是寄存器“IOMUXC_SW_MUX_CTL_PAD_XX”,IOMUXC_SetPinConfig函数是设置GPIO上下拉,输入输出,以及速度等,最终设置的寄存器 “IOMUXC_SW_PAD_CTL_PAD_XX”。
函数IOMUXC_SetPinMux在文件fsl_iomuxc.h中定义,源码如下:
static inline void IOMUXC_SetPinMux(uint32_t muxRegister,
uint32_t muxMode,
uint32_t inputRegister,
uint32_t inputDaisy,
uint32_t configRegister,
uint32_t inputOnfield)
{
*((volatile uint32_t *)muxRegister) =
IOMUXC_SW_MUX_CTL_PAD_MUX_MODE(muxMode) |
IOMUXC_SW_MUX_CTL_PAD_SION(inputOnfield);
if (inputRegister)
{
*((volatile uint32_t *)inputRegister) = IOMUXC_SELECT_INPUT_DAISY(inputDaisy);
}
}
函数IOMUXC_SetPinMux一共有6个参数,他们的说明如下:
muxRegister IO复用寄存器地址,比如GPIO1_IO03的IO复用寄存器SW_MUX_CTL_PAD_GPIO1_IO03地址是0x20e0068。
muxMode IO的复用值,IO配置成什么功能,比如要将GPIO1_IO03设置为GPIO功能的话此参数就要设置成5。
inputRegister外设输入IO选择寄存器地址,有些 IO 在设置为其他的复用功能以后还需要设置IO输入寄存器,比如GPIO1_IO03复用为UART1_RX的时候还需要设置寄存器UART1_RX_DATA_SELECT_INPUT,此寄存器地址为0X020E0624。
inputDaisy寄存器inputRegister的值,比如GPIO1_IO03要作为UART1_RX引脚的话此参数就是1。
configRegister未使用。
inputOnfield IO软件输入使能,比如GPIO1_IO03寄存器“SW_MUX_CTL_PAD_GPIO1_IO03“的 SION 位(bit4),如果使能GPIO1_IO03的软件输入功能,就要设置该参数为1,否则设置该参数为0。
IOMUXC_SetPinMux函数就是根据参数对寄存器muxRegister和inputRegister赋值,在main.c文件的31行使用此函数将GPIO1_IO03的IO设置成GPIO模式,代码如下:
IOMUXC_SetPinMux(IOMUXC_GPIO1_IO03_GPIO1_IO03, 0);
我们看到此函数有两个参数,按照刚才我们的分析,这个函数应该需要6个参数,我们进一步分析下传入的参数,我们看到第一个参数是IOMUXC_GPIO1_IO03_GPIO1_IO03,这应该是个宏定义,我们可以在文件“fsl_iomuxc.h”中找到他的定义,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的宏定义如下所示:
#define IOMUXC_GPIO1_IO03_GPIO1_IO03 0x020E0068U, 0x5U, 0x00000000U,
0x0U, 0x020E02F4U
我们可以看到该宏定义有五个参数,将这个宏定义带入到main.c文件的31行代码处,就是:
IOMUXC_SetPinMux (0x020E0068U, 0x5U, 0x00000000U, 0x0U, 0x020E02F4U, 0);
我们看到此时就与IOMUXC_SetPinMux函数定义的需要6个参数对应上了。如果我们将GPIO1_IO03复用成UART1_RX使用,我们使用如下的代码:
IOMUXC_SetPinMux(IOMUXC_GPIO1_IO03_UART1_RX, 0);
接着我们来看下函数IOMUXC_SetPinConfig,此函数的定义也是在“fsl_iomuxc.h”文件中,源码如下:
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;
}
}
此函数也是有6个参数,其中的前面5个和函数IOMUXC_SetPinMux一样通过宏定义来传入的,但是此函数只使用了参数configRegister和configV alue,cofigRegister参数是IO配置寄存器地址,比如GPIO1_IO03的IO配置寄存器IOMUXC_SW_PAD_CTL_PAD_GPIO1_IO03,地址为0x20e02f4,参数configValue 就是要写入到这个寄存器的数值。main.c文件的43行代码展开如下:
IOMUXC_SetPinConfig(0x020E0068U, 0x5U, 0x00000000U, 0x0U, 0x020E02F4U, 0X10B0);
根据函数IOMUXC_SetPinConfig的源码可以知道,上面代码就是将寄存器0x20e02f4的值设置为0x10b0。我们在以后可以使用这两个函数设置IO的复用功能以及IO的具体配置。
main.c我们就讲到这里,基本和上一章一样,只是我们用到了NXP提供的SDK里面的寄存器定义,以及IO配置相关的两个函数:IOMUXC_SetPinMux和IOMUXC_SetPinConfig。