2023年7月30日日曜日

自作CPUで遊ぶ 3

ZUMI32でHDD用のスピンドルモータを制御してみた。使用したモーターはジャンクのHDDから抽出したやつで電極が4つある。各電極間の電気抵抗を測ると1つの電極に対して他の3つの抵抗値が同じになるのでコイルはスター型の接続になっているようだ。 FPGAの出力でモーターのコイルを直接ドライブ出来ないので、Power FETを介してドライブした。ちょうど手持ちにSanKenのFKI10531というFETがあった。このFETはVGS(th)が2.0V (typ)なのでFPGAで制御するのに都合が良い。
3相モーターなので駆動は2つのコイルを同時にONにしその状態を順繰りに切り替えていく方式にした。CPUからの制御はタイマー割り込みを使用して割り込みハンドラ内で行うようにした。 何発のパルスでモーターが1回転するのか不明だったので割り込み周期を1秒にしてパルス数と回転の関係を見たところ12個のパルスでモーターが1回転することが判った。 市販のHDDの回転数は5400rpm〜7200rpm位のようだが、今回使用するモーターが載っていたHDDの回転数は不明だ。仮に5400rpmとすると1秒で 5400÷60 = 90 回転 (90Hz、11.1ms)となる。 このモーターを5400rpmで回すには 90Hz × 12 = 1080Hz 、ほぼ 1ms 周期でパルスを発生させる必要がある。つまり、割り込み周期は1msだ。 実際に、その周期でモーターを駆動してみると脱調して回らなかった。パルスモーターと同じように台形駆動(最初は低速で駆動し徐々に回転数を上げていく)が必要なようだ。 色々試してみたところ、パルス周期を30msecから初めて徐々に周期を短くしていくやり方で2.1msecまでは駆動できた。しかし、それ以下にすると脱調してしまう。 円板の有無でも変わるのかも知れない。
CPUの方はまったく問題無い。普通に使えている。

2023年7月23日日曜日

FPGAでLチカ (Spartan7の場合)

ZUMI32でモーターやA/D、D/A等の制御実験をやってみたくなり、ジャンク箱から使えそうな部品を取り出してきた。
DCモーターやHDDのスピンドルモーターや、I2C I/FのA/D、D/A、温度センサやサーミスタ、ペルチェ素子などがあった。やはり人生持つべきものはジャンク箱だ。 DCモーターのPIDによる回転数制御などもやってみたいと考えている。 以下は仮組みした状態。DCモーターの回転数をロータリーエンコーダで測り、PWMでDCモーターを制御する。
この他にも、スピンドルモータの制御やペルチェ素子の制御(温調)などもやってみたいと考えているが、今日は別のことをやってみた。

以前、このブログでFPGAでLチカというのをやった。FPGAの中にリングオシレータを作りその出力でLEDを点滅させるというものだ。 これをCMODS7のSpartan7でもやってみた。 
Vivadoでこの方法でインプリできるのか興味があったのだが、やってみたらインプリできた。 但し、XDCに set_property CLOCK_DEDICATED_ROUTE FALSE [get_nets BTN0_IBUF] という制約を書く必要があった。 トランスペアレントラッチの数だが、色々と試行した結果、このやり方の場合は14600個が上限だった。CMODS7に搭載されているSpartan7はxc7s25csga225-1で、このデバイスのFF数は29200個だがFFでなくラッチとして使う場合は14600個が上限のようだ。
上記を合成&インプリした結果が以下。
FFの使用率は50%だがSLICEとしては全部使われている。
得られた出力波形が以下だ。
周期が15.6usecなので1素子当たりの遅延は単純計算で 15.6/2/14600 ≒ 0.534[nsec] となる。したがって、素子1個のリングオシレータにした場合は約1GHzのクロックが生成できそうだ。 Spartan7のデータシート DS189によるとスピードグレード -1 のCLBのトグル周波数 FTOGは1098MHzとなっているので、ほぼこの値に近い。
リングオシレータを1素子にし、その代わりにそれをGBUFを通してクロックとして2048個のFFによるリングカウンタを駆動して出力が得られるかを見てみたところ出力がトグルしなかった。 次に素子数を2にしてやってみたらこちらは出力された。
周波数は約192.4KHzだった。これの2048倍がクロック周波数になるので 192.4×2048 ≒ 393.2MHzとなった。これはリングオシレータの素子数が2の場合なので、1の場合はこの2倍で786.4MHz。 何故か、最初に求めた値より若干低い。 

