UARTのビットバンギングのPiGPIOライブラリの例


11

PiGPIOライブラリ http://abyz.me.uk/rpi/pigpio/index.htmlは、その機能の1つが「ユーザーgpioを使用するソフトウェアシリアルリンク」であると述べています。

これを使用して、2つの空きGPIOピン上でソフトウェアUARTを生成できることを意味します。

プロジェクトのサンプルページには、この機能の例はありませんが、Googleにはありません。

誰かこれをやったことがありますか?もしそうなら、私に例を示してください。

そうでない場合、UARTをビットバンギングするための代替ライブラリはありますか?

おかげで、


参照:raspberrypi.stackexchange.com/questions/3475/…raspberrypi.stackexchange.com/questions/24019/…後者は、pigpioを指す@joanによって回答されているため、彼はさらに洞察を提供できます。
ガニマ

Piからラップトップに送信し、ラップトップをPiにエコーバックさせることで、pigpioソフトウェアシリアルのテストを数日間費やしました。私はそれを書くつもりでしたが、イベントがその練習を追い越しました。私が見つけることができるものを見ていきます。
ジョーン

回答:


13

ソフトウェアシリアルの信頼性をテストするために使用したPythonを以下に示します。入力側はかなり簡単です。PythonまたはCで適切なビットバンシリアルオープンコールを行うだけです。波形を使用してビットストリームを作成する必要があるため、出力側がより複雑になります。

ここのコードは、8ビットのデータではなく7ビットのデータを使用しています。テストは、バイトごとに異なるビットのサポートを追加するのとほぼ同時に書かれました。

このコードは、バイナリデータのブロックをラップトップに(シリアルドングルを介して)接続されているgpioに書き込みます。ラップトップは入力シリアルデータを出力シリアルラインにエコーします。Piは別のgpioでシリアルデータを読み取ります。

コードは、送信データと受信データの不一致をチェックします。ラップトップはエラーがないと想定されているため、エラーはビットバンギングにあると想定されます。

ログを見ると、19.2kbps未満のものは確かでした。115.2 kbpsまでのものは妥当でしたが(チェックサムが必要です)、230.4 kbpsで13%のバイトエラー率が得られました。

#!/usr/bin/env python

# bb_serial.py
# 2014-12-23
# Public Domain

# bit bang transmit and receive of serial data
#
# tested by connecting the arbitrary RX/TX gpios to a USB
# serial dongle plugged in to a Linux box.
#
# on the Linux box set the baud and data bits (cs5-cs8)
#
# stty -F /dev/ttyUSB0 19200 cs8
# cat </dev/ttyUSB0 >/dev/ttyUSB0
#
# so the Linux box echoes back data received from the Pi.
#
# laptop timings deviations
#
# baud  exp us   act us
#   50   20000    13310 * 75
#   75   13333    13310
#  110    9091    13310 * 75
#  134    7462     6792 * 150
#  150    6667     6792
#  200    5000     6792 * 150
#  300    3333     3362
#

import sys
import time
import difflib

import pigpio

RX=19
TX=26

MSGLEN=256

if len(sys.argv) > 1:
   baud = int(sys.argv[1])
else:
   baud = 115200

if len(sys.argv) > 2:
   bits = int(sys.argv[2])
else:
   bits = 8

if len(sys.argv) > 3:
   runtime = int(sys.argv[3])
else:
   runtime = 300

ten_char_time = 100.0 / float(baud)

if ten_char_time < 0.1:
   ten_char_time = 0.1

MASK=(1<<bits)-1

# initialise test data

msg = [0] * (MSGLEN+256)

for i in range(len(msg)):
   msg[i] = i & MASK

first = 0

pi = pigpio.pi()

pi.set_mode(TX, pigpio.OUTPUT)

# fatal exceptions off (so that closing an unopened gpio doesn't error)

pigpio.exceptions = False

pi.bb_serial_read_close(RX)

# fatal exceptions on

