概述
总结
pinctrl作为驱动
iomuxc节点在设备树里面 存储全部所需的引脚配置信息
最后因为犯傻,写了裸机使用datasheet的过程,不然脱离裸机太久
iomux节点匹配pinctrl子系统
控制硬件外设的时候 要知道有哪些gpio 再看gpio有哪些服用寄存器
接着在程序配置gpio相关寄存器 这样搞效率很低
所以用iomux节点保存所有的引脚组 pinctrl驱动起来的时候获得所有引脚信息 保存在内存
pinctrl子系统预先确定引脚的数量和名字
- 为每个引脚的配置信息分配内存
- pinctrl子系统统一管理每个引脚的使用状态
-iomux节点存放了各种引脚属性,pinctrl驱动解析iomux节点,存放引脚信息进入内存
iomux节点里如何填写
//iomuxc节点
//imx6ull.dtsi
iomuxc: iomuxc@20e0000 {
compatible = "fsl,imx6ul-iomuxc";
reg = <0x20e0000 0x4000>;
};
//继续扩展 引用iomux节点 **imx6ull-seeed-npi.dts**
&iomuxc {
pinctrl-names = "default","init","sleep"; //选定引脚状态
pinctrl-0 = <&pinctrl_uart1>; //一个状态就是一组引脚,比如对应下面
pinctrl-1 =<&xxx>;
pinctrl-2 =<&yyy>;
...
pinctrl_uart1: uart1grp {
fsl,pins = <
MX6UL_PAD_UART1_TX_DATA__UART1_DCE_TX 0x1b0b1
MX6UL_PAD_UART1_RX_DATA__UART1_DCE_RX 0x1b0b1
>;
};
...
}
上面 引脚里面的宏是什么意思
MX6UL_PAD_UART1_TX_DATA__UART1_DCE_TX
#define MX6UL_PAD_UART1_TX_DATA__UART1_DCE_TX 0x0084 0x0310 0x0000 0 0
< mux_reg conf_reg input_reg mux_mode input_val >
0x0084 0x0310 0x0000 0x0 0x0
mux_reg:引脚复用设置寄存器 基地址+mux_reg 就是 PIN 的复用寄存器地址。
conf_reg : 设置这个引脚的电气属性的寄存器地址 基地址+conf_reg =设置pin的电气属性地址
input_reg:引脚输入设置寄存器 有些外设有 input_reg 寄存器
引脚需要输入功能时设置
mux_mode:复用寄存器设置值
设置引脚复用
input_val:输入寄存器设置值
设置引脚输入特性
宏的最后跟随了一串数字 用来设置PIN的电气属性值 比如IO 的上/下拉、驱动能力和速度等
引脚状态初始化
在设备树里面节点 会变成plantform_dev 会执行probe进行匹配驱动
但是执行probe和drv配对之前 先回执行really_porbe() 这个函数和下面的引脚状态关系很大
用来初始化引脚值
//iomuxc节点
//imx6ull.dtsi
iomuxc: iomuxc@20e0000 {
compatible = "fsl,imx6ul-iomuxc";
reg = <0x20e0000 0x4000>;
};
//继续扩展 引用iomux节点 **imx6ull-seeed-npi.dts**
&iomuxc {
pinctrl-names = "default","init","sleep"; //选定引脚状态
pinctrl-0 = <&pinctrl_uart1>; //一个状态就是一组引脚,比如对应下面
pinctrl-1 =<&xxx>;
pinctrl-2 =<&yyy>;
...
pinctrl_uart1: uart1grp {
fsl,pins = <
MX6UL_PAD_UART1_TX_DATA__UART1_DCE_TX 0x1b0b1
MX6UL_PAD_UART1_RX_DATA__UART1_DCE_RX 0x1b0b1
>;
};
...
}
还是用上一个设备树举例 看了下面的例子
就知道驱动的引脚其实在 probe之前就已经初始化好了电气属性了
drivers/base/dd.c
static int really_probe(struct device *dev, struct device_driver *drv)
{
int ret = -EPROBE_DEFER;
...
re_probe:
dev->driver = drv;
ret = pinctrl_bind_pins(dev); //这里根据iomux节点的 几个引脚状态来初始化引脚组
...
if (dev->bus->probe) {
ret = dev->bus->probe(dev);
if (ret)
goto probe_failed;
} else if (drv->probe) {
ret = drv->probe(dev); //这个是熟悉的probe
if (ret)
goto probe_failed;
}
...
}
int pinctrl_bind_pins(struct device *dev)
dev->pins->default_state = pinctrl_lookup_state(dev->pins->p,PINCTRL_STATE_DEFAULT);//从设备节点状态找到指定状态
//本次是default状态
dev->pins->init_state = pinctrl_lookup_state(dev->pins->p,PINCTRL_STATE_INIT); /这次找init状态
if (IS_ERR(dev->pins->init_state))
pinctrl_select_state(dev->pins->p,dev->pins->default_state);//没有init状态变成default状态
else
ret = pinctrl_select_state(dev->pins->p, dev->pins->init_state);//有的话引脚变成init状态
裸机流程
因为犯傻,一时候对裸机流程和这个分不清楚,datasheet忘记啥玩了 写在这里
问了mcu同学,如果是mcu怎么玩的: mcu都是物理地址,在mcu访问的寄存器中
从0开始到0x80000000这样 都是寄存器地址, 往后就是片内的flash地址 再往后就是rom地址
那我们如果裸机配置gpio的话 过程为 时钟打开->引脚复用->电气属性配置->设置gpio属性->设置中断属性
datasheet第30章 iomux章 包含了所有的引脚的复用配置寄存器 比如:IOMUXC_SW_MUX_CTL_PAD_UART1_CTS_B
UART1_CTS_B 这个有点像原理图上的pad_name或pin_name 用来定义不同的引脚名字
也包含了所有引脚的电气属性配置寄存器 比如 IOMUXC_SW_CTL_PAD_UART1_CTS_B
用来配置 迟滞比较器 来设置上下拉电阻 或IO作为输入的时候 设置IO使用上下拉还是状态保持器
或者禁止上下拉/状态保持器功能 或禁止或者使能开路输出 或IO_SPEED 或IO用作输出驱动能力 压摆率(io在0和1跳变要的时间)
上面已经给引脚选择了复用为gpio功能
下面翻到 datasheet到gpio章 找其他寄存器配置gpio
一组gpio最大32个,一个寄存器32位 刚刚好能配置一组状态
配置 GPIO_DR寄存器 决定这一组gpio如果输出的话 输出状态
配置 GPIO_GDIR寄存器 决定这一组gpio用作输入还是输出
配置 GPIO_ICR1或2寄存器 两个寄存器决定了中断触发方式,用两个32位寄存器决定了一组gpio中断触发方式
配置 GPIO_IMR寄存器 决定这组gpio是否打开中断
读取 GPIO_ISR寄存器 知道这组gpio中哪个gpio中断触发
@@@@@@@@@@参考正点的汇编点灯
最后
以上就是迷你小猫咪为你收集整理的13_pinctrl子系统的全部内容,希望文章能够帮你解决13_pinctrl子系统所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复