shotaのマイクロマウス研修11[ESP32でMPU9250とSPI通信する]


こんにちは、shotaです。

社員研修として、オリジナルマウスの製作を始めます。

[前回の記事]ではオリジナルマウスの仕様を決めました。

今回はタイトルの通り、ESP32で9軸センサMPU9250とSPI通信をします。

 

確認すること

できあがったプログラムがこちらです

n分クッキングみたいですが、先に完成したプログラムと通信結果を紹介します。

プログラムは[GitHub]に公開しています。[ESP-IDFのサンプル]をもとに作成しました。

WHO_AM_I(0x75)の応答のみを実装しています。

 

通信結果はこちらです。MPU9250からの返答0x71が確認できます。


$ make monitor

~~~ 省略 ~~~

I (267) cpu_start: Pro cpu start user code
I (285) cpu_start: Starting scheduler on PRO CPU.
I (0) cpu_start: Starting scheduler on APP CPU.
MPU ID: 71


SPI通信信号をロジアナで確認した結果がこちらです。

ESP32からの送信信号0xF5(Readビット(0x80) + WHO_AM_I(0x75))と、MPU9250からの返答0x71が確認できます。

また、通信クロック500 kHzも確認できます。

それでは、このプログラムができるまでの過程をここに書きます。

 

開発環境の導入からHello Worldまで

は、省略します。公式ページを見れば実施できるため、ここには書きません。

[ESP-IDF Programming Guide]Get Startedから開発環境(ESP-IDF)を導入してください。

私は、Linux(Xubuntu 16.04)に開発環境を作りました。使用するESP32のボードは[ESP32-DevKitC-32D]です。

 

ESP32のSPI機能について確認

まず、[公式ドキュメント]や、[Technical Reference Manual][データシート]を閲覧することを推奨します。

ここでは、引っかかった項目をピックアップします。

 

4つのSPIモジュールがある (が、2つしか使えない)

SPI0、SPI1、VSPI、HSPIがありますが、SPI0とSPI1は内部のフラッシュメモリに接続されているため使用できません。

今回のプログラムではHSPIを使用しました。

 

8bit以外のデータを送るとき要注意

[公式ドキュメントのTips]にあるTransactions with integers other than uint8_tを参照してください。

ESP32のSPI通信では、1バイトずつMSB firstモードで送信されます。

例えば、送信バッファに0x15 (0b0000 0101) が格納されてる時、8bit サイズで送信すると 0 0 0 0 0 1 0 1 という順番でデータが送信されます。

ところが、このデータを5bit サイズで送信すると、 0 0 0 1 0 が送信されます。 0b00101 ではないのでご注意ください。

基本8bitサイズでデータを送るので、この問題には直面しないと思います。

 

しかし、16 bit ( あるいは32bit) のデータを送信するときは更に注意です。

ESP32は[リトルエンディアン]で設計されています。 例えば、送信バッファに0xABCD という16bitのデータを格納した時、メモリ上ではCD ABの順番で保存されます。

そのため、0xABCD を送信したつもりでも、実際はC D A B の順番で送信されています。

この対策として、データの順序を変換する[SPI_SWAP_DATA_TX]と、[SPI_SWAP_DATA_RX]というマクロが用意されています。

実際に使用した例がこちらです。(GitHubのコードと同じです)

    uint16_t tx_data = (address | READ_FLAG) << 8;
    tx_data = SPI_SWAP_DATA_TX(tx_data , 16);
    t.tx_buffer = &tx_data;

    ret=spi_device_polling_transmit(spi, &t);  // Transmit!
    assert(ret==ESP_OK);            // Should have had no issues.

    uint8_t data = SPI_SWAP_DATA_RX(*(uint16_t*)t.rx_data, 16) & 0x00FF; // FF + Data

    return data;

まず16bitの領域(tx_data)に 0xF500を格納します。 0xF5は、WHO_AM_Iのアドレス0x75 + Readビット0x80です。

このままだと、メモリ上では00 F5という順番で格納されているので、送信の順番も00 F5になってしまいます。

