0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Raspberry Pi 3 で PaSoRi RC-S330 が nfcpy で動かなかったのでトラブルシューティングした

0
Posted at

TL;DR

  • Raspberry Pi 3B+ に Sony PaSoRi RC-S330054c:02e1)を挿して python -m nfc すると input/output error while waiting for ack で初期化に失敗する。
  • 権限でもドライバでもなく、Pi3 の USB コントローラ dwc_otg の split-transaction の不具合が原因。64バイトを超える bulk-OUT 転送に応答が返らない
  • nfcpy は起動時の自己テスト diagnose('line')265バイト送るため、リーダーを使う前に必ず死ぬ。
  • カーネル起動オプションに dwc_otg.fiq_fsm_enable=0 dwc_otg.fiq_enable=0 を「セットで」 追加すると直る。
  • 落とし穴: fiq_enable=0 を単独指定すると効かない(ドライバが矛盾とみなして補正で戻す)。

環境

  • Raspberry Pi 3 Model B+ / Raspberry Pi OS(aarch64, kernel 6.x)
  • Python 3.13 + nfcpy 1.0.4(venv)
  • PaSoRi RC-S330(FeliCa S330, USB 054c:02e1、RC-S956 チップ)

症状

$ python -m nfc
This is the 1.0.4 version of nfcpy run in Python 3.13 ...
I'm now searching your system for contactless devices
ERROR:nfc.clf.rcs956:input/output error while waiting for ack
Sorry, but I couldn't find any contactless device

lsusb ではちゃんと見えているし、pcscd などの競合もない。udev で plugdev 権限も付けてある。困った。

切り分け

権限・競合は無関係

  • デバイスノードは crw-rw-r-- root plugdev、ユーザーは plugdev 所属で rw 可。
  • pcscd は inactive、デバイスを掴んでいるプロセスも無し。
  • USB リセット(USBDEVFS_RESET)を投げても変化なし。

エラーの発生箇所

nfcpy の pn53x.pycommand() を追うと、コマンド送信(write_frame)は成功し、その直後の ACK 読み取り(read_frame)で IO エラーになっていた。command() は read の例外を種類問わず「input/output error while waiting for ack」に丸めるので、実体は タイムアウト(チップが応答しない) だった。

転送サイズの境界を測る

エコーコマンドをデータ長を変えて送ってみると——

フレーム長 結果
64 バイト OK
65 バイト 無応答(タイムアウト)

ちょうど USB フルスピード bulk の最大パケットサイズ 64 バイトが境界。つまり 複数 USB パケットにまたがる bulk-OUT 転送が届いていない

なぜ nfcpy が即死するか

nfcpy は Device.__init__ で必ず chipset.diagnose('line') という通信自己テストを実行し、これが 262 バイトのデータ(フレーム長 273 バイト) を送る。64バイトの壁を超えるので、リーダーを一度も使わないうちに初期化が落ちる。小さいコマンド(GetFirmwareVersion 等)は通る。

原因:Pi3 の dwc_otg split-transaction

  • RC-S330 は フルスピード(12Mbps) デバイスで、Pi3 の内蔵ハイスピードハブ配下にぶら下がる。
  • Pi3 の USB コントローラ dwc_otg は、これを split transaction で駆動する。
  • この経路の マルチパケット bulk-OUT 転送に不具合があり、64バイトを超えると応答が返らない。

リーダー側のファームは正常(PC につなげば 265 バイトも通る前提で nfcpy は作られている)。ホスト側 USB スタックの問題

対処

カーネル起動オプションで FIQ を完全に無効化する。Raspberry Pi OS なら /boot/firmware/cmdline.txt(1行のスペース区切り)の末尾に追記:

dwc_otg.fiq_fsm_enable=0 dwc_otg.fiq_enable=0

再起動後、適用されたか cmdline ではなく実際の値で確認:

cat /sys/module/dwc_otg/parameters/fiq_enable      # N なら無効化成功
cat /sys/module/dwc_otg/parameters/fiq_fsm_enable  # N

dmesgFIQ disabled / FIQ split-transaction FSM disabled が出ていれば OK。これで 64バイトの壁が消え、265バイト級のフレームも往復し、python -m nfc がリーダーを検出する。

** found Sony RC-S330 RCS956v1.30 at usb:001:004

ハマりどころ:fiq_enable=0 単独は効かない

最初 dwc_otg.fiq_enable=0 だけを指定したが、まったく効かなかった。原因はドライバの整合性チェック:

dwc_otg: fiq_fsm_enable was set without fiq_enable! Correcting.

FSM が有効なのに FIQ だけ無効、という矛盾をドライバが「補正」して FIQ を有効に戻してしまう/sys/module/dwc_otg/parameters/fiq_enableY のままで気づいた。
必ず fiq_fsm_enable=0fiq_enable=0 をセットで指定すること。

試して効かなかった/不要だったもの:

設定 結果
fiq_fsm_enable=0 単独 65バイトが時々通る程度。壁は残る(NG)
fiq_enable=0 単独 ドライバ補正で無効化されず(NG)
dwc_otg.speed=1(USB全体を低速固定) 直る見込みだが全USBが12Mbps化(有線LANも低速化)。FIQ無効化で解決したので不要

補足:ハードを選べるなら

Pi 4 / Pi 5 は USB コントローラが dwc_otg ではなく xHCI なので、この不具合自体が出ない。リーダーを安定運用したいなら Pi4/5 が無難。

まとめ

  • input/output error while waiting for ackdwc_otg の split-transaction で >64バイトの bulk-OUT が落ちるのが真因。
  • dwc_otg.fiq_fsm_enable=0 dwc_otg.fiq_enable=0 をセットで入れて再起動。
  • 効いたかは /sys/module/dwc_otg/parameters/ の実値で確認。
  • 確実に避けたいなら Pi4/5。
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?