pigpio.exceptions = True

# create a waveform representing the serial data

pi.wave_clear()

TEXT=msg[first:first+MSGLEN]
pi.wave_add_serial(TX, baud, TEXT)
wid=pi.wave_create()

# open a gpio to bit bang read the echoed data

pi.bb_serial_read_open(RX, baud, bits)

# zero error counts

bad_char = 0
total_char = 0

# run for fixed time

start=time.time()

while (time.time()-start) < runtime:

   pi.wave_send_once(wid)   # transmit serial data
   pi.wave_delete(wid)

   TXTEXT = TEXT

   first += 1
   if first >= MSGLEN:
      first = 0

   TEXT=msg[first:first+MSGLEN]
   pi.wave_add_serial(TX, baud, TEXT,bb_bits=7)

   while pi.wave_tx_busy(): # wait until all data sent
      pass

   wid=pi.wave_create()

   count = 1
   text=""
   lt = 0
   total_char += MSGLEN

   while count: # read echoed serial data
      (count, data) = pi.bb_serial_read(RX)
      if count:
         text += data
         lt += count
      time.sleep(ten_char_time) # enough time to ensure more data

   if text != TXTEXT: # Do sent and received match?
      if lt == MSGLEN: # No, is message correct length?
         for i in range(MSGLEN): # If so compare byte by byte.
            if text[i] != TXTEXT[i]:
               # print("{:2X} {:2X}".format(text[i], TXTEXT[i]))
               bad_char += 1
      else: # Wrong message length, find matching blocks.
         ok = 0
         s=difflib.SequenceMatcher(None, TXTEXT, text)
         for frag in  s.get_matching_blocks():
            ok += frag[2] # More matching bytes found.
            # print(frag)
         # print(text, MSGLEN, ok)
         if ok < MSGLEN: # Sanity check.
            bad_char += (MSGLEN - ok)
         else:
            print("*** ERRONEOUS good={} LEN={} ***".format(ok, MSGLEN))

print("secs={} baud={} bits={} bad={:.3f}%".
   format(runtime, baud, bits, float(bad_char)*100.0/float(total_char)))

print("total={} badchar={}".format(total_char, bad_char))

# free resources

pi.wave_delete(wid)

pi.bb_serial_read_close(RX)

pi.stop()

ログ

