Python PySerial с автоматической RTS через полудуплексную плату RS-485 с использованием Beaglebone Black Angstrom

Я пытаюсь использовать Beaglebone Black под управлением Angstrom (ядро 3.8) для связи с устройствами в полудуплексной сети RS-485 на 9600-N-8-1.

Я пытаюсь использовать плату RS-485 Breakout, похожую на эту: https://www.sparkfun.com/products/10124, за исключением того, что чип является MAX3485 http://www.maximintegrated.com/datasheet/index.mvp/id/1079. Я купил плату в сборе с контактами и клеммной колодкой. Мой друг протестировал его с помощью осциллографа и заявил, что плата RS-485 работает. На плате есть пять контактов, которые подключаются к BBB. 3-5 В (мощность), RX-I, TX-O, RTS и GND.

Я отключил поддержку HDMI на BBB, чтобы UART4_RTSn а также UART4_CTSn булавки будут доступны.

    mkdir /mnt/boot
    mount /dev/mmcblk0p1 /mnt/boot
    nano /mnt/boot/uEnv.txt
    #change contents of uEnv.txt to the following:
    optargs=quiet capemgr.disable_partno=BB-BONELT-HDMI,BB-BONELT-HDMIN 

Затем я нашел наложение для включения UART-4 с управлением RTS/CTS:

            /*
     * Modified version of /lib/firmware/BB-UART4-00A0.dtbo to add RTS so we can reset Arduinos
     */
    /dts-v1/;
    /plugin/;

    / {
      compatible = "ti,beaglebone", "ti,beaglebone-black";
      part-number = "BB-UART4-RTS";
      version = "00A0";
      exclusive-use = "P9.13", "P9.11", "P9.15", "P8.33", "P8.35", "uart4";

      fragment@0 {
        target = <0xdeadbeef>;

        __overlay__ {


          pinmux_bb_uart4_pins {
            pinctrl-single,pins = <
              0x070 0x26   /* P9_11 = UART4_RXD = GPIO0_30,    MODE6 */
              0x074 0x06   /* P9_13 = UART4_TXD = GPIO0_31,    MODE6 */
              /* need to enable both RTS and CTS, if we only turn on RTS then driver gets confused */
              0x0D0 0x26   /* P8_35 = UART4_CTSN = lcd_data12, MODE6 */
              0x0D4 0x06   /* P8_33 = UART4_RTSN = lcd_data13, MODE6 */
              /* 0x040 0x0F   /* P9_15 = GPIO1_16 = GPIO48,       MODE7  failed attempt to put DTR on gpio */
            >;
            linux,phandle = <0x1>;
            phandle = <0x1>;
          };
        };
      };

      fragment@1 {
        target = <0xdeadbeef>;

        __overlay__ {
          status = "okay";
          pinctrl-names = "default";
          pinctrl-0 = <0x1>;
        };
      };

      __symbols__ {
        bb_uart4_pins = "/fragment@0/__overlay__/pinmux_bb_uart4_pins";
      };

      __fixups__ {
        am33xx_pinmux = "/fragment@0:target:0";
        uart5 = "/fragment@1:target:0"; /* Not a mistake: UART4 is named uart5 */
      };

      __local_fixups__ {
        fixup = "/fragment@1/__overlay__:pinctrl-0:0";
      };
    };

Скомпилировал и включил оверлей:

    cd /lib/firmware
    dtc -O dtb -o BB-UART4-RTS-00A0.dtbo -b 0 -@ BB-UART4-RTS-00A0.dts 
    echo BB-UART4-RTS:00A0  > /sys/devices/bone_capemgr.*/slots

Подключил плату 485 к ББ вот так

    3-5V to P9_05 (VDD_5V)
    RX-I to P9_13 (UART4_TXD) 
    TX-O to P9_11 (UART4_RXD)
    RTS  to P8_33 (UART4_RTSn)
    GND  to P9_01 (DGND)

В Python я пытаюсь использовать последовательный порт, как это:

    import serial
    ser = serial.Serial('/dev/ttyO4', baudrate=9600, rtscts=True)
    ser.write(list_of_byte_dat)

Я знаю, что программа работает, потому что когда я использую конвертер USB в RS-485 на /dev/ttyUSB0 и установить rtscts=False связь работает в обоих направлениях просто отлично. Но я не могу заставить коммуникацию работать правильно, используя плату RS-485.

