NXP i.MX6 GPIO原理解析及引脚复用

本文详细介绍了在眺望电子TW-IMX6DL-EVM开发板上复用GPIO的过程,包括GPIO的操作原理、内核GPIO的配置以及中断控制。通过修改设备树配置,将CAN1总线引脚复用为GPIO,展示了引脚复用的步骤。同时,讨论了GPIO寄存器的配置,如数据寄存器、方向控制寄存器等,以及如何通过这些寄存器进行数据读写和中断设置。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

项目场景:

在眺望电子TW-IMX6DL-EVM开发板上复用GPIO引脚,并分享其原理。

编译环境及开发包: 主机:ubuntu18.04
交叉编译器:arm-linux-gnueabihf-gcc
开发板:TW-IMX6DL-EVM
Linux:Linux-4.1.15

注意:本文章的所有命令涉及到的路径均为眺望电子官方环境路径,需根据自身实际环境改变。本文所演示的平台来自于眺望电子 iMX6 ARM嵌入式平台,这是一个基于NXP iMX6 ARM处理器,支持单核/双核Cortex-A9的核心板。


解决方案:

1、GPIO操作原理

1.1 GPIO寄存器

每一个GPIO有8个寄存器需要配置,每一个GPIO寄存器功能如下:
GPIO_DR(Data Register)数据寄存器
  当GDIR设置为输出时,写DR的内容用来驱动GPIO的引脚,读DR的内容则返回存储在DR中的值。
  当GDIR设置为输入时,读DR返回给定IO 引脚的状态(PSR data),而不是DR data。
  
GPIO_GDIR(Data Direction Register)方向控制寄存器
  控制GPIO引脚的方向,1作为输出,0作为输入,寄存器中的每一位标识一个特定pad的方向。
  仅当相应的引脚被设置为GPIO,GDIR才起作用。
  
GPIO_PSR(pad status register)状态寄存器
  32-bit的只读寄存器。寄存器中的每一位都存储相应pad的值。
  
GPIO_ICR1,ICR2中断控制寄存器
   两个32-bit寄存器,寄存器中每两位控制一条中断线,ICR1控制中断0~15,ICR2控制中断16~31。其可设置的值为:

  • 00中断是低电平触发触发
  • 01中断是高电平触发
  • 10中断是上升沿触发
  • 11中断时下降沿触发

IMR(Interrupt Mask Register)中断屏蔽寄存器
  32-bit寄存器,每一位是相应中断线的屏蔽位, 0中断被屏蔽,1中断被使能。
  
GPIO_ ISR(Interrupt Status Register)中断状态寄存器
  32bit register,每一位用于指定对应的中断线是否有中断发生,当一个中断发生,这个寄存器中的相应位被设置为1。
  
GPIO_EDGE_SEL(Edge Select Register)
  32bit 寄存器,覆盖ICR寄存器的配置,选择edge 作为中断触发的条件。

1.2 IO功能操作

从引脚读取数据:
配置IOMUX选择GPIO模式;
配置GPIO的GPDR为输入;
从PSR寄存器读取数据(也可以从DR读取,此时会返回PSR内的值);

写数据到引脚:
配置IOMUX选择GPIO模式;
配置GPIO的GPDR为输出;
写值到Data Register(DR);

中断控制:
  除了通用的input/output功能外,GPIO内部的edge-detect逻辑反映一个被配置为input的pad是否发生了状态转换。

2.内核GPIO操作

设备树imx6qdl-sabresd.dtsi是TW-AC6-EVM设备的配置文件。其中GPIO的配置在pinctrl_hog:hoggrp标签下。
程序清单1 引脚复用为gpio功能
目录:arch/arm/boot/dts/imx6qdl-sabresd.dtsi

