我正在创建一个基于 NXP(飞思卡尔)i.MX287 处理器的嵌入式系统。我正在使用通过迷你 PCIe 连接器连接到我的评估板的核心处理板。
UART 0、3、4 用作 RS232,UART 1、2 用作 RS485。核心板在其引脚排列中不提供 RTS 信号,因此我必须使用 I2C GPIO 扩展器的引脚来控制 RS485 方向。 GPIO扩展模块还用于控制板子上的其他一些设备。
在用户空间,我可以使用 libi2c 控制方向引脚,但我的客户要求我将方向引脚控制放在 UART 驱动程序中。
问题:
1- 我如何与 auart 驱动程序中的 i2c 设备交互? (是否可能)
2- 如果可能,那么如何防止 i2c-0 总线被内核阻塞? (我还需要用户空间调用 libi2c 才能正常工作)
我在谷歌上搜索了很多,但大多数情况都是关于如何使用 I2C 驱动程序或如何激活 sysfs 中的 GPIO 引脚,而我能够完成所有这些。
libi2c 用于用户空间,所以我不能在这里调用它。我也知道在内核中打开文件 (/dev/i2c-0) 并读取或写入它不是一个好主意。我试图了解处理此问题的最佳方法是什么,而不会导致任何并发访问问题。
我会很感激任何想法
P.S. - 我对 Linux 内核的工作原理没有深入的了解,如果我的问题有点含糊,很抱歉。
编辑 1: 根据@0andriy 的建议,我编辑了 DTS 文件并将以下内容添加到 /arch/arm/boot/dts/my_dts_file.dts
:
/dts-v1/;
#include "imx28.dtsi"
/ {
// some definitions
apbx@80040000 {
i2c0: i2c@80058000 {
pca8575: gpio@20 {
compatible = "nxp,pca8575";
reg = <0x20>; // PCA8575PW Address -0-0-0
gpio-controller;
#gpio-cells = <2>;
};
};
auart1: serial@8006c000 {
pinctrl-names = "default";
pinctrl-0 = <&auart1_2pins_a>;
linux,rs485-enabled-at-boot-time;
rs485-rts-delay = <0 0>; // in milliseconds
rts-gpios = <&pca8575 4 GPIO_ACTIVE_LOW>;
rs485-rts-active-low;
status = "okay";
};
auart2: serial@8006e000 {
pinctrl-names = "default";
pinctrl-0 = <&auart2_2pins_b>;
linux,rs485-enabled-at-boot-time;
rs485-rts-delay = <0 0>; // in milliseconds
rts-gpios = <&pca8575 5 GPIO_ACTIVE_LOW>;
rs485-rts-active-low;
status = "okay";
};
};
// some definitions
};
然后重建内核。我还编辑了 mxs-auart.c 驱动程序中的 mxs_auart_init_gpios
函数,以在启动时打印出所有 auart GPIO 的引脚描述。但是 gpiod = mctrl_gpio_to_gpiod(s->gpios, i)
始终为 NULL。 /sys/class/gpio/
root# ls /sys/class/gpio
export gpiochip128 gpiochip64 unexport
gpiochip0 gpiochip32 gpiochip96
编辑 2:
imx28.dtsi
文件中的
auart1_2pins_a
和 auart2_2pins_b
:
auart2_2pins_b: auart2-2pins@1 {
reg = <1>;
fsl,pinmux-ids = <
MX28_PAD_AUART2_RX__AUART2_RX
MX28_PAD_AUART2_TX__AUART2_TX
>;
fsl,drive-strength = <MXS_DRIVE_4mA>;
fsl,voltage = <MXS_VOLTAGE_HIGH>;
fsl,pull-up = <MXS_PULL_DISABLE>;
};
auart1_2pins_a: auart1-2pins@0 {
reg = <0>;
fsl,pinmux-ids = <
MX28_PAD_AUART1_RX__AUART1_RX
MX28_PAD_AUART1_TX__AUART1_TX
>;
fsl,drive-strength = <MXS_DRIVE_4mA>;
fsl,voltage = <MXS_VOLTAGE_HIGH>;
fsl,pull-up = <MXS_PULL_DISABLE>;
};
我正在使用内核 4.14.13
请您参考如下方法:
我对你们的董事会一点都不熟悉,所以对这个答案持保留态度,但我注意到你们的文件中有一些有趣的东西。
首先,您需要定义要用于切换 UART pinmux 内部方向的 I2C 引脚:
auart2_2pins_b: auart2-2pins@1 {
reg = <1>;
fsl,pinmux-ids = <
MX28_PAD_AUART2_RX__AUART2_RX
MX28_PAD_AUART2_TX__AUART2_TX
MX28_PAD_I2C0_SCL__I2C0_SCL
>;
fsl,drive-strength = <MXS_DRIVE_4mA>;
fsl,voltage = <MXS_VOLTAGE_HIGH>;
fsl,pull-up = <MXS_PULL_DISABLE>;
};
请务必仔细检查您要使用的引脚名称,我无法确定这是正确的。
然后,您似乎缺少 I2C Controller 的 pinctrl
:
i2c0: i2c@80058000 {
pinctrl-names = "default";
pinctrl-0 = <&i2c0_pins_a>;
status = "okay";
pca8575: gpio@20 {
compatible = "nxp,pca8575";
reg = <0x20>; // PCA8575PW Address -0-0-0
gpio-controller;
#gpio-cells = <2>;
};
};
我无法确认您的 reg
和您的密码,但我假设您是从董事会的文档中获取的。如果没有,请确保找到可靠的硬件来源。
最后,我不确定你为什么要让 RTS 线路处于低电平状态,大多数收发器都有一个 DE/~RE 输入,这意味着你需要让线路处于高电平状态才能驱动总线。也许您的驱动程序不同...
你正在尝试做的事情被记录为适用于其他董事会,所以我想除非有错误,否则你应该能够让它工作。