きっかけ
最近、Raspberry Pi とI2Cセンサーを接続してそのデータを表示するアプリケーションをTMSSoftware WebCore(の中の Miletus)を用いて作成しています。
しかしどうせなら使い慣れているPCアプリケーションとしても作成したいと考えました。
TMSSoftware Blog(Miletus brings Raspberry Pi target in Delphi)
https://www.tmssoftware.com/site/blog.asp?post=843
TMSSoftware Blog(Tracking High Altitude Balloons with Delphi and TMS Miletus)
https://www.tmssoftware.com/site/blog.asp?post=1021
Honeywell HMC6352 (2軸、I2C) デジタルコンパスモジュールを Delphi から使いたい
数年前に購入して埃をかぶっていた Strawberry Linux の HMC6352 デジタルコンパスモジュール(2軸、I2C)を Arduino や Raspberry Piではなく Delphi から使ってみます。
Honeywell HMC6352 は、2軸磁気抵抗センサーと方位計算に必要なアナログおよびデジタルサポート回路、マイクロプロセッサ、アルゴリズムを組み合わせた完全統合型コンパスモジュールです(HMC6352データシートより)。
Strawberry Linux の製品ページ
https://strawberry-linux.com/catalog/items?code=12106
HMC6352データシート
https://strawberry-linux.com/pub/HMC6352A.pdf
1. Windows10 PC からI2Cデバイスへアクセスする
良いデバイスはないかなあとネット検索していてこちらのブログを参考にさせて頂きました。
ArduinoやRaspberry Pi のように直接接続することはできませんので今回は通販ショップ エレファインから購入した
Devantech社のUSB-I2C interface moduleを使用しました。
このUSB-I2Cインターフェイスを用いることでシリアル通信経由で HMC6352 と簡単にI2C通信できるソフトウェアを作成することができます。
[仕様]
- USB I2Cマスターに変換
パソコンのUSBに接続し、I2Cマスターとして使用することができます。 通信速度は、100kHz固定です。 - 複数のI2Cデバイスを接続することができます。
- バスマスターとしてのみ使用できます。SCLとSDAは、4.7kΩでプルアップされています。バス電圧は、5Vです。
- Widows 7でも使用可能 Windows XPはもちろん、Windows 7 32ビット、64ビット、Windows 2000、Windows MEでも使用できます。
- Linux, Mac OSにも対応
Mac OS8, OS9, OSXにも対応しております。 - 仮想COMポートとして動作
パソコンのUSBに接続すると、仮想COMポート(VCP)として動作しますので、RS232C通信と同様になり、HID(キーボード等のHuman Interface Device)仕様のものと違って、比較的簡単にプログラムを作成することができます。
2. シリアル通信用コンポーネント
TMSSoftware の VCLコンポーネントである TMS Async を使いました。Single developper license で 80€です。
TMS ALL-ACCESS サブスクリプションに含まれています。
[TMS software ホームページの機能説明]
TMS Async は、Windows でシリアル ポートへのアクセスを提供するコンポーネントを含む通信パッケージです。イベント ドリブン アーキテクチャは最高のパフォーマンスを提供し、すべてのツールをバックグラウンドで実行できます。
1.Proven concept used multiple years already in lots of industrial applications
2.Advanced class object structure.
3.Advanced but easy to use design interface.
4.Optimized even t-driven architecture.
5.Provides the highest possible performance.
6.Supports all important transfer protocols.
7.Components to build advanced comport servers.
8.Easy to use with any type of serial hardware.
9.Links directly to your EXE, no runtime.
10.Built-in support for XModem, YModem & ZModem protocols
11.Codeless terminal component with extendable emulation interface
12.Component for codeless visualisation of status
3. USB-I2Cインターフェイスとの接続確認とコマンド
私の環境では FTDI FT232R USBチップ用のドライバーは自動的に読み込まれました。
-
ターミナルソフト
RS232Cテストツールを用いました。 -
COMポート設定
- ボーレート: 19200
- データビット: 8
- パリティ: None
- ストップビット: 2
-
コマンド
I2C_SGL: 0x53 -> Philips PCF8574 I/O チップなどnon-registered デバイス用の 1 バイトの読み取り/書き込み。今回の HMC6352 が該当
I2C_MUL: 0x54 -> アドレスを設定せずに複数のバイトを読み取り (EEPROM、Honeywell 圧力センサーなど) 今回の HMC6352 が該当
I2C_AD1: 0x55 -> 1 バイトのアドレス指定されたデバイスの単一バイトまたは複数バイトの読み取り/書き込み (ほとんどのデバイスがこれを使用)
I2C_AD2: 0x56 -> 2 バイトアドレスのデバイス、32kbit (4kx8) 以上の EEPROM の単一バイトまたは複数バイトの読み取り/書き込み
I2C_USB: 0x5A -> USB-I2C モジュールへのコマンド 0x01 を続けるとRevision Numberを返す -
Revision の確認(ターミナルソフトから送信)
送-> <5A><01>
->受 <9>
これで USB-I2CインターフェイスのFirmware Revision Number が帰ってきます。
今回は0x09が帰ってきましたので 9.0ということになります。
4. USB-I2CインターフェイスからHMC6352へアクセス
HMC6352 のデフォルトでは'A'を送ると方位データを2バイトで返してきます。
また送信後の Time delay が 6000 μsec 必要のようです
RS232Cテストツールから以下を送ります。
送-> <53><42><41> //間隔あける <54><43><02>
->受 <01><04><13>
0x53(I2C_SGL)はDirect Read/Write command
0x42は HMC6352のI2Cアドレス(8ビット)
0x41は Data byte で 'A'になります。
※上記でHMC6352に1バイトのデータをWriteします。書込レジスタアドレス指定は必要なし
次に HMC6352 からデータを受信します。
0x54(I2C_MUL)はRead multiple bytes without setting new address
0x43 はI2Cアドレス7bit+Write(=1)です
0x02 は2バイトのデータを読み取ります。
一連のバイトデータの間には少しDelayがないとうまくデータが返ってきませんでした。
ここでは3バイト帰ってきています。これはUSB-I2Cインターフェイスが先頭に読取り成功のフラグとして<01>を付加するからです。
つまりは残りの0x04, 0x13 が方位データということになります。
方位の算出方法は、データシートよりMSBの0x04 を左に8ビットシフトしてLSBの0x13を足すと10進数で 1043 となり、これを10で割った数値 104.3度が方位ということになります。
5. Delphi での実装とI2C通信のデバッグ
ここまでで方位データの読取りが確認できましたので実際にTMS Asyncを用いてコードを入力していきます。
ほとんどコンポーネントの機能を利用することで追加することは余りありませんでした。
しかしZEROPLUS社のArduino starter kit with Logic Analyzer 附属のロジックアナライザーを使用してUSB-I2CインターフェイスとHMC6352の間のI2C通信を解析することでスムースにデバッグすることができました。
ZEROPLUS社のロジックアナライザー(上)
・チャンネル数:8
・インターフェース:USB1.1(2.0対応)
・サンプリング周波数:
内部(タイミング):100MHz
外部(ステート):75MHz
ARDUINOスターターキットwithロジックアナライザ(秋月電子通商)
ロジックアナライザー自体は初心者向けに簡素化、機能制限がされているようですが素人の電子工作用途には必要十分なものでした。
デバッグ風景(緑丸印が USB-I2Cインターフェイス、赤丸印がHMC6352デジタルコンパス、その間にZEROPLUS社のロジックアナライザーを接続)
HMC6352は 5Vでも動いたのですがデータシート上はMax5.2vだったので双方向レベルコンバーター(FXMA2102)を挟んでいます。
procedure TForm1.ComPortSettings;
begin
// COMポート設定
VaComm1.Baudrate := br19200;
VaComm1.Databits := db8;
VaComm1.Stopbits := sb2;
VaComm1.Parity := paNone;
end;
3. HMC6352へコマンドを送信
コマンドの設定
var
Form1: TForm1;
CMD_A_SET: array [0 .. 2] of BYTE = (
$53, // USB-I2Cコマンド(I2C_SGL): 1バイト書き込み
$42, // HMC6352の I2C address: 0x42(7ビット+ 0(Write))
$41 // 'A'
);
CMD_GET_Direction: array [0 .. 2] of BYTE = (
$54, // USB-I2Cコマンド(I2C-MUL) 複数バイトを読み取る
$43, // i2cアドレス7bit+1(Read)
$02 // HMC6352から2バイト読み取る
);
///
/// HMC6352 へのコマンド
/// i2c address = 0x42(8bit)
procedure TForm1.btnSendClick(Sender: TObject);
begin
SendCommand;
Sleep(100);
end;
procedure TForm1.SendCommand;
var
OK: Integer;
begin
OK := 0;
VaComm1.PurgeReadWrite;
if not VaComm1.Active then
Memo1.Lines.Add('Can not open Com Port!!');
// ’A’コマンド(Get Data. Compensate and Calculate New Heading)
VaComm1.WriteBuf(CMD_A_SET, 3);
if not OK = length(CMD_A_SET) then
Memo1.Lines.Add('Writing Error!!');
// Directionデータの読み込み
OK := VaComm1.WriteBuf(CMD_GET_Direction, 3);
if not OK = length(CMD_GET_Direction) then
Memo1.Lines.Add('Writing Error!!');
end;
Sleep(100)と調整するとこちらの環境ではロジアナ上で良い結果が得られました。
4. WriteBuf()を呼び出すとVaCommコンポーネントのVaCommRxCharイベントが発生するので、バッファーから受信データを取り出す
procedure TForm1.VaComm1RxChar(Sender: TObject; Count: Integer);
var
LBuffer: array [0 .. 2] of BYTE;
LBufCount: Integer;
I: Integer;
RetOK: Integer;
MSB: Integer;
LSB: Integer;
Direction: Extended;
begin
MSB := 0;
LSB := 0;
Direction := 0.0;
// バッファーからの読取り
if VaComm1.ReadBufUsed > 0 then
begin
ReceivingPortNumberMsg;
LBufCount := VaComm1.ReadBuf(LBuffer, 3); // 3バイト読み取る
if LBufCount <> 3 then
begin
ReadErrorMsg;
end
else
begin
for I := 0 to 2 do
begin
if I = 0 then
begin
RetOK := LBuffer[I];
if RetOK = 1 then
DeviceResponseOK
else
DeviceNoResponse;
end
else if I = 1 then
begin
MSB := Integer(LBuffer[I]);
MSB := MSB shl 8;
end
else
begin
LSB := LBuffer[I];
end;
Memo1.Lines.Add('Buffer= ' + IntToHex(LBuffer[I]));
end;
CalculateDirection(MSB, LSB, Direction);
ShowDirectionMsg(Direction);
end;
end
end;
5. 方位の算出
procedure TForm1.CalculateDirection(MSB: Integer; LSB: Integer;
var Direction: Extended);
begin
Direction := (MSB + LSB) / 10;
end;
6. 結果の表示
7. (おまけ)COMポート設定
TMS Async では TVaConfigDialog コンポーネントを用いるとコードを書かずに簡単に設定変更ダイアログが出せて便利です。
まとめ
これまでは ArduinoやRaspberry Pi上でC++、Pythonを用いて細々と開発していたのですが、TMS Miletusを用いてDelphi IDE 上でそれ(Raspberry Pi)を行うことが出来るようになってきました。
それでもやはり使い慣れたWindows PC上でセンサーデータやI2Cデバイスの操作をしたいという気持ちもありました。
これからさらに容易にI2Cデバイスを扱えるようになると楽しみが広がりそうです。
コードについては趣味レベルですのであくまでご参考程度にお願いします。