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を外付けにすることで、十分な精度と送信頻度を達成することができた。