4
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

MPU9250をSPIで使用する方法

Last updated at Posted at 2020-04-04

MPU9250

9軸のセンサー
磁気3、ジャイロ3、加速度3軸持つセンサー

I2C、SPIどちらの通信でも可能。
SPIによる方法を説明する

データシート
ハードウェア https://invensense.tdk.com/wp-content/uploads/2015/02/PS-MPU-9250A-01-v1.1.pdf
レジスタ https://cdn.sparkfun.com/assets/learn_tutorials/5/5/0/MPU-9250-Register-Map.pdf

接続

|MPU9250 |expression |Arduino:マイコン |
|---|---|---|--- |
|Vcc |3.3V | 3.3V |
|GND |GND |GND |
|SCL|SPI-clock|CLK:13|
|SDA|Data Input|MOSI:11|
|EDA|センサを追加する場合|NoConection|
|ECL|に使用する|NoConection|
|ADO|Data Output|MISO:12|
|INT|割り込み出力らしい|NoConection|
|NCS|ChipSelect|CS:10|
|FSYNC|不明|GNDにしておけば良いらしい|

5V-3.3V変換はよくわからない。
変換を入れなくても、入れてもちゃんと動作した事例がある。
しかし、入れた結果、電圧が足りないのかArduino側が判定しない(ロジアナで見るとデータが出てるのに)事例があった。

変換ICを持っていない場合は直で繫いで試しても良いと思う
持っている場合は付けて見て、だめなら外しては試して見ると良いと思う

SPI

通信モードは3、立ち上がりラッチ、基本SCK状態はHIGH
SCL周波数は、読み込みのみなら20MHzまで
書き込みもする場合は1MHzにすると良いらしい(1MHzで動いた)

SPIプロトコル

読み込み
CS->HIGH
アドレス8bit(アドレスの先頭ビットが1=Read,0=Write )
空データ8bit送信と同時に受信
CS->LOW

書き込み
CS->HIGH
アドレス8bit(アドレスの先頭ビットが1=Read,0=Write )
書き込みデータ8bit
CS->LOW

動作確認プログラム:MBED用

# include "mbed.h"
# include "Serial.h"


Serial pc(USBTX, USBRX); // USBシリアルポートのインスタンス

SPI spi(D11,D12,D13);
DigitalOut cs(D10);

int main() {
    spi.format(8,3);
    spi.frequency(1000000);
    cs=1;
    
    pc.baud(250000);
    
    cs=0;
    int val = spi.write(0xF5);
    val = spi.write(0x00);
    cs = 1;
    
    pc.printf("START\r\n");
    pc.printf("%8x \r\n",val);

    
    while(1){
        
    }
}

これで、71が読み込めている場合、通信成功。
プログラムは、アドレス0x75(WHO_AM_I)を読み込んでいる。
正確には、Readなので先頭ビットを1にしてアドレス0xF5を読んでいる。

動作確認:arduino用

# include <SPI.h>
# include<avr/io.h>
# include<avr/interrupt.h>

# define cs 10

void setup() {
  pinMode(cs,OUTPUT);  //2020.4.09 追加
  SPI.setBitOrder(MSBFIRST);  //最上位ビット(MSB)から送信
  SPI.setClockDivider(SPI_CLOCK_DIV4);  //通信速度をデフォルト
  SPI.setDataMode(SPI_MODE3);   //アイドル5Vで0V→5Vの変化で送信する
  SPI.begin();  //開始
  Serial.begin(250000);
  
}

void loop() {
  byte data = Read(0x75);
  Serial.println(data, HEX);
  delay(100);
}

void Write(byte address, byte data) {
  digitalWrite(cs, LOW);
  SPI.transfer(address);
  SPI.transfer(data);
  digitalWrite(cs, HIGH);
}
byte Read(byte address) {
  digitalWrite(cs, LOW);
  SPI.transfer(address | 0x80);
  byte data = SPI.transfer(0);
  digitalWrite(cs, HIGH);
  return data;
}

0x71が読めれば、成功です。

ジャイロ、加速度読み込みプログラム

# include <SPI.h>
# include<avr/io.h>
# include<avr/interrupt.h>

# define cs 10

void setup() {
 pinMode(cs,OUTPUT);  //2020.4.09追加
  SPI.setBitOrder(MSBFIRST);  //最上位ビット(MSB)から送信
  SPI.setClockDivider(SPI_CLOCK_DIV4);  //通信速度をデフォルト
  SPI.setDataMode(SPI_MODE3);   //アイドル5Vで0V→5Vの変化で送信する
  SPI.begin();  //開始
  Serial.begin(250000);
  byte data = Read(0x75);
  Serial.println(data, HEX);
  delay(100);
}

void loop() {
  byte dataH = Read(0x3B);
  byte dataL = Read(0x3C);
  int AX = dataH << 8 | dataL;

  dataH = Read(0x3D);
  dataL = Read(0x3E);
  int AY = dataH << 8 | dataL;

  dataH = Read(0x3F);
  dataL = Read(0x40);
  int AZ = dataH << 8 | dataL;


  dataH = Read(0x43);
  dataL = Read(0x44);
  int GX = dataH << 8 | dataL;
  dataH = Read(0x45);
  dataL = Read(0x46);
  int GY = dataH << 8 | dataL;
  dataH = Read(0x47);
  dataL = Read(0x48);
  int GZ = dataH << 8 | dataL;


  if (AX > 32768) {
    AX = AX - 65535;
  }
  if (AY > 32768) {
    AY = AY - 65535;
  }
  if (AZ > 32768) {
    AZ = AZ - 65535;
  }
  if (GX > 32768) {
    GX = GX - 65535;
  }
  if (GY > 32768) {
    GY = GY - 65535;
  }
  if (GZ > 32768) {
    GZ = GZ - 65535;
  }

  //if(Flag == 1){
  Serial.print(AX );
  Serial.print(" ");
  Serial.print(AY );
  Serial.print(" ");
  Serial.print(AZ );
  Serial.print(" ");

  Serial.print(GX );
  Serial.print(" ");
  Serial.print(GY );
  Serial.print(" ");
  Serial.print(GZ );
  Serial.println(" ");
}