この場合はリングカウンタを使ったが、このようにラッチではなくFFとして使う場合は上限がカタログ通りのFF数までは使えるようだ。以下のようにリングカウンタのbit数を29188個にしてもインプリできた。インプリ後のUtilizationを見るとFFの数が何故か29194になっていた。
上記は29188bitのリングカウンタの値を101010.... にしており、これを発振可能な最大周波数で駆動している。このときの消費電流を見たら635mAも流れていた。 素子数を半分にすると406mA、さらに半分にすると239mAになった。電流はUSBの電流を見ている。

2023年7月17日月曜日

自作CPUで遊ぶ 2

今時のデバイスだと、うちの子はどの位の周波数までいけるのかを見てみた。 具体的にはCMOD S7というSpartan7を搭載したDigilentの評価ボード向けにデザインを作ってVivadoでインプリしてタイミングエラーにならないギリギリの周波数を探した。 このCMOD S7はxc7s25csga225-1が実装されている。
インプリするアーキテクチャは以下のようにした。ZUMI32のペリフェラルはINTC(割り込みコントローラ)、TIMER、GPIO (LED & SW)、命令用メモリは8KByte、データ用メモリは4KBとした。 左側のUARTとUIは命令メモリとデータメモリにプログラムをダウンロードするためのモジュールでありZUMI32からはアクセス出来ない。
タイミングエラーにならないギリギリのクロック周波数を探った結果、上限は113MHzだった。但し、これはFPGAのスピードグレードが-1の場合であり、-2だと140MHzまでmetした。 このデザインはリソース使用率が低く、Physical viewを見るとかなり散らばって配置されているので、もっとリソース使用率が高いデザインにするともう少し上の周波数まで行けるんじゃないだろうか? という気がする。
ZYNQでも同様にしてやってみた。以下のようなアーキテクチャにした。 デバイスはxc7z010clg400-1だ。
このデザインでの上限は100MHzと、驚いたことにSpartan7よりも低い値になった。しかし、physical viewを見ると中身はスッカスカでありこれがクロック周波数を下げている要因では無いかという気がする。 もっと混んだデザインにするとmetする周波数は上がるんじゃないだろうか。
最新のデバイスではないが、Lattice MachXO2でもやってみた。ターゲットデバイスはLCMXO2-7000HC-4TG144Cにした。 結果は49MHzが上限だった。リソースの使用率は30〜40%位だった。スピードグレードを5にした場合は53MHzに上がった。
CMOD S7に戻って、プログラムを作って動かしてみた。CMOD S7には3色LEDが1つ、単色LEDが4つ搭載されているのでタイマー割り込みで単色LEDをナイトライダー風に点滅させるプログラムにした。 フォアグラウンド側はmain()でタイマーの初期設定後、割り込みを許可し、その後 while(1); ループに入る。後はタイマーに設定した周期で割り込みが入るので、割り込みハンドラーでLEDの点滅処理を行う。 このプログラムを-O2最適化オプションでコンパイルして得られたサイズは命令部が1992Byte、データ部(固定値)が24Byteだった。
実機で動かす前にシミュレーションで確認してみる。
※.シミュレーションでは割り込み周期を10usに短縮した。
上図の通りフォアグラウンドは while(1); で無限ループしているので、フォアグラウンド実行時のPC(プログラムカウンタ)は同じ番地を指している。 割り込みを検出すると割り込みベクタアドレス0x00000020をフェッチし、そこから割り込みハンドラに分岐し、処理が終わると割り込み前の番地に戻っている。
実機動作

動作周波数については、ちょっと物足りなさを感じるが全く使い物にならないレベルでは無い。 50MHz以上なら遊びに使うにはまぁまぁ十分ではないかと思う。
プログラム開発は、PC上でCでプログラムを書いてコンパイルして動かすのと同等の手順で出来る。
出来上がったマシン語列は今回のように実機にダウンロードして動かすようにも出来るし、ROM化(命令メモリに初期値として設定)することも出来る。難点はデバッグ用の仕組みをまだ入れていないことだが、今の所特に支障は無い。

このCPUでモーターとかアクチュエータを動かしてみたり、装置のユーザーインタフェース部の処理をさせたりしてみたいもんだ。


2023年7月8日土曜日

自作CPUで遊ぶ

前回まででスコア表示機能の追加が出来た。iCE40LMボードやブロック崩しゲームで次にやってみたいことや作ってみたいことが色々と頭に浮かんでいるのだが、このテーマは一旦お休みして次は自作CPUで遊んで見ることにした。

