我试图通过使用设备树覆盖(在引导时不运行C应用程序)使SC16IS752 (SPI到UART转换器)在RS485模式下工作。
我从github的官方来源获取了SC16IS752的原始覆盖源:
不添加linux,rs485-enabled-at-boot-time;
行,它的工作方式如下:(RTS总是很高)
我像这样更改了fragment@1
部件并添加了RS485 (我还更改了时钟freq,因为我在硬件中使用的是1.843200MHz晶体,而不是14.xxMHz):
fragment@1 {
target = <&spi1>;
frag1: __overlay__ {
#address-cells = <1>;
#size-cells = <0>;
pinctrl-names = "default";
pinctrl-0 = <&spi1_pins &spi1_cs_pins>;
cs-gpios = <&gpio 18 1>;
status = "okay";
/* RS485 SUPPORT */
linux,rs485-enabled-at-boot-time;
rs485-rts-delay = <0 0>;
/* RS485 SUPPORT END */
sc16is752: sc16is752@0 {
compatible = "nxp,sc16is752";
reg = <0>; /* CE0 */
clocks = <&sc16is752_clk>;
interrupt-parent = <&gpio>;
interrupts = <24 2>; /* IRQ_TYPE_EDGE_FALLING */
gpio-controller;
gpio-cells = <2>;
spi-max-frequency = <4000000>;
/* I also tried to put it here */
/* but RTS is always HIGH */
/* RS485 SUPPORT */
/* linux,rs485-enabled-at-boot-time; */
/* rs485-rts-delay = <0 0>; */
/* RS485 SUPPORT END */
sc16is752_clk: sc16is752_clk {
compatible = "fixed-clock";
#clock-cells = <0>;
clock-frequency = <1843200>;
};
};
};
};
我编译了dts
文件,并将其放到/boot/overlays
中,并在/boot/config.txt
中添加了正确的行来使用覆盖。
RTS行现在总是低的(没有标志,它是高的-见上图):
所以这个标志已经被内核/驱动程序读取了,但是RTS在我发送数据时什么也不做。它应该是这样的:
最后一次使用RS485模式的屏幕截图是在我在C程序中转换RS485模式之后拍摄的,如下所示:
#include <fcntl.h>
#include <unistd.h>
#include <linux/serial.h>
/* Include definition for RS485 ioctls: TIOCGRS485 and TIOCSRS485 */
#include <sys/ioctl.h>
int main(int argc, char *artv[]){
/* Open your specific device (e.g., /dev/mydevice): */
int fd = open ("/dev/ttySC0", O_RDWR);
if (fd < 0) {
/* Error handling. See errno. */
return -1;
}
struct serial_rs485 rs485conf;
/* Enable RS485 mode: */
rs485conf.flags |= SER_RS485_ENABLED;
/* Set logical level for RTS pin equal to 1 when sending: */
rs485conf.flags |= SER_RS485_RTS_ON_SEND;
/* Set logical level for RTS pin equal to 0 after sending: */
rs485conf.flags &= ~(SER_RS485_RTS_AFTER_SEND);
rs485conf.delay_rts_before_send = 0;
rs485conf.delay_rts_after_send = 0; // zero! nie obsługiwane przez SC16IS752
if (ioctl (fd, TIOCSRS485, &rs485conf) < 0) {
/* Error handling. See errno. */
return -2;
}
/* Use read() and write() syscalls here... */
/* Close the device when finished: */
if (close (fd) < 0) {
/* Error handling. See errno. */
return -3;
}
return 0;
}
那么,问题是如何在没有C程序的情况下做到这一点呢?
我怀疑驱动程序没有默认配置,并且在SER_RS485_RTS_ON_SEND和SER_RS485_RTS_AFTER_SEND标志中都有零。如果这是真的-(额外的问题)我应该报告这个司机在这种情况下的问题吗?
有用的资源:
编辑/添加后:
我还注意到,当我的覆盖在引导时被应用并运行这段代码(它应该从端口读取标志,我不确定它是否正确)。
/* Reading rs485conf struct from port */
if (ioctl (fd, TIOCGRS485, &rs485conf) < 0) {
/* Error handling. See errno. */
return -2;
}
printf("Before: ");
binprintf(rs485conf.flags); // function that prints int as binary
printf("\n");
所有的旗帜都是空的。所以..。启动后覆盖更改了RTS状态,但是端口上的标志是零吗?我不明白。
发布于 2020-11-02 13:03:32
如果有人发现了这个问题,就像我试图让SC16IS752在I2C上使用RPi时一样,答案是:
sc16is7xx.c
驱动程序没有任何调用uart_get_rs485_mode()
的代码,这些代码在serial_core.c
中描述,并出现在其他几个串行驱动程序中;rs485-rts-active-low
似乎只添加到RPi 5.3和更高版本的内核中(参见此提交)。为了解决第一个问题,我对sc16is7xx.c
驱动程序做了几处小更改,请参阅此提交。uart_get_rs485_mode()
函数从设备树中获取相关属性,并写入一个struct serial_rs485
,与TIOCSRS485
ioctl使用的相同。这些更改还没有经过回归测试,但目前它在我的SC16IS752接口上对我来说是可靠的。
此提交基于5.4内核,因此支持rs485-rts-active-low
属性,因此可以很好地与MAX3072行驱动程序一起工作。
下面是我的覆盖文件的一部分:
fragment@1 {
target = <&i2c_arm>;
__overlay__ {
#address-cells = <1>;
#size-cells = <0>;
status = "okay";
sc16is752: sc16is752@48 {
compatible = "nxp,sc16is752";
reg = <0x48>; /* i2c address */
clocks = <&sc16is752_clk>;
interrupt-parent = <&gpio>;
interrupts = <18 2>; /* IRQ_TYPE_EDGE_FALLING */
gpio-controller;
#gpio-cells = <2>;
i2c-max-frequency = <400000>;
linux,rs485-enabled-at-boot-time;
rs485-rts-active-low;
};
};
};
下面是一个显示它工作的范围图像:
参考:D8=SCL
,D9=SDA
,D10=_IRQ
,D11=TXD
,D12=_RTS
,D13=RXD
,Analog1=one RS485 line
,Analog2=RXD
(与D13相同)。命令响应来自远程ModBus设备。请注意,在传输期间,_RTS
很高(3.3V),因为存在双重否定。
https://unix.stackexchange.com/questions/541473
复制相似问题