void Write(byte address, byte data) {
  digitalWrite(cs, LOW);
  SPI.transfer(address);
  SPI.transfer(data);
  digitalWrite(cs, HIGH);
}
byte Read(byte address) {
  digitalWrite(cs, LOW);
  SPI.transfer(address | 0x80);
  byte data = SPI.transfer(0);
  digitalWrite(cs, HIGH);
  return data;
}

mbedでもやりましたが、なぜか読めないバイトがあったりして難しいので止めました

各種設定について

sleep解除、スケール設定、LPF、出力周波数設定を上記ではしていません。
しなくてもなぜか動きました。I2Cで使うなら必要なはずなのですが・・・
初期設定では
+-250dps,+-2g,1kHz更新 っぽいです
ジャイロの感度設定

  Write(0x1B,0x00);   //250dps
  Write(0x1B,0x08);   //500dps
  Write(0x1B,0x10);   //1000dps
  Write(0x1B,0x18);   //2000dps

ローパスフィルタのカットオフ周波数設定
F_CHOICEは00にしておけばOK(デフォルト)
デフォルト250Hz

  Write(0x1A, 0x06);  //gyro LPF5Hz
  Write(0x1A, 0x03);  //gyro LPF41Hz
  Write(0x1D, 0x03);  //acce LPF45Hz

加速度計の感度設定

Write(0x1C, 0x04);  //acce +-4g
Write(0x1C, 0x10);  //acce +-8g
Write(0x1C, 0x14);  //acce +-16g

使うやつ以外をコメントアウトすれば使えます(確認済み)

追記:Arduino Dueを使用する場合

DueにはSPIが一つあり、ICSPヘッダのみから利用できます。Pin13,12,11はSPIピンにはなりません。Arduino-Due-Pin-mapping.png
この図の中央の6本のオスヘッダのSCK,MOSI,MISOにさして利用します。
プログラムは#includeの部分の

forArduinoDue
# include<avr/io.h>
# include<avr/interrupt.h>

を除くことで動作できます。

# include <SPI.h>

# define cs 10

void setup() {
  pinMode(cs,OUTPUT);
  SPI.setBitOrder(MSBFIRST);  //最上位ビット(MSB)から送信
  SPI.setClockDivider(SPI_CLOCK_DIV32);  //通信速度をデフォルト
  SPI.setDataMode(SPI_MODE3);   //アイドル5Vで0V→5Vの変化で送信する
  SPI.begin();  //開始
  Serial.begin(250000);
  byte data = Read(0x75);
  Serial.println(data, HEX);
  delay(100);
}

void loop() {
  byte dataH = Read(0x3B);
  byte dataL = Read(0x3C);
  int AX = dataH << 8 | dataL;

  dataH = Read(0x3D);
  dataL = Read(0x3E);
  int AY = dataH << 8 | dataL;

  dataH = Read(0x3F);
  dataL = Read(0x40);
  int AZ = dataH << 8 | dataL;


  dataH = Read(0x43);
  dataL = Read(0x44);
  int GX = dataH << 8 | dataL;
  dataH = Read(0x45);
  dataL = Read(0x46);
  int GY = dataH << 8 | dataL;
  dataH = Read(0x47);
  dataL = Read(0x48);
  int GZ = dataH << 8 | dataL;


  if (AX > 32768) {
    AX = AX - 65535;
  }
  if (AY > 32768) {
    AY = AY - 65535;
  }
  if (AZ > 32768) {
    AZ = AZ - 65535;
  }
  if (GX > 32768) {
    GX = GX - 65535;
  }
  if (GY > 32768) {
    GY = GY - 65535;
  }
  if (GZ > 32768) {
    GZ = GZ - 65535;
  }

  //if(Flag == 1){
  /*
  Serial.print(AX );
  Serial.print(" ");
  Serial.print(AY );
  Serial.print(" ");
  Serial.print(AZ );
  Serial.print(" ");
*/
  Serial.print(GX );
  Serial.print(" ");
  Serial.print(GY );
  Serial.print(" ");
  Serial.print(GZ );
  Serial.println(" ");
}

void Write(byte address, byte data) {
  digitalWrite(cs, LOW);
  SPI.transfer(address);
  SPI.transfer(data);
  digitalWrite(cs, HIGH);
}
byte Read(byte address) {
  digitalWrite(cs, LOW);
  SPI.transfer(address | 0x80);
  byte data = SPI.transfer(0);
  digitalWrite(cs, HIGH);
  return data;
}

image.png
SPIの通信速度は

SPI.setClockDivider(SPI_CLOCK_DIV32);

で4MHzクロックになってました。

追記: Arduino Mega接続

|MPU9250 |expression |Mega |
|---|---|---|--- |
|Vcc |3.3V | 3.3V |
|GND |GND |GND |
|SCL|SPI-clock|CLK:52|
|SDA|Data Input|MOSI:51|
|EDA|センサを追加する場合|NoConection|
|ECL|に使用する|NoConection|
|ADO|Data Output|MISO:50|
|INT|割り込み出力らしい|NoConection|
|NCS|ChipSelect|CS:53|
|FSYNC|不明|GNDにしておけば良いらしい|

4
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?