FDDの34ピン信号をRaspberry PiのGPIOに接続してフロッピーを読み書きしてみたので、作業メモを残しておきます。USB-FDDが使えない、古い倍密度フォーマットのための環境を用意したくてやってみたのですが、2HDにも一応使えるようです。テストは主に2HDとPC-6601用1D/1DDで行いました。
(2017.10.12追記: カーネル4.9.yで動くようドライバを修正。また、Raspberry Pi Zeroでも動作することを確認しました。)
(2018.2.25追記: ドライバのビルド手順とMakefileを更新しました。)
Raspberry Pi A+のGPIOにFDDを接続
Raspbian上で動きます。カーネル4.4.44+と4.9.53+でテストしました。専用のデバイスドライバ内で割り込みを停止して、データリード信号がONになるタイミングをポーリングで待ち、その時間の一覧をファイルに書き出す、というのが基本的な仕組みです。読み出し終了後、別のプログラムでD88形式に変換します。書き込みはその逆です。ディスクイメージを丸ごと吸い出したり流し込んだりする形になります。原理としては、以前RXマイコンを使ってやってみた実験と同じことをやっています。
吸い出したイメージは、セクタ内データだけでなく、GAP/SYNC/アドレスマーク/セクタID/CRC/書き足し境界に発生した中途半端な信号、などをすべて含んだものになります。また、データビットの他にクロックビットも含みます。D88への変換時には、ビット間の時間差を求めて2μs単位 (倍密度の場合) もしくは1μs単位 (高密度の場合) に四捨五入し、SYNC部でデータビットかクロックビットかを判定して解析を行います。SYNCによる周波数調整は今のところ行っていません。
Y-E DATA製YD-702D-6639Dを使ってテストしました。普通の (新しめの) 34ピン2モード/3モードFDDであれば、大きな違いは無いのではないかと思います。また、以下の信号線の他に、FDDの電源 (5V) を接続する必要があります。電源は1Aあれば大抵のドライブで足りそうな感じです。
GPIO番号 | GPIO設定 | RPIピン番号 | FDDピン番号 | 信号名 | FDDから見たIN/OUT | 機能 (ON=LOW) |
---|---|---|---|---|---|---|
- | - | - | 2 | MODE SELECT | IN | 2HDモード時に回転数を360rpmにする (使用せず) |
4 | IN | 7 | 8 | INDEX | OUT | トラックの開始位置信号 |
17 | OUT | 11 | 12 | DRIVE SELECT | IN | ドライブ使用時ONにする |
18 | OUT | 12 | 16 | MOTOR ON | IN | ディスクを回転させるモーターをON |
27 | OUT | 13 | 18 | DIRECTION SELECT | IN | シーク方向を決める。ON時内側 |
22 | OUT | 15 | 20 | STEP | IN | 1ステップ分シークする |
23 | OUT | 16 | 22 | WRITE DATA | IN | データ書き込み信号 |
24 | OUT | 18 | 24 | WRITE GATE | IN | データ書き込み時ONにする。OFF時リード・シーク可 |
25 | IN | 22 | 26 | TRACK 00 | OUT | ヘッドが最外周にあればON |
- | - | - | 28 | WRITE PROTECT | OUT | ライトプロテクトがかかったディスクならON (使用せず) |
8 | IN | 24 | 30 | READ DATA | OUT | データ読み取り信号 |
7 | OUT | 26 | 32 | SIDE ONE SELECT | IN | OFF時サイド0、ON時サイド1選択 |
- | - | - | 34 | DISK CHANGE | OUT | 電源投入後もしくはディスクが抜かれるとON (使用せず) |
GND | GND | 39など | 奇数ピン | GND | GND | GND |
一応、UARTとI2CとSPIを避けて、26ピン内に収めるようにしてみました。面倒なので自分は信号線すべて直結していますが、Raspberry PiのGPIOが3.3Vなのに対し、FDDのI/Oは一般に5Vなので、おすすめしません。適宜レベル変換などするべきでしょう。
FDDの出力は、複数台つないだ時の電圧の衝突を避けるため、大抵オープンドレインになっています。なので内部プルアップしていなければ直結しても大丈夫かなと思ったのですが、中には5Vを直接出すドライブもあるようです。手元にあるものだと、TEAC FD-05HG-4668-Uが5V直接出力でした (3ステートバッファを使っているようです)。34ピン式でなくFFCケーブルを使うタイプで、コネクタとピンアサインを変換して接続したのですが、直結だと動きませんでした。と言うかGPIO動作がしばらく変になったりしたので、Raspberry Pi側が何らかのダメージを受けたかもしれません。34ピン式ドライブなら大体大丈夫なのかな?
オープンドレインの場合、READ DATA信号については、500〜1kΩ程度の抵抗で3.3Vにプルアップし、なるべく短いケーブルで接続した方が良さそうです。倍密度ディスクではあまり気にしなくても大丈夫なようで、手元のセットアップでは外部プルアップなしでも読めましたが、2HDだと駄目でした。GPIOの内部抵抗 (約50kΩ) によるプルアップのみだと、信号が鈍って隣り合うビットが分離できなくなるケースがあるようです。
手元のFDDでは1kΩの抵抗で5Vにプルアップしてあるようです。直結すると3.3Vになりましたが、降下分の電流はどこに流れてるんでしょう。GPIO出力のシンク電流はデフォルトでは最大8mAということですが、こういう接続を想定した値なのかはよくわかりません。またドライブによってプルアップ抵抗値はまちまちのようです。幸い今のところは壊れていないようですが……。
また、GPIOが入力設定の状態で直結すると5Vがそのままかかります。Raspbianでは初期状態が入力設定なので、直結するなら出力に設定した後でFDDの電源を入れるようにした方が無難でしょう。後述の読み書き手順の場合は、スクリプトを走らせた後で電源を入れることになります。自分はあまり気にせず電源入れちゃってますが…。繰り返しますが、直結はおすすめはしません。
$ sudo apt-get update $ sudo apt-get upgrade $ sudo apt-get dist-upgrade
$ sudo apt-get install raspberrypi-kernel-headers
$ make
ドライバは最低限の機能しか持っていません。insmod gpiofd.koとした後、デバイスファイル /dev/gpiofd に対してデータの読み書き (read/write) がかかると、フロッピーに対して1トラック分のアクセスを行います。GPIO端子の設定、モーターのON/OFF、シーク、サイド選択といった動作はドライバでは関知しておらず、ユーザーランドで行う前提です。アクセスはdd bs=524288 count=1のように十分大きなバッファサイズを指定してトラックごと各1回で行います。後述の読み書き手順では、スクリプト側でこれらの操作を行っています。データ形式は、INDEX信号を起点としたREAD DATA信号の時間をns単位に直して4バイトデータとして記録し、最後に一周したINDEX信号の時間も記録します。また、2HD書き込み時には書き込み補償 (write precompensation) を行っています。
時間計測は、ARMタイマーをフリーランニングモードで使っています。Raspberry Pi A+だとコアクロック250MHzなので、4nsごとに+1するカウンターとして使えます。最初は「じゃあ4nsの時間精度で読み書きできるんだ!」と思ったのですが、残念ながらそううまくは行かないようです。GPIOのアクセスには一回あたり数十nsかかるので、それより良い精度は出せません。バスの調停の問題らしいので、ユーザーからはどうしようもないような気が。ちなみにコアクロック周波数は設定やRaspberry Piのモデルによって異なるため、1μsごとに+1するシステムタイマーを使い、トラックアクセスの度に測定するようにしています。
Wiring Piとcpufrequtilsが必要です。インストールされていない場合は、以下を行っておいてください。
$ sudo apt-get install wiringpi cpufrequtils
./fd.sh r 2hdとします。sudoの権限が必要です。
to_d88 <type> [-r rpm] [outfile]です。typeは1d/1dd/2d/2dd/2hdのいずれか、rpmのデフォルトは300、outfileのデフォルトはfd.d88です。300rpmのドライブで読んだデータであることを前提に変換を行います。試していませんが、-r 360とすれば300rpmのドライブを使ってもPC-98用なんかのデータを変換できるかもしれません。メッセージが大量に出るので、変換エラーがないかチェックするなり/dev/nullに放り込むなりしましょう。
from_d88 [-r rpm] [infile]です。rpmのデフォルトは300、infileのデフォルトはfd.d88です。300rpmのドライブを使用することを前提に変換を行います。試していませんが、-r 360とすればPC-98用なんかのデータを300rpmのドライブで書き込めるように変換できるかもしれません。また、回転数を少しだけ遅くすれば、標準より多くのデータを詰め込むことも可能です。
./fd.sh w 2hdとします。sudoの権限が必要です。
./unformat.sh 2hdとします。sudoの権限が必要です。
トップ > 雑多なもの > Raspberry Pi A+のGPIOを用いた3.5インチフロッピーのリード/ライト実験