Cmod A7ボード(FPGA)を使って、オリジナル16ビットCPUコアMoscoviumの開発を進めています。
独自仕様のマイコン(ハードウェア面)だけではなく、その開発環境(ソフトウェア面)としてBlockly for Moscoviumの整備も進めてきました(詳細はこちらから)。今回は、BlocklyでI2C通信を使うための拡張を実施します。
ハードウェアとしては、過去に同期二線式シリアル通信STWSERユニットを設計しました。
ソフトウェア🍦としては、アセンブラでWireライブラリを整備済みです。詳細は以下記事からご覧ください。
「#17-5 I2Cを使いたいの」
「#17-6 I2Cマスタ通信」
これらの成果物をBlockly for Moscoviumに対応させて行きます。
Blocklyに追加すべきブロックについて、以下の通りとします。
目標仕様:
I2Cマスタデバイスに限定する事で、ずいぶんと簡潔にまとめられそうです。
前節の目標仕様に基づき、以下の様なカスタムブロックを作成しました。これをWireブロック(群)と呼ぶことにします。
詳細仕様に関しては、Blockly for Moscoviumマニュアルでご確認ください。
Blockly.XML→Moscovium.ASM変換スクリプトを更新すると共に、Wireライブラリを追加しました。まとめて、こちらからダウンロードしてください。
以下のバナーからGitHubを参照しても、必要ファイルにアクセスする事が可能です。
Blockly for Moscovium開発環境の構築については、こちらの記事をご参照ください。
デザイン(回路)をCmod A7ボードに書き込む手順については、こちらをご確認ください。
次に、機能検証を兼ねたサンプルプログラムの作成に進みます。
Arduino用として過去作成したC言語プログラム(smbus_master.ino)が有ります。これに相当するプログラムをBlocklyで作成しました。以下にリンクしておきます。
完成プログラム:blky_smbus_master.xml
※ブラウザによっては、XMLファイルをレンダリングして表示してしまうので、「右クリック ⇒ リンク先を保存」などしてください。
Blockly for MoscoviumのXMLタブに貼り付けて、ご利用ください。Blockly.XML→Moscovium.ASM変換手順を参照して、Moscoviumマイコンに書き込んでください。
Moscoviumマイコンが起動すると、シリアルモニタから以下のコマンドを受け付ける様に、なっています。
シリアルモニタコマンド仕様:
SMBus準拠のプロトコルが使えるので、大抵のモジュールにはアクセスが可能です。I2Cバス上にぶら下がったスレーブデバイスのスキャンもできるので、新しいデバイスを接続した時の最初のデバッグや動作確認などにも使えて、有用なプログラムであるはずです。
前節に示したプログラム中で、I2Cバス上のスレーブアドレスをスキャン(【scan】コマンド)するために、対象スレーブアドレス+書き込みビットだけのプロトコル(書き込みも読み出しも実施しない)を使っています。このような特殊なプロトコルを、「I2Cフレーム」を直接生成して作成しました。
I2Cフレーム仕様についてはこちらをご参照ください。
指定されたI2Cフレームを実行するブロックとしては、wire frameブロックを用意してあります。
以下、順を追って使い方を簡単に説明しておきます。
実際にBlocklyで作成した関数を下図に抜粋します。
I2Cフレームを自分で作ることができるようになると、ブロックとして用意されたSMBus準拠アクセスだけではなく、複数バイトのバーストアクセスや、ロングワードアクセス等のプロトコルを自由に作成して使うことができます。そのサンプルとしてご活用ください。
ここからは、Cmod A7ボード(FPGA)へ実際に書き込んで実験して行きます。
STWSERユニット(I2C通信)を搭載したマイコン(例えば、MBOC115BY1608等)をCmod A7ボードへ書き込んでください。Vivadoのプロジェクトは、こちらのGitHubからダウンロード(バナーをクリック)することができます。
続いて、Cmod A7ボードへ適切なI2C通信モジュールを接続しましょう。本ページでは、9軸加速度・ジャイロ・磁気センサMPU9250モジュールを使って見ようと思います(下図)。
MPU9250にはMCM(Multi-Chip Module)として磁気センサチップAK8963が内蔵されています。MPU9250のデータシートはこちらから検索して見つけてください。
何本か固定すべき信号線があるので、こちらの接続表に従って接続しましょう。実験中の様子を以下図に示します(写真は使い回し)。
以下、実験サンプルに従って実験を進めて行きます。
実験サンプル:【 】内はシリアルモニタからの送信データ
【slv,68,1】
OK: slave=0x68, as big endian
MPU9250のスレーブアドレス=0x68へのアクセス指示と共に、第二引数「1」によって、ビッグエンディアンを指定しました。MPU9250には16ビットサイズのデータレジスタがあり、ビッグエンディアンです。
第二引数を「0」とするか、あるいは省略すると、リトルエンディアンのモジュールへアクセスできます。ちなみに、MCMのAK8963はリトルエンディアンです。
【swr1,37,02】
OK: swr1[0x37]=0x02
MPU9250内に集積されたAK8963にアクセスを通すため、MPU9250のI/OレジスタINT_PIN_CFG(0x37)のBYPASS_ENビットに1(0x02)を立てました。
【scan】
OK+ +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +a +b +c +d +e +f
00: -- -- -- -- 0c -- -- --
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
60: -- -- -- -- -- -- -- -- 68 -- -- -- -- -- -- --
70: -- -- -- -- -- -- -- --
OK: scan
I2Cバスをスレーブアドレス0x08〜0x77までスキャンして見ました。
MPU9250のスレーブアドレス=0x68と、磁気センサチップAK8963のスレーブアドレス=0x0cが見つかりました。
【srd1,75】
OK: srd1[0x75]=0x71
MPU9250のI/OレジスタWHO_AM_I(0x75)を読み出しました。読み出したデータ0x71は、MPU9250のIDコードと一致しています。……読み出し成功です。
【srd2,3b】
OK: srd2[0x3b]=0xffc0
【srd2,3d】
OK: srd2[0x3d]=0xffb0
【srd2,3f】
OK: srd2[0x3f]=0x4028
MPU9250から、加速度センサのx,y,zレジスタ(I/Oレジスタアドレス0x3b〜0x40、各16ビット符号付整数レジスタ)を読み出しました。
デフォルト設定の2gレンジなので、以下式で加速度へ換算可能です。
読み出し値を使って計算してみると以下の通りです。
加速度ベクタ=(0xffc0,0xffb0,0x4028)=(−0.038,−0.048,9.824)[m/s2]
机の上などに平に置いた状態ならば、上例の様に、z軸方向に重力加速度g=9.8[m/s2]が検出され、x,y軸方向は0近傍の値が読み出せるはずです。エンディアンの指定が間違っていたりすると、上例の様に読み出せないはずなので、試してみてください。
手持ちのセンサモジュールにはI2Cで通信するタイプのモジュールが複数存在します。上の様な簡単なプログラムなので、アセンブラでも作れない事は無いですが、Blocklyでプログラミングできる様になったことで応用が利くし、活用の幅が広がりました。