Panasonic HHC ~ カセットインターフェース

2023/06/21

 RL-P1004Aプリンタには、カセットインターフェース機能があります。

カセットテープレコーダを接続し、録音・再生することで、HHC内のファイルを保存・読込ができます。

ただ現状では、アナログ・カセットレコーダは、動作するものも少なくなりました。何より、操作性が悪く、内容の編集もできない問題があります。


そこで、USB経由でPCに接続し、デジタル保存できるようにしてみました。デジタル保存によって、テキストファイルは、PCで編集後、HHCに戻すことも可能になります。


RL-P1004Aプリンタのアナログ入出力を解析すると、下記のような仕様のようです。
・'SAVE OUT'出力は、5mVpp
・'LOAD IN'入力は、1.0Vpp
・変調方式は、約1,500bpsのFM方式で、'0' -> 1.5KHz信号の半サイクル, '1' -> 3.0KHzの1サイクル



最適なMCUモジュールを選ぶために、要件を整理すると、
・コンパクトなハードウェア
・USB接続できるMCUモジュール
・MCUモジュール内のデータ保存スペース
・アナログ入出力が可能


上記から、RP2040-Zeroモジュールを選定しました。プログラミングにはmicropythonを選択しました。アナログ入力にはADCが使えますが、'SAVE OUT'出力が小さすぎますので、OP-ampを追加して、300倍のゲインを稼ぎました。アナログ出力については、micropythonはインタープリタであり、不定期のガーベージコレクションが発生するため、正確なタイミングのデジタル出力には不向きです。このため、RP2040のPIOASM機能で、正確なFMエンコードが実現しました。アナログ出力は、3.3Vppをトリマ抵抗器で、1.0Vpp程度に調整(ほぼ中点)しています。


下記が、カセットインターフェースの回路図です。



OP-ampは、電源3.3Vで十分なゲインと優れた周波数特性のNJU77701Fを選定しました。パッケージがSOT-23-5と米粒サイズですので、必要に応じ、DIP化変換基板の使用をお勧めします。


下記は、試作用基板にアナログ回路を実装し、RP2040-Zeroと接続した写真です。


次は、小型のプラスッチックケースに入れ、RL-P1004Aに接続した状態です、



実行例として、まず、PC上のThonnyツールを利用して、main.pyを実行し、'r'コマンドを選択します。次に、Panasonic HHCのメインメニューから'PRINTER/CASSETTE'を選択後、'1=SAVE FILE'、'1=ALL FILES'と進み、RL-P1004Aの'SAVE OUT'からアナログ信号を出力させます。しばらく待つと、'data'サブフォルダーにファイルが保存されることを確認できます。PC間の転送は、Thonnyツールが便利です。



ここで、ファイル形式が0x08(テキスト形式)の場合、拡張子'txt'が作成されますので、内容確認・修正できます。新規作成されたテキストファイルをHHCに転送することも可能です。


HHCに転送する場合は、テキストファイルファイル形式の場合は、拡張子'txt'その他の形式では、拡張子'bin'を指定することで、転送ファイルを指定できます。'*.txt'とすれば、ワイルドカード指定も可能です。


これで、HHC上でのプログラミングが容易になります。

micropythonで作成したカセットインターフェースツールを公開します。PIOASMの使い方など参考にしてもらえれば幸いです。また、レトロな他のPCにも応用できるかもしれません。


下記は、PIOASM部分の抜粋です。コメント部が、設計上のクロックタイミングになります。今回は50KHzの比較的遅いクロックで駆動していますが、最高125MHzまで動作させることができますので、独自のアプリケーションに柔軟に対抗させることができます。ただ、最高32命令しか使えない点が制約になります。興味がある方は、RP2040のデータシートを確認ください。

@asm_pio(out_init=PIO.OUT_LOW, autopull=False)

def fm_encoder(): # output stream to RL-P1004A cassette interface

    # outset -  DATA

    # HIGH freq -> 320uS(16 clock) + 320uS(16 clock)

    # LOW  freq -> 640uS(32 clock)

    # 1 clock = 20uS

    label("loop")

    pull(block)                      # clock#4

    set(x, 31)                       # clock#5

    jmp("start_bit")                 # clock#6

    

    label("next_bit")

    nop().delay(3)                   # clock#3

    

    label("start_bit")

    out(y, 1)                        # clock#7

    jmp(not_y,"bit0")                # clock#8


    label("bit1")

    nop().delay(5)                   # clock#9

    in_(pins, 1)                     # clock#15

    mov(pins, invert(isr)).delay(14) # clock#16 <- flip output

    in_(pins, 1)                     # clock#31

    mov(pins, invert(isr))           # clock#32 <- flip output

    jmp("check_loop")                # clock#1

    

    label("bit0")

    nop().delay(21)                  # clock#9

    in_(pins, 1)                     # clock#31

    mov(pins, invert(isr))           # clock#32 <- flip output

    nop()                            # clock#1

    

    label("check_loop")

    jmp(x_dec,"next_bit")            # clock#2

    jmp("loop")