これを、SPI_SWAP_DATA_TXをつかって変換します。変換後は、 F5 00 という順番でメモリに格納されます。

 

受信データも同様に変換します。センサモジュールからはFF 71 という順番で応答が返ってきますが、受信バッファには 71 FFという順番で格納されます。

これを、SPI_SWAP_DATA_RXを使って、FF 71 の順番に変換します。

 

GPIOマトリックスとIOMUX

[GPIO matrix and IOMUX]に書かれているように、GPIOマトリックスを使用すると、40MHz以上で通信できません。高速通信をしたい場合はIOMUXピンを使用してください。

そもそも、GPIOマトリックスとIOMUXとは何なのか?については、[こちらの記事]が参考になりました。

GPIOマトリックスによって好きなピンに機能を割り当てられますが、通信速度の制限がかかります。

 

今回はIOMUXピンでSPI通信を確認した後、IOMUX以外のピンを使ってみます。

 

MPU9250とESP32の接続

9軸センサモジュール MPU9250は[こちらのモジュール]を使います。

オリジナルマウスで使用予定の[ICM-20648]とピン互換であるため、職場の先輩からお借りしています。

※MPU9250は[新規設計非推奨]です。ご注意ください。

[MPU9250のデータシート]を参考に、ブレッドボード上で配線しました。

MPU9250ピン ESP32ピン ESP32機能
VCC 5V 5V
GND GND GND
AD0 / SDO 12 MISO
SDA / SDI 13 MOSI
SCL / SCLK 14 CLK
nCS 15 CS

プログラムの作成

プログラムの全体は[GitHub]のコードを参照してください。

ポイントは以下のとおりです。

  • MPU9250のSPIクロックは最大1MHz。今回は500kHzを設定する。
  • MPU9250のSPIモードは3。[SPIモードとは]
  • MPU9250のSPI通信は16クロックサイクル(以上)で行われる。前半8サイクルでアドレス+R/Wビットを送信し、後半8サイクルでデータを送信する。

通信結果は記事の最初のとおりです。

 

IOMUXピン以外を使ってみる

ピンの割当を以下のように変更します。これらのピンはHSPIのIOMUXピンではありません。

MPU9250ピン ESP32ピン ESP32機能
VCC 5V 5V
GND GND GND
AD0 / SDO 16 MISO
SDA / SDI 17 MOSI
SCL / SCLK 18 CLK
nCS 19 CS

※参考ピンアサイン [https://ht-deko.com/arduino/pic/esp32_devkitc_pinout_01.png]

ピン割り当て以外に、通信速度も500kHzから1MHzに変更します。GPIOマトリックスを使用しても、40MHzまでは速度が出せるので通信できるはずです。

プログラムは以下のように変更しました。


#define PIN_NUM_MISO 16 // 12
#define PIN_NUM_MOSI 17 // 13
#define PIN_NUM_CLK 18 // 14
#define PIN_NUM_CS 19 // 15

/* ----- 省略 ----- */
 spi_device_interface_config_t devcfg={
.clock_speed_hz=1000*1000, //Clock out at 1 MHz
.mode=3, //SPI mode 3
.spics_io_num=PIN_NUM_CS, //CS pin
.queue_size=7, //We want to be able to queue 7 transactions at a time
};

通信結果がこちらです。MPU9250からの返答0x71が確認できます。

$ make monitor

~~~ 省略 ~~~

I (267) cpu_start: Pro cpu start user code
I (285) cpu_start: Starting scheduler on PRO CPU.
I (0) cpu_start: Starting scheduler on APP CPU.
MPU ID: 71

SPI通信信号をロジアナで確認した結果がこちらです。

ESP32からの送信信号0xF5(Readビット(0x80) + WHO_AM_I(0x75))と、MPU9250からの返答0x71が確認できます。

また、通信クロック1 MHzも確認できます。

 

今回のまとめと、次回やること

今回のまとめです。

  • ESP32でSPI通信できました
  • 好きなピンをSPIに割り当てられました

次回こそは、マウスの設計方針を書きます。


Posted in DCマウス研修, ブログ, 研修