デバイスツリーオーバーレイでイネーブルの場合、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@1RS485を追加しました。 (ハードウェアで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フラグの両方がゼロのようです。これが真であれば - (ボーナス質問)この場合、このドライバに関する問題を報告する必要がありますか?

便利なリソース:


後で修正/追加:

また、起動時にオーバーレイを適用してこのコードを実行するとき(ポートからフラグを読み取る必要がありますが正しいかどうかわからない)も確認しました。

    /* 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、、、、、、、、、(D13と同じ)。コマンド応答はリモートModBusデバイスから来ます。デュアルマイナスがあるため、転送中は電圧が高い(3.3V)ことに注意してください。D9=SDAD10=_IRQD11=TXDD12=_RTSD13=RXDAnalog1=one RS485 lineAnalog2=RXD_RTS

おすすめ記事