[解決しました] STM32のADCで嵌った( MultiChannel 非連続 循環バッファ DMA TIM3駆動 )

DMAでADC開始した後にさらにADC開始をしていたために一回チャネルがずれてしまうことになったようだった。

pUart = &huart1;
HAL_ADC_MspInit(&hadc1);
HAL_UART_Receive_DMA(pUart, RdBuff, RCV_BUFF_SIZE); /* 受信開始 */
HAL_ADC_Start_DMA(&hadc1, ADC_BUFF, ADC_BUFF_SIZE*6);
HAL_ADCEx_Calibration_Start(&hadc1);
HAL_ADC_Start(&hadc1);

修正にいたる過程では6chのうち一つだけを増やしてサンプリングしたいということなどの要望がありDMAを使うものと割り込み駆動をするものとでトライしたがままならずDMAのみでサンプルするチャネルを当該のみ10倍にすることにした。この際に、バッファ段数の動的切り替えなどをトライする過程でADCとDMAの停止・取り込み再開の検討をする中で上記の点について気づきなおすことでトリガ単位で一つのチャネルをADC取り込みがなされることを確認できた。

HAL_ADC_MspInit(&hadc1);
HAL_UART_Receive_DMA(pUart, RdBuff, RCV_BUFF_SIZE); /* 受信開始 */
HAL_TIM_Base_Start(&htim3);
HAL_ADCEx_Calibration_Start(&hadc1);
HAL_ADC_Start_DMA(&hadc1, ADC_BUFF, ADC_BUFF_SIZE*15);

 

STM32のADCで嵌った( MultiChannel 循環バッファ DMA TIM3駆動 )

STM32F103を用いてADCを複数チャネル使い、常時計測を行い計測要求があった時点で過去10mS間の64回のデータを移動平均を取って処理報告制御するという処理を組んでいたのだが、STM32の持つDiscontinuousモードを用いて各チャネルを一回ずつ分割して順次TIM3のイベント周期で計測していくという形で計測をした。TIM3で25uS毎にイベントを出してADCが1chずつ計測していきDMAがサーキュラーバッファに格納していく。PA0にNucleoのGND/3.3Vを接続してバッファにどの様に入るのかを確認した。この使い方をすると、3.3V result on PA0 discontinuous modeの様にバッファの先頭に入るべきが2つ目に入る結果となった。

150uS周期に全てのチャネルを一気に計測するContinuous modeにして計測した結果は、3.3V result on PA0 continuous modeのようにバッファ先頭に入る形となった。期待値は、こちらなのでこのモードを用いる形にした。なぜズレるのかは不明だ。

ちなみにCubeMXは6.5.0でIDEはTrueStudio9.3.0でのケースなのでCubeMXでの問題があるのかも知れない。納入先の指定で開発環境が指定されているのでその範囲で対応と対策を試みて納品に漕ぎつけた。

 

STM32マイコンの評価ボードで開発支援

フリーランスでの仕事をいただくと実機前に適用マイコンに近い評価ボードで実装してみて開発環境に用いている。今回のマイコンはSTM32F103CBT6で128kBのFlashと20kBほどの組み込みマイコンではMidRangeのものだ。アーキテクチャの近いものとしてSTM32F103RBが搭載されているNucleo-103RBを用いて開発をしている。実際の機器との違いはピンアサインなど種々あるのだが、必要なI/Fについては割付先の違いくらいなのでコード生成機能(CubeMX)を用いて変更する程度で処理としては簡単に変更するのも最近のツール進化で楽になっている。

こうした評価ボード自体も、そのまま小規模なシステムに組み込んで用いてしまうことも多いのは昨今のチップ不足などもあり普通に見かける。評価開発にブレッドボードやArduino互換での端子なども含めて便利だからでもある。

ArduinoのAVRなどに比べるとARM-CoreM3が搭載されているこのボードは強力でクロックは72MHzまで高める事が出来るし内蔵の周辺機能も沢山集約されていてマイコンメーカーとして名をはせているST Micro社が世界に沢山出している人気マイコンでもある。

SPI/I2C/UART/ADC/TIMER/GPIOが多く搭載されているので、仕事でよくいただく測定器のファーム開発ではとても有用だし開発ボードにデバッガも組み込まれているのでUSBでPCと接続すればそのままソースコードをみつつ確認動作が出来る。USB一本でVCPチャネル経由でのアプリからの通信処理も確認できるので、主にシリアルコマンドで動作させることが多いのでこれも便利な一面だ。

さて、今回の開発では多くのアナログ信号のセンサ処理でフィードバックしたりセンサデバイスの線形補間処理も行って所要機能の精度確保を実現したりする必要もある。ADCからのデータ収集を一括して常時DMAで集信することも出来て処理としては過去のデータから移動平均を取るなどの作りこみも容易だ。ちなみに今回は6chを10ms周期にそれぞれ64回測定したものをオンデマンドで平均処理をして返送するという使い方だ。タイマから25uS周期でトリガを発生させて順次20uS程度の取り込み処理でADCがメモリ配列に取り込んでいく。DMAでサイクリックバッファに取り込むわけだ。

いろいろと稼働させていくと標準の動作クロック8MHzのままではリソース不足となりPLL設定のクロック割付にして高速にしていく。コアの速度・周辺クロックをそれぞれ調整して必要なものに変えていく。むやみに上げるとCMOS構造故に消費電力は周波数に比例して上昇する。USB接続で動作する構造のボードなので5Vから3.3Vのレギュレータを経て、300mA/100mAの二種の設定が出来るもののこれを越す場合には別途電源を供給する必要がある。USBハブの能力を上げてもこれは解決できない。しかしながら、このマイコン自体の消費電流からみても十分だということが分かった。ARM CortexM3クラスのマイコンなので消費電流は100mA程度に収まるらしい。拡張基板などを搭載したりする場合を除いては十分なものだろう。

今回は、デバッグ時点で応答しないという現象が多発して「Target not responding」というようなメッセージが出ていたのだが、評価基板の回路図と照らして間違ったIOの設定をしたりして端子同志がショートしたりといった事象が起きてしまったからのようだった。ともあれ。必要十分な低めのクロックを与えて消費電流を抑えることは必要だろう。コマンドとアイドルループ処理で凡そ0.6mS程度でソフトは回っているようだ。表示LEDにフリックを入れてオシロで確認できた。ADC以外にもシリアルコマンドの受信はDMAに任せていてコマンド処理ループ側で取り込みバッファからの読み出しで実行している。

測定器として接続されるのでホストからの処理を取りこぼしてはならないので、DMA任せにしているのは気楽だ。DACで出力した結果のADCを読みだす必要もあり、時間経過後に取り込んだADCバッファを移動平均処理したものを扱うには時間経過のポスト処理も必要だ。タイマ割り込みでの時間経過通知などで対応している。