У меня две проблемы с платой RS-485, обе связаны с RTS.

  1. RTS на плате работает в обратном направлении так, как я ожидаю. Когда я подаю напряжение на вывод RTS платы rs485, светодиод RTS на плате гаснет и плата не передает. Когда я снимаю напряжение с контакта RTS, включается светодиод RTS и плата передает. Как изменить полярность контакта UART_RTSn на BBB?

    Temporary solution: I've made a small bone script program that uses UART4_RTSn pin as input. It turns on a different GPIO when the UART4_RTSn pin is off and turns off that same GPIO pin when the UART4_RTSn pin is on. Then hooked up the RTS pin on the rs485 board to the GPIO pin instead of the UART4_RTSn pin.

    Это, кажется, плохое решение, но оно заставляет RTS на плате RS485 включаться в правильное время при отражении на /dev/ttyO4 из командной строки.

    Как я могу изменить полярность UART4_RTSn закрепить или настроить аппаратную конфигурацию или изменить конфигурацию в pyserial?

    Это подводит меня ко второму вопросу

  2. Как я уже говорил в задаче 1, UART4_RTSn Пин будет работать автоматически (но в обратном направлении) для меня при выводе значения на порт tty, например:

    echo -en '\x02\xFD\xCD......' > /dev/ttyO4
    

    Это сделает UART4_RTSn светодиод мигает во время передачи данных. Если он настроен без упомянутого выше костяного сценария, он будет нормально включен и мигать во время передачи. Если я использую мой хак с бэкскриптом, он будет выключен и мигать во время передачи (что я и хочу). Однако это работает только при использовании echo из командной строки. Когда я использую Python и настраиваю последовательный порт UART4_RTSn Пин становится неактивным. Он не будет мигать во время передачи. Как только я сделаю заявление в python:

    ser = serial.Serial('/dev/ttyO4', baudrate=9600, rtscts=True)
    

    UART4_RTSn штифт отключается и остается выключенным. Не мигает при отправке информации с использованием ser.write(stuff), В результате плата rs485 не включена для передачи. Как я могу получить UART4_RTSn пин для автоматической работы в pyserial? Я пытался установить rtscts=False и это не сработало.

    Я могу использовать ser.setRTS(True) или же ser.setRTS(False) чтобы вручную переключать значение контакта, чтобы я знал, что я использую правильный контакт и что он распознается. Но я не хочу напрямую переключать контакт UART4_RTSn. Я хочу, чтобы он работал автоматически, когда последовательный порт передает данные, и он работает при использовании echo, но не в Python.

Любая помощь будет принята с благодарностью.

3 ответа

RTS обычно активный активный низкий сигнал, я подозреваю причину, по которой вы видите, что данные передаются с echo является то, что он не использует RTS/CTS (оставляя его на высоком уровне) и поэтому может только передавать данные.

Согласно сообщению на http://www.raspberrypi.org/phpBB3/viewtopic.php?f=26&t=29408

Если вы включите аппаратное управление потоком (CRTSCTS в "man termios", или "stty crtscts -F /dev/ttyAMA0", или pySerial rtscts=True), то отправка будет происходить только после подтверждения CTS. RTS будет утвержден за исключением случаев, когда буфер ввода ядра заполнен. Входной буфер ядра составляет около одной страницы или 4 КБ, поэтому ваше приложение должно отстать в чтениях до того, как RTS действительно изменится.

Поэтому убедитесь, что CTS утверждается (тянется к земле) за пределами вашей доски. Однако я не думаю, что это даст вам правильный контроль над RTS, который вам нужен.

Итак, для вашего приложения вы должны отключить аппаратное управление потоком (rtscts=False) и вручную управлять RTS с помощью setRTS(1) перед записью и setRTS(0) после этого.

Если вы все еще не видите, как данные поступают на устройство, попробуйте поменять местами провода A & B - маркировка A/B (разочаровывающе) не согласована на устройствах RS485. Лучше использовать D+/D- маркировку, если это возможно, в ваших собственных приложениях.

Используйте ioctl, чтобы изменить уровень логики...

98         struct serial_rs485 rs485conf;
 99 
100         /* Enable RS485 mode: */
101         rs485conf.flags |= SER_RS485_ENABLED;
102 
103         /* Set logical level for RTS pin equal to 1 when sending: */
104         rs485conf.flags |= SER_RS485_RTS_ON_SEND;
105         /* or, set logical level for RTS pin equal to 0 when sending: */
106         rs485conf.flags &= ~(SER_RS485_RTS_ON_SEND);
107 
108         /* Set logical level for RTS pin equal to 1 after sending: */
109         rs485conf.flags |= SER_RS485_RTS_AFTER_SEND;
110         /* or, set logical level for RTS pin equal to 0 after sending: */
111         rs485conf.flags &= ~(SER_RS485_RTS_AFTER_SEND);
112 
113         /* Set rts delay before send, if needed: */
114         rs485conf.delay_rts_before_send = ...;
  1. Вы можете использовать pnp транзистор / p канал Mosfet/ логический вентиль не - инвертор, как 7404

  2. может быть, вам нужно очистить буфер записи после операции записи ser.write(....) ser.flush()

Другие вопросы по тегам