STM32L010をADコンバータとして使用して入力デバイスを試作し、評価した。結果はかなり良好であった。

概要

現在、ゲーム用の自作の入力デバイスをいろいろと試作中である。

BLEでPCと通信させるのが便利そうなので、最初はマイクロビットを使ってみたが、これは入力情報の送信頻度を上げることが難しかった。

次に、M5Stamp Picoを使ってみた。こちらでは送信頻度はかなり上げることができた。しかし、ボリュームの位置情報を検出するのに、内蔵のADコンバータを使ったところ、あまり精度が良くならなかった。

そこで今回は、ADコンバータを外付けする形で構成し、試作、評価してみた。

STM32マイコン

外付けのADコンバータとして採用したのが、STM32マイコンである。

一般的なADコンバータICではなくSTM32マイコンとした理由は、主に価格である。STM32L010は現在、秋月電子で100円以下で購入できる。

また、このチップは非常に使い慣れている物であり、自作のモジュール基板も所持しているため、試作するのにとても使いやすかった。

STM32の方のソフトも作成する手間はあるものの、AD変換をしてデータを送信するだけの簡単なものである。一度作ってしまえば手直しもほとんど必要ない。

そういったわけで、まずはSTM32をADコンバータとして、評価してみることにした。

構成

前回はM5Stamp Picoを使用したが、今回は同じESP32であるESP32-WROOM-32Eを使用した。M5Stampはどうやら値上がりしてしまったようだし、WROOMのDIPモジュールが使いやすそうだったので使ってみた。

STM32は自作のモジュールである。モジュール内にレギュレータを実装して3.3Vを生成しているので、電源ノイズの影響はかなり少ないはずである。ボリュームにかける電圧は、STM32の端子から出力している。これは、自作モジュールの回路的な問題である。

STM32とESP32の間は、SPIで通信させている。STM32側がマスターである。SPIであれば十分な速度が出せるし、STM32側にタイミングを制御させることで、AD変換に影響が出ない期間で通信させることができる。

STM32のソフト

STM32での処理は、10msごとにAD変換を行い、結果をSPIで送信するというものである。AD変換の精度に影響が出にくいように、AD変換にはDMAを使ってCPUをスリープさせるようにした。

ADCの設定
  • Continuous Conversion : Disabled
  • Discontinuous Conversion : Disabled
  • DMA Continuous Requests : Disabled
  • End Of Conversion : End of sequence
  • Sampling Time : 39.5 Cycles
  • External Trigger : Timer 2 Trigger Out event
  • External Trigger Conversion Edge : rising edge
  • NVIC : Enabled

TIM2でトリガをかけて、2チャンネル分をDMAで自動的に変換し、終了時に割込みで復帰して処理する。毎回TIM2でトリガをかけるので、繰り返しにはしない。

DMAの設定
  • Mode : Normal
  • Increment Address : Memory
  • Data Width : Half Word

繰り返しにしないので、DMAの方もNormalの設定で良い。

TIM2の設定
  • Prescaler : 31
  • Period : 9999
  • Master/Slave Mode : Disable
  • Trigger Event : Update Event

プリスケーラで1MHzにして、10msごとにイベントが発生するようにPeriodを設定している。タイマの割込みは必要ない。

SPIの設定
  • Mode : Full-Duplex Master
  • Frame Format : Motorola
  • Data Size : 8 Bits
  • First Bit : MSB First
  • Prescaler : 8
  • CPOL : High
  • CPHA : 2 Edge
  • NSS Signal Type : Software

SPIのモードは、MODE3と呼ばれているものである。NSS(CS)はソフトの方で制御するようにしている。こちらはDMAも割込みも使わず、ポーリング処理で送信するようにしている。

処理の概要

メインループ側の処理としては、TIM2とADCを開始したら、スリープに入るだけである。HAL_SuspendTickで止めておかないと、SysTickで起きてしまうので注意が必要。

スリープには、HAL_PWR_EnterSLEEPMode(0, PWR_SLEEPENTRY_WFI) で入る。

HAL_ADC_ConvCpltCallback で、SPIの送信処理を行う。終わったら次のADCの開始をして戻り、メインループ側でまたスリープに入ることになる。

ESP32のソフト

ESP32側の処理は、SPIのスレーブ受信と、BLEの処理である。arduinoのESP32SPISlaveというライブラリを使用した。

データの受信を待って、受信が完了したら処理を開始する形である。データを文字列に変換して、BLEで送信している。

評価

評価には自作のBLEデバイステストアプリを使用した。

まず送信頻度であるが、これは設計どおりに、毎秒100回となっているようである。まったく問題ない。

精度の方も十分であった。マイクロビットのときと同様に、1024段階の出力で、値が1だけ振れるかどうかという結果である。

まとめ

STM32をADCとして使う構成で、問題なく動作させることができた。

想定どおり、ADCを外付けにすることで、十分な精度と送信頻度を達成することができた。