シリアル怪奇現象の正体見たり、「使用しているライブラリの仕様には注意」

先日、FPGAにシリアル接続すると、データが化けるという怪奇現象が発生することがわかりました。

thira2.hatenablog.com

原因が不明でオシロスコープやロジアナでみないといけない(持ってないですが)と思ったのですが、 識者の方からのコメントではボーレートがずれて、最後のStopbitを拾っているということでした。

というわけで、いろいろ試して原因を探してみることにしました。

  1. uartについて38Kbpsに速度落として確認
    --> 結果は115.2Kbpsと同様にNGでした。。

  2. Parity CheckとStop bit用の待ちサイクルを1サイクル分伸ばしてみた。
    (待ちサイクルが短いからParity bitで0を拾って開始されてしまったのではと想像) --> NG。Loopbackすら失敗しました。。。

1, 2より、シリアルの転送速度依存ではなく、またParity check, stopbitの長さは関係ないことがわかりました。 となると、そもそものクロック周波数が125MHzと想定していたのが100MHzだったりするのではと思いました。 そうなると残念ながら、クロック周波数測定の方法がないので、測る装置を購入するかしないといけない状況です。。

どうしたものかな。。 と思いました。

ぼんやりと、シリアル転送のタイミングチャートを見ていて、ふと 今回パリティは使っていないなと気付きました。 使っていないときには、Parityは送信不要とも思えました。 もし、Parityを送っておらず、skipしてStop codeを送ると、想定する受信データは1つずれることになります。

先日コメント頂いた内容で、最後のStop bitを拾っているという言葉がキラリ光りました。

「もしかして、PythonのSerialライブラリのParityとStopの扱いが想定と違うんじゃないのでは?」

pySerial API — pySerial 3.0 documentation

class serial.Serial
__init__(port=None, baudrate=9600, bytesize=EIGHTBITS, parity=PARITY_NONE, stopbits=STOPBITS_ONE, timeout=None, xonxoff=False, rtscts=False, write_timeout=None, dsrdtr=False, inter_byte_timeout=None)

parity – Enable parity checking. Possible values: PARITY_NONE, PARITY_EVEN, PARITY_ODD PARITY_MARK, PARITY_SPACE
stopbits – Number of stop bits. Possible values: STOPBITS_ONE, STOPBITS_ONE_POINT_FIVE, STOPBITS_TWO

↑のサイトを調べて驚愕でした。Serialライブラリのデフォルト設定はParityは送付しない、Stop bitは1つ送信と 想定していたものと2bit分異なっていたんです。(想定はparity 1bit, stop 2bit)

ということはです。想定に近づけるために、parity 1bitにする、あるいはstop 2bitにするとどうなるのか? 試してみました。

「PASSしました」

-ser = serial.Serial('/dev/tty.usbserial-14310', 115200, timeout=1.0)
+ser = serial.Serial('/dev/tty.usbserial-14310', 115200, timeout=1.0, parity=serial.PARITY_ODD) # stopbits=serial.STOPBITS_TWO

怪奇現象の正体

  1. pyserialライブラリのデフォルトはparity 1bitがなく、stop bitは1bitだった。
  2. 一方でFPGAのシリアル受信器はparity 1bit, stop bitは2bit(実際は半サイクルwait)想定だった。
  3. 1, 2より、データ部分が半サイクルずれることになり、データとして1bit前後した。
    1bit後: stop bitを拾ったために0x80に1bit右シフトした結果が出た。(0x80,0x80, 0x81, 0x81..)
    1bit前: 0x80が消えて1bit左シフトした値が出力されるようになった。(0x1,0x3, 0x5..)

あとがき

送信側(今回はSerialライブラリ)の仕様を理解していなかったことで、今回の現象が生じました。 とても基本的なことなので、お恥ずかしい限りで情けない限りです。

使用しているライブラリの仕様には注意しようと誓いました。