11年位前にこのブログで32bit CPU(zumi32)を開発した。このCPUはハーバード・アーキテクチャのRISC型32bit CPUで、パイプライン数は3段だ。割り込みや例外にも対応している。レジスタは17個ありR0は値0の固定値、R15はPC(プログラムカウンタ)、R1からR14は汎用レジスタだ。この他に割り込みや例外発生時の戻り番地を格納するEPCレジスタも持っている。フラグはキャリーフラグとゼロフラグを持っている。命令実行のスループットは、load/store/swapを除いて1命令/1cycleで実行する。分岐時は最小でも2サイクルパイプラインがストールする。また、分岐は遅延分岐になる。乗除算命令は持っていないが、その代わりにシフト命令(バレルシフタ)を持たせた。プログラム開発は、CPU開発時に簡易アセンブラも作って当初はそれでプログラムを作成していた。その後、C言語でもプログラミング出来るようにしたくなったのだが、独自の命令セットにしたので既存CPU用のGCCを流用することが出来ずにgcc-4.5.2をzumi32用にポーティングした。GCCの資料が難解でこれには1〜2年ぐらいかかった。
当時はzumi32をインプリしたデザインをSpartan3E、Spartan6、Cyclone IIIに実装して動かした。 割り込みも使えるのでファグラウンドでマンデルブロート集合を描画し、タイマ割り込みでを使ってその中に周期的に文字列を描画させたりしていた。マンデルブロート集合の計算は固定小数で計算した。
zumi32はSYSCALL(ソフトウェア例外)命令も実装したので、次にリアルタイムモニタ(FreeRTOS)を実装してみた。マンデルブロート集合を描画するタスクと、FPGAボードのLEDを点滅させるタスクの2つのタスクを動かし、フォアグラウンドのIdleタスクでは別のLEDを点滅させた。この実装でzumi32の遅延割り込みのバグが見つかったが無事修正できた。
・・・と、長々と説明してきたが、今度はこのCPUで何か作って動かしてみたいと考えている。




2023年7月2日日曜日

iCE40LMボードで遊ぶ 3

一応フォントのデザインは出来たのでこのデータをiCE40LMのBRAMの初期値データに変換した。BRAMに初期値を設定してROMとして使う。 この初期値の設定方法だがiCEcube2の場合はインスタンスするBRAMのParameterとして設定する必要がある。そのため、Cのchar型の配列としてフォントを定義し、プログラムでこれをパラメータ文に変換した。
で、最終的に出来たfont_romのコードがこれ。
このゲームはVRAMを使っていない。syncgenはHSYNCやVSYNC等のVIDEO同期信号を生成しているが、掃引している座標値も同時に出力している。 ゲームの各部はこの座標値と自分の座標位置を常に比較しており、自分の領域に来たらフラグを立てる。ビデオデータ出力段はこれらのフラグを見て最終的に出力するデータを決定している。フォントの表示もこの方法で処理している。
以下は、実際に動かしたところ。フォントは16x16にして正解だった。8x8だと小さすぎて見にくかっただろうと思う。 表示している内容だが、右上は消したブロックの数にした。左上の数字はゲームの残り回数だ。このゲームは元々5回まではブロックの状態を引き継いでゲームを続けられるようにしていたので、その残り回数を表示するようにした。この値が0になると全ブロックが復活する仕様だ。
RTLの合成は成功した。タイミングエラーも出ていない。リソース使用率もまだまだ余裕がある。
以下は動作環境。奥の3段重ねの基板はiCE40LMのConfigROMプログラム用の基板だ。一番上のボードにFT2232HLが載っている。Lattice DiamondのProgrammerを使って書き込む。左下の赤黒のコードが付いている黒い物体はゲーム開始用のプッシュスイッチだ。その右側はビープ音再生用のスピーカー。さらにその右側はラケット(バー)を左右に動かすためのロータリーエンコーダーだ。
で、実際にプレイしてみた。実に楽しいのだが、自分の反射神経が驚くほど衰えていることに愕然としている。実機評価にならない(笑)。でも、なかなか楽しい。

ということで、文字表示は成功した。 \(^_^)/

自作CPUで遊ぶ 25

まだ制御ソフトが完成していないので今まではスピンドルを移動するために一々簡単なプログラムを書いて移動させていたのだが、非常に面倒なのでCNCペンダント的なものを作ることにした。 右側の縦に2つ並んでいるスイッチ...