harry /ram $ for ((i=0;i<4;i++)); do /code/bb_serial.py 230400; done
secs=300 baud=230400 bad=12.610%
total=249344 badchar=31443
secs=300 baud=230400 bad=12.580%
total=247296 badchar=31111
secs=300 baud=230400 bad=12.669%
total=246528 badchar=31232
secs=300 baud=230400 bad=12.274%
total=249600 badchar=30635
harry /ram $ for ((i=0;i<4;i++)); do /code/bb_serial.py 115200; done
secs=300 baud=115200 bad=0.378%
total=246784 badchar=934
secs=300 baud=115200 bad=0.152%
total=241408 badchar=368
secs=300 baud=115200 bad=0.189%
total=249088 badchar=472
secs=300 baud=115200 bad=0.347%
total=242688 badchar=843
harry /ram $ for ((i=0;i<4;i++)); do /code/bb_serial.py 57600; done
secs=300 baud=57600 bad=0.080%
total=220416 badchar=177
secs=300 baud=57600 bad=0.066%
total=219392 badchar=145
secs=300 baud=57600 bad=0.099%
total=219904 badchar=218
secs=300 baud=57600 bad=0.084%
total=219136 badchar=184
harry /ram $ for ((i=0;i<4;i++)); do /code/bb_serial.py 38400; done
secs=300 baud=38400 bad=0.019%
total=206336 badchar=39
secs=300 baud=38400 bad=0.021%
total=206848 badchar=43
secs=300 baud=38400 bad=0.015%
total=206592 badchar=30
secs=300 baud=38400 bad=0.030%
total=206592 badchar=61
harry /ram $ for ((i=0;i<4;i++)); do /code/bb_serial.py 19200; done
secs=300 baud=19200 bad=0.000%
total=175104 badchar=0
secs=300 baud=19200 bad=0.000%
total=175360 badchar=0
secs=300 baud=19200 bad=0.000%
total=175360 badchar=0
secs=300 baud=19200 bad=0.000%
total=174336 badchar=0
harry /ram $ for ((i=0;i<4;i++)); do /code/bb_serial.py 75; done
secs=300 baud=75 bad=0.000%
total=2048 badchar=0
secs=300 baud=75 bad=0.000%
total=2048 badchar=0
secs=300 baud=75 bad=0.000%
total=2048 badchar=0
secs=300 baud=75 bad=0.000%
total=2048 badchar=0
harry /ram $ for ((i=0;i<4;i++)); do /code/bb_serial.py 19200; done
secs=300 baud=19200 bad=0.000%
total=174592 badchar=0
secs=300 baud=19200 bad=0.000%
total=174592 badchar=0
secs=300 baud=19200 bad=0.000%
total=174848 badchar=0
secs=300 baud=19200 bad=0.000%
total=174848 badchar=0
harry /ram $ for ((i=0;i<4;i++)); do /code/bb_serial.py 19200; done
secs=300 baud=19200 bad=0.000%
total=174848 badchar=0
secs=300 baud=19200 bad=0.000%
total=175360 badchar=0
secs=300 baud=19200 bad=0.000%
total=174592 badchar=0
secs=300 baud=19200 bad=0.000%
total=174848 badchar=0
harry /ram $ for ((i=0;i<4;i++)); do /code/bb_serial.py 19200; done
secs=300 baud=19200 bad=0.000%
total=174592 badchar=0
secs=300 baud=19200 bad=0.000%
total=175104 badchar=0
secs=300 baud=19200 bad=0.000%
total=175104 badchar=0
secs=300 baud=19200 bad=0.000%
total=175360 badchar=0
harry /ram $ for ((i=0;i<4;i++)); do /code/bb_serial.py 19200; done
secs=300 baud=19200 bad=0.000%
total=175104 badchar=0
secs=300 baud=19200 bad=0.000%
total=174592 badchar=0
secs=300 baud=19200 bad=0.000%
total=174848 badchar=0
secs=300 baud=19200 bad=0.000%
total=175104 badchar=0
harry /ram $ for ((i=0;i<4;i++)); do /code/bb_serial.py 19200; done
secs=300 baud=19200 bad=0.000%
total=174848 badchar=0
secs=300 baud=19200 bad=0.000%
total=174848 badchar=0
secs=300 baud=19200 bad=0.000%
total=174848 badchar=0
secs=300 baud=19200 bad=0.000%
total=175104 badchar=0

どのシリアルドングルを使用しましたか?古いものは時々かなり信頼できないことがあります...
not2qubit

テストにはPL2303HX USB To RS232 TTL 5V 3.3V出力モジュールを使用しました。eBayから£1.53。
ジョーン

ドングルの信頼性を簡単にテストできます。独自のTxをRxに接続してテストを再実行します
イヤカム'29年

0

TxをRxに直接配線して、ドングルのようなエラーを追加するものがない場合は、ライブラリが実際にどの程度優れているかを示します。

Raspberry Pi 3b +では、GPIO 23をTxとして、GPIO 24をRxまたはその他の無料のGPIOとして使用します。これは、オンボードUARTと同じ順序で見栄えがよく、実際にはその隣にあります。Rxの右側にGNDピンがあり、右側にピンが3つだけあります。

結果:

Until 19200bps no errors.
- 38400 and 57600 bps less 1% error sometimes
- 115200bps was 10-20% error or so
- 230400bps over 80% error or so

チェックサムハッシュやSPI / I2CからUARTへのコンバーターを使用せずに19200以下で生活できる場合は、問題ありません。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.