&iomuxc {
	pinctrl-names = "default";
	pinctrl-0 = <&pinctrl_hog>;

	imx6qdl-sabresd {
		pinctrl_hog: hoggrp {
			fsl,pins = <
			
				MX6QDL_PAD_NANDF_D0__GPIO2_IO00 0x80000000
				MX6QDL_PAD_NANDF_D1__GPIO2_IO01 0x80000000
				MX6QDL_PAD_NANDF_D2__GPIO2_IO02 0x80000000
				MX6QDL_PAD_NANDF_D3__GPIO2_IO03 0x80000000
				MX6QDL_PAD_GPIO_0__CCM_CLKO1    0x130b0
				MX6QDL_PAD_EIM_D22__GPIO3_IO22  0x80000000
				MX6QDL_PAD_EIM_D26__GPIO3_IO26 0x80000000
				MX6QDL_PAD_EIM_CS1__GPIO2_IO24 0x80000000
				MX6QDL_PAD_EIM_A25__GPIO5_IO02 0x80000000
				MX6QDL_PAD_EIM_D23__GPIO3_IO23 0x80000000
				MX6QDL_PAD_EIM_EB3__GPIO2_IO31 0x80000000
				MX6QDL_PAD_SD1_CMD__GPIO1_IO18 0x80000000
				MX6QDL_PAD_EIM_D16__GPIO3_IO16 0x80000000
				MX6QDL_PAD_SD3_RST__GPIO7_IO08	0x80000000
				MX6QDL_PAD_EIM_DA9__GPIO3_IO09 0x80000000
				MX6QDL_PAD_NANDF_CS0__GPIO6_IO11 0x80000000
				MX6QDL_PAD_NANDF_CS1__GPIO6_IO14 0x80000000
				MX6QDL_PAD_NANDF_CS2__GPIO6_IO15 0x80000000
				MX6QDL_PAD_NANDF_CS3__GPIO6_IO16 0x80000000
				
				MX6QDL_PAD_GPIO_4__GPIO1_IO04  0x80000000 
			>;
		};

程序清单1中的MX6QDL_PAD类型宏定义在arch/arm/boot/dts/imx6q-pinfunc.h文件中。

#define MX6QDL_PAD_EIM_D16__GPIO3_IO16              0x090 0x3a4 0x000 0x5 0x0

宏的各项含义为:

0x090        IOMUXC_SW_MUX_CTL_PAD_EIM_DATA16    mux寄存器偏移地址
0x3a4         IOMUXC_SW_PAD_CTL_PAD_EIM_DATA16    pad寄存器偏移地址
0x000                                            input寄存器偏移地址
0x5          ALT5 — Select signal GPIO3_IO16.    mux的模式
0x0                                              input类型
0x80000000   IOMUXC_SW_MUX_CTL_PAD_EIM_DATA16的值 设置为芯片默认

之后会在内核初始化时调用drivers/pinctrl/pinctrl-imx.c中imx_pinctrl_parse_groups函数读取fsl.pin属性值,并保存在lisk指针变量中,紧接着,分别读取list中的值mux_reg、conf_reg、input_reg的值并设置为mux_mode、config、input_val。更多关于设备树gpio的配置资料,请阅读Documentation/devicetree/bindings/pinctrl/fsl,imx-pinctrl.txt。

若是在文件系统中GPIO的value一直为0,则需要在arch/arm/boot/dts/imx6q-pinfunc.h文件中修改MX6QDL_PAD_EIM_D16__GPIO3_IO16的值,在上一节可知可以通过修改引脚功能寄存器IOMUXC_SW_MUX的SION位为1设置为软件强行配置模式。修改结果如下:

#define MX6QDL_PAD_EIM_D16__GPIO3_IO16 0x144 0x514 0x000 0x15 0x0

3.示例

3.1CAN1总线引脚复用为GPIO

打开“IMX6DQRM.pdf”数据手册的“26.2 External Signals”章节可以看到CAN总线I/O信号.

打开imx6qdl-sabresd.dtsi内核设备树文件,搜索can1可以得到如程序清单2的内容:
程序清单2 can1相关代码
目录:arch/arm/boot/dts/imx6qdl-sabresd.dtsi

&can1 {
	pinctrl-names = "default";
	pinctrl-0 = <&pinctrl_flexcan1>;
	status = "okay"; 
};
		pinctrl_flexcan1: flexcan1grp {
			fsl,pins = <
				MX6QDL_PAD_KEY_ROW2__FLEXCAN1_RX        0x17059
				MX6QDL_PAD_KEY_COL2__FLEXCAN1_TX		0x17059
			>;
		};

把程序清单2的内容中的两个引脚(即fsl,pins下的两个引脚)删除掉或者注释,以防重复使用该引脚。
注:引脚复用的原则是:在设备树中添加想要实现的该引脚的功能,需要把以前的复用功能去掉,无复用功能直接添加即可。

从程序清单2中可以得到can1读引脚使用图1的I/O信号是KEY_ROW2。KEY_ROW2是一个引脚独一无二的标志,由此判断设备树中的引脚是否为同一引脚。
  在imx6q-pinfunc.h头文件中搜索KEY_ROW2,可以得到如程序清单3内容:

程序清单3 KEY_ROW2引脚复用
目录:arch/arm/boot/dts/imx6q-pinfunc.h

#define MX6QDL_PAD_KEY_ROW2__ECSPI1_SS2             0x20c 0x5dc 0x808 0x0 0x1
#define MX6QDL_PAD_KEY_ROW2__ENET_TX_DATA2          0x20c 0x5dc 0x000 0x1 0x0
#define MX6QDL_PAD_KEY_ROW2__FLEXCAN1_RX            0x20c 0x5dc 0x7e4 0x2 0x0
#define MX6QDL_PAD_KEY_ROW2__KEY_ROW2               0x20c 0x5dc 0x000 0x3 0x0
#define MX6QDL_PAD_KEY_ROW2__SD2_VSELECT            0x20c 0x5dc 0x000 0x4 0x0
#define MX6QDL_PAD_KEY_ROW2__GPIO4_IO11             0x20c 0x5dc 0x000 0x5 0x0
#define MX6QDL_PAD_KEY_ROW2__HDMI_TX_CEC_LINE       0x20c 0x5dc 0x88c 0x6 0x1

可以看到引脚KEY_ROW2除了可以复用FLEXCAN1_RX还可以复用为GPIO4_IO11功能。一般可以从引脚的命名后缀可以看出该引脚的作用,如MX6QDL_PAD_KEY_ROW2__FLEXCAN1_RX该引脚复用为can读引脚,MX6QDL_PAD_KEY_ROW2__GPIO4_IO11该引脚复用为GPIO。
  在imx6qdl-sabresd.dtsi设备树文件的pinctrl_hog: hoggrp标签下添加GPIO引脚复用:
程序清单4 KEY_ROW2引脚复用成GPIO
目录:arch/arm/boot/dts/imx6qdl-sabresd.dtsi

&iomuxc {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_hog>;

imx6qdl-sabresd {	
pinctrl_hog: hoggrp {
fsl,pins = <
...
MX6QDL_PAD_KEY_ROW2__GPIO4_IO11 0x80000000 /* 引脚KEY_ROW2复用为GPIO4_IO11 */
>;
}; 
...
};

复用成gpio,后面的config值默认是0x80000000,为快速配置,如果复用成其它功能相关的值可以参考设备树中默认配置的值,如串口uart配置的值为0x1b0b1

参考资源链接:[NXP i.MX6ULL引脚配置工具PINS-TOOL-IMX详解](https://wenku.csdn.net/doc/6452318bea0840391e739170?utm_source=wenku_answer2doc_content) 首先,为了深入理解如何利用PINS-TOOL-IMX为i.MX6ULL处理器进行引脚配置,我推荐查看《NXP i.MX6ULL引脚配置工具PINS-TOOL-IMX详解》。这本书将为你提供全面的工具使用指导和高级配置技巧。 在开始之前,请确保你的开发环境已经安装了最新版本的PINS-TOOL-IMX,并且安装了适用于i.MX6ULL处理器的设备树源代码。接下来,我们可以通过以下步骤进行引脚配置和代码生成: 1. 打开PINS-TOOL-IMX软件,选择i.MX6ULL作为目标处理器。 2. 在软件界面中,选择你想要配置引脚,并设置相应的电气属性,比如多路复用功能、输入输出模式、上拉/下拉电阻等。 3. 根据你的应用需求,配置其他相关的引脚属性,比如速率和驱动电流。 4. 当所有引脚配置完成后,点击工具中的生成代码按钮,选择C语言代码作为输出格式。 5. 生成的C语言代码会包含必要的宏定义和函数,用于初始化和操作引脚。以下是一个生成代码的示例片段: ```c #define GPIO1_IO07_SOURCE 0x*** #define GPIO1_IO07_VALUE 0x*** #define GPIO1_IO07_DIR 0x*** #define GPIO1_IO07_INT 0x*** void MX_GPIO1_Init(void) { /* GPIO Ports Clock Enable */ __HAL_RCC_GPIO1_CLK_ENABLE(); /*Configure GPIO pin Output Level */ HAL_GPIO_WritePin(GPIO1, GPIO_PIN_7, GPIO_PIN_RESET); /*Configure GPIO pin : PtPin */ GPIO_InitTypeDef GPIO_InitStruct = {0}; GPIO_InitStruct.Pin = GPIO_PIN_7; GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; HAL_GPIO_Init(GPIO1, &GPIO_InitStruct); } ``` 6. 如果你使用的是Linux设备树,还需要确保生成的设备树片段(.dtsi文件)正确地添加到了你的设备树源代码中,以便编译器能够理解和配置硬件。 完成以上步骤后,你就可以将生成的C语言代码和设备树片段集成到你的Linux项目中,进行编译和测试。在实际操作中,你可能还需要根据实际情况调整引脚配置,或者修改生成的代码以满足特定的开发需求。 为了进一步深化对PINS-TOOL-IMX的理解,并探索更多高级功能,建议继续学习《NXP i.MX6ULL引脚配置工具PINS-TOOL-IMX详解》一书中的相关章节。这本书不仅涵盖了基本的引脚配置和代码生成,还涉及了如何处理复杂硬件配置和优化引脚使用效率等高级主题。 参考资源链接:[NXP i.MX6ULL引脚配置工具PINS-TOOL-IMX详解](https://wenku.csdn.net/doc/6452318bea0840391e739170?utm_source=wenku_answer2doc_content)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

眺望电子-ARM嵌入式

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值