stm32f405rg + hal ライブラリ を使用してmpu6500とお話する 

こんばんわ!

先日Twitterでアンケートを取ったところ需要があるという意見を多数いただいたので書いていこうと思います。

実際私自身もはまったのでそれも踏まえて書いていきたいと思います。

最初のstm32 cubeでの設定などに関しては下記のリンクなどを参照してください。

 

sora-siro.hatenablog.com

 

まず初めにmpu 6500 のデータシートを見て設定をするうえで必要そうなことが書いてある場所を探します。この記事では必要そうなところを大まかにピックアップして載せていきます。

いきなりこうだよねみたいな書き方をしていたらデータシートを各自でみて確認してみてください。データシートを読む練習?になると思います。

間違ってたらごめんなさい。ご指摘いただけばと思います。

まずは、MPU-6500 Product Specification Revision 1.1 のデータシートから読んでいきます!

f:id:sora_siro:20180915214208p:plain

このページを見ると、2000deg/s にするためには FS_SEL = 3, スケール調整をするために 16.4 で割ればいいということがわかりました。

f:id:sora_siro:20180915214628p:plain

ここをみるとspiの書き込み時は1MHz,読み込みだけなら20MHzまで対応していることがわかります。

先ほど設定したSPIの通信速度をみて間違っている場合は各自直しておきましょう。

f:id:sora_siro:20180915221511p:plain

パワーモードはこんな感じらしいです。

f:id:sora_siro:20180915215244p:plain

この前に通信の際にこのデバイスを指定するときはこのデバイスにつないでるcsPinをLowにしてあげて、このようにすればいいみたいです。

8bit 送って 8bit 送るという16bit 刻みでの通信を行う必要があるそうです。

まずは、アドレスを指定する8bitを送ります。

ただし、最上位ビットでR(Read)/W(Write) : bit 1 / 0 + アドレス、書き込みなら書き込む内容、読み込みならダミーを送信すればいいようです。

ここまでの内容から通信に必要なソースコードを書いてみると以下のようになりました。

読み込みは以下のようになります。

uint8_t read_byte( uint8_t reg )
{
uint8_t ret,val;
HAL_GPIO_WritePin( gyro_cs_GPIO_Port, gyro_cs_Pin, GPIO_PIN_RESET ); //cs = 0;
ret = reg | 0x80;
HAL_SPI_Transmit( &hspi2, &ret,1,100 ); // 読み込みアドレス
HAL_SPI_Receive( &hspi2,&val,1,100 );
HAL_GPIO_WritePin( gyro_cs_GPIO_Port,gyro_cs_Pin, GPIO_PIN_SET ); //cs = 1;
return val;
}

HAL ライブラリには SPI_Receive という便利な関数があったのでそれを使っちゃいました!

続いて書き込みです。

///////////////////////////////////////////////////////////////////////
// spi write 1 byte
// [argument] Register
// [Substitutiong] write data
// [return] nothong
///////////////////////////////////////////////////////////////////////
void write_byte( uint8_t reg, uint8_t val )
{
uint8_t ret;
ret = reg & 0x7F ;
HAL_GPIO_WritePin( gyro_cs_GPIO_Port, gyro_cs_Pin, GPIO_PIN_RESET ); //cs = 0;
HAL_SPI_Transmit( &hspi2, &ret,1,100 ); // 書き込みアドレス
HAL_SPI_Transmit( &hspi2, &val,1,100 );
HAL_GPIO_WritePin( gyro_cs_GPIO_Port,gyro_cs_Pin, GPIO_PIN_SET ); //cs = 1
}

書き込みのときは書き込みのアドレスが上位ビットだけ送信になるので ret = reg & 0x7Fとして最上位ビットは絶対に0になるようにしてます

これで書き込み、読み込みができました。続いてお話しするためには設定が必要になるみたいなのでそれを見ていきたいと思います。

 

次に、MPU-6500 Register Map and Descriptions Revision 2.1を見ていきましょう!

私はこのページに載っているアドレスで必要なものだけマクロ定義をしています。

すべてマクロ定義をしてもOKだと思います。

そうじゃないと確認する際に面倒だと思います。

 

さて、レジスタの詳しい内容を見ていきましょう。

今回設定やチェックをする必要がありそうな内容は

Who Am I ( 君の名は(映画は関係ありません) ) 0x70

2000deg/secに設定する

Z Axis を読み込む

パワー(ジャイロモード)をOnにする

データの出力を許可する

といったところだと思うのでこれらをできるようにそれぞれのレジスタに書き込んだり読み込んだりをできるようにしましょう

 

順番的には

Who Am I

パワーをON

データの出力を許可する

2000 deg / sに設定する

Z 軸のデータを読み込むといったところでしょうか?

 

まずは who am i からいきます。

who am i のレジスタを読みこむ。 以上

はい簡単ですね。

つづいてパワーをON にしましょう

adder 0x6B  PWR_MGMT_1

f:id:sora_siro:20180915222825p:plain

よし、すべてに0をいれれば動くということで0x00を代入します。

ソフトで表すと

write_byte( MPU6500_PWR_MGMT_1, 0x00 );

こんな感じです。

 データの出力を許可するの設定も同様にデータシートを見ていきます。

f:id:sora_siro:20180915223440p:plain

FIFO,LPFは使用する必要がないのですべてに0を代入してしまいましょう!

write_byte( MPU6500_CONFIG, 0x00 );

 

2000 deg / sec の設定の仕方も同様にして

f:id:sora_siro:20180915223725p:plain

2000 deg / sec にするためには 4:3 に 11 をたてればいいみたいです。

書き込む内容は0x18 ですね。

write_byte(MPU6500_GYRO_CONFIG, 0x18);

さて、ここまでで書き込みができたので次は読み込みをしましょう。

ジャイロのデータは16bit で一つのデータになりますが、なんどmpu 6500 は上位と下位でレジスタが分かれてしまっているためなんとかして16bitのデータにまとめる必要があります。なのでビットシフトとキャストを使用してデータの結合、取得を行います!

float MPU6500_read_gyro_z( void )
{
int16_t gyro_z;
float omega;

gyro_z = (int16_t)( ( read_byte(MPU6500_RA_GYRO_ZOUT_H) << 8 )
| read_byte(MPU6500_RA_GYRO_ZOUT_L) );
 
omega = (float)( gyro_z / GYRO_FACTOR);

return omega;
}

こんな感じになります。

gyro_z でジャイロのデータを読み込んで、omegaではdeg/sに直すために定数で割っています。

あとは割り込み関数内で

prev_omega, machine_degree は global変数なり,static でそのファイル内でのみの静的な変数なり毎回リセットされないようにして

now_omega = MPU6500_read_gyro_z();

machine_degree += ( now_omega + prev_omega ) / 2.0f * dt;

prev_omega = now_omega;

とでもすればマシンの角度が取得できると思います。

ただし、この生のデータの値を使用すると0点ドリフトに角度が影響を受けてすごい勢いで大きくなることや小さくなるといった現象に見舞われる可能性があるのでその場合はオフセットを入れましょう。

これは各自考えてみてください。

ヒントはデータをある一定周期で取得してそのデータを足し合わせて・・・です。

 

最後に

データシートはしっかり読みましょう( 自分への戒め )

 

知見のあるかたで、ここをこうしたほうがいいということがあればご指摘していただきたいです。よろしくお願いします。