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")