장치 트리 오버레이에서 활성화되면 SC16IS752의 RS485 하드웨어 RTS가 작동하지 않습니다.

장치 트리 오버레이에서 활성화되면 SC16IS752의 RS485 하드웨어 RTS가 작동하지 않습니다.

장치 트리 오버레이를 사용하여(시작 시 C 응용 프로그램을 실행하지 않고) SC16IS752(SPI-UART 변환기)가 RS485 모드에서 작동하도록 하려고 합니다.

github의 공식 소스에서 SC16IS752에 대한 원래 적용 범위 소스를 얻었습니다.

sc16is752-spi1-overlay.dts

줄을 추가하지 않으면 linux,rs485-enabled-at-boot-time;다음과 같이 작동합니다. (RTS는 항상 높습니다)

장치 트리 플래그 없음

이렇게 부품을 변경 fragment@1하고 RS485를 추가했습니다. (하드웨어에서 14.xxxxMHz가 아닌 1.843200MHz 크리스털을 사용하고 있기 때문에 클럭 주파수도 변경했습니다.)

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 프로그램을 사용하지 않고 수행하는 방법?

장치 트리에서 rs485 모드를 설정하는 것만으로는 충분하지 않은 이유는 무엇입니까?

드라이버에 기본 구성이 없고 SER_RS485_RTS_ON_SEND 및 SER_RS485_RTS_AFTER_SEND 플래그가 모두 0인 것 같습니다. 이것이 사실이라면 - (보너스 질문) 이 경우 이 드라이버에 대한 문제를 보고해야 합니까?

유용한 리소스:


나중에 수정/추가:

또한 시작 시 오버레이를 적용하고 이 코드를 실행할 때(포트에서 플래그를 읽어야 하는데 올바른지 확실하지 않음)도 확인했습니다.

    /* 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 상태를 변경했는데 포트의 플래그가 0인가요? 난 이해가 안 돼요.

답변1

SC16IS752가 RPi의 I2C를 통해 작동하도록 할 때처럼 누구든지 이 문제를 발견하면 간단한 대답은 다음과 같습니다.

  • 드라이버 에 설명된 sc16is7xx.c코드 호출이 없습니다 .uart_get_rs485_mode()serial_core.c다른 여러 직렬 드라이버에도 나타납니다.
  • 장치 트리 속성은 rs485-rts-active-lowRPi 5.3 이상 커널에만 추가된 것으로 보입니다(이 항목 참조).범죄).

첫 번째 문제를 해결하기 위해 드라이버를 약간 변경했습니다 sc16is7xx.c. 다음을 참조하세요.범죄. 이 uart_get_rs485_mode()함수는 장치 트리에서 관련 속성을 가져와서 struct serial_rs485ioctl에서 사용하는 것과 동일하게 에 기록합니다 TIOCSRS485. 이러한 변경 사항은 아직 회귀 테스트를 거치지 않았지만 현재 내 브레드보드 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;
        };
    };
};

작동 방식을 보여주는 오실로스코프 이미지는 다음과 같습니다.

I2C 및 RS485 신호

참고: D8=SCL, D9=SDA, D10=_IRQ, D11=TXD, D12=_RTS, D13=RXD, Analog1=one RS485 line, Analog2=RXD(D13과 동일). 명령 응답은 원격 ModBus 장치에서 나옵니다. _RTS이중 부정이 있기 때문에 전송 중에는 전압이 높다(3.3V)는 점에 유의하세요 .

관련 정보