ADCのDMA転送モードを試してみた

アナログ入力が少ない場合はあまり問題になりませんが、例えば複数のセンサを取り込んでデジタル処理する場合、順番に読み出しを行う方法では効率がよくありません。

このような複数の入力(マルチチャネル)の場合はDMA転送を行うと処理がすっきりします。STM32F334のADCコントローラにはDMA転送のモードがありますので今回はこれを試してみます。

また、単にDMAモードにするだけでは面白くないので、もういっちょう光センサ(CdSセル)をアナログ入力につっこんでみたいと思います。

準備するもの

まずNucleoボードに光センサを接続します。前々回、前回から追加で必要なものを列挙します。

  • CdSセル(仕様不明)
  • 抵抗(10KΩ)
  • クリップ付きジャンパー線
CdSセル

CdSセルはご覧のような形をしており、光の量に応じて抵抗値が変わる素子です。この素子と抵抗で分圧したものをアナログ端子に入力します。回路図としてはこんな感じになります。

回路図2

PA0は前回使いましたので、今回はPA1を使用します。仕組みとしてはCdSセルに当たる光の量によって抵抗値が変化し、3.3Vが分圧されPA1の電圧が変化します。

各パーツを接続する

CdSセルと抵抗を直接Arduinoのコネクタに差し込みます。結線が必要なところはクリップケーブルで接続しました。

可変抵抗器接続

ちょっと写真ではごちゃついて分かりにくいですが、これでちゃんと回路図通りに結線されています。それではソフトウェアの作業に移ります。

再びSTM32CubeIDEでADCを設定する

STM32CubeIDEを起動して、ADCの入力追加とDMAの設定を行います。左のツリーから「adc.ioc」をダブルクリックします。

Device Configuration Toolが開きますので、ADC1をクリックしIN2の設定を「IN2 Single-ended」に変更します。

ADCの設定1

ここで、IN2の色が黄色になっています。何か警告色のようですが、マウスポインタを持っていくと、画面のようにUSARTとコンフリクトしているようです。

ADCの設定2

詳しくは分かっていませんが、たぶん同時に使用できないモードなのだと思いますのでUSART2を禁止します。「Connectivity」を開いて「USART2」をクリックし、Modeを「Disable」にします。

ADCの設定3

再びIN2を見てみますと、まだ黄色のままです。これはどうやら「Differential」に設定したときの警告のようですので無視します。

次はADCの下側のタブにある「DMA Settings」の設定を行います。と言いますのは、ADC側のDMA転送を有効にしようと思ったときに、こちらの設定をまず行わないと変更できなかったためです。「DMA Settings」のタブをクリックして、「Add」ボタンを押します。

ADCの設定4

DMA Requestを「ADC1」に設定し、DMAの転送先をリングバッファにするため、Modeを「Circular」に設定します。

ADCの設定5

次は「Parameter Settings」のタブをクリックしてADCの設定を行います。まず、DMA転送を有効するために「DMA Continuous Requests」を「Enable」に設定します。

ADCの設定6

前回と同様にIN2を有効にすることで「Rank 3」の設定が追加されていますので、変換数を「Number Of Conversion」で3に設定します。次にRank 3の設定では「Channel」と「Sampling Time」をそれぞれ「Channel 2」と「601.5 Cycles」に変更します。

ADCの設定7

これで一通りの設定は終わりです。保存すればコードジェネレーターで、新たな設定がソースコードに反映されます。

DMAでの値の読み出し

次はADCの読み出し部分を変更します。ソースコードは以下のようになります。

DMAでの読み出しコード

むちゃくちゃシンプルになりました。DMAはバッファを用意しておけば、スタートさせるだけで変換を自動的に繰り返しやってくれます。

HAL_ADC_Start_DMA(&hadc1, (uint32_t*)gu_dma, 3);
    AD変換を開始し、値を指定バッファに指定個数分DMA転送します。

バッファとして「gu_dma」を配列宣言しています。この変数の要素の0、1、2にそれぞれ、内蔵温度センサ、PA0、PA1の値が格納されます。ですので、値の読み出しは、

gu_temp = gu_dma[0];
gu_ain0 = gu_dma[1];
gu_ain1 = gu_dma[2];

でOKです。それでは、これをビルドしてリアルタイムモニタで確認してみます。

リアルタイムモニタで確認する

前回と同様にPALMiCE4を起動し、リアルタイムモニタのウィンドウから、追加ボタンを押して「gu_ain1」を登録します。設定は前回と同じです。

RTM設定

プログラムを実行してみましょう。下の赤い線が可変抵抗器によるアナログ入力で、真ん中が内蔵温度センサ、上の緑の線が今回追加したCdSセルによるものです。CdSセルの値は何もしなくても若干のばらつきがあるようです。

RTMの表示1

CdSセルを手で覆い隠すと、抵抗値が上がって電圧変化が起こります。同時に可変抵抗器も変化させてみました。

RTMの表示2

にぎやかです。グラフが思い通りに反応していますので、ADCのDMA転送はうまく行ったようです。CdSセルは反応が分かりやすいのでやってみるとクセになります。実際に動いている様子を動画にしました。

リアルタイム・モニタ機能でアナログ入力を見える化

DMAは難しそうと思っていましたが、実際やってみるとコーディングがシンプルにできて簡単でした。もっとたくさんのセンサを接続するときも利用できそうです。

今回でSTM32のアナログ入力の記事は終了しますが、今後の予定としてSTM32でFreeRTOSなどの検証もやって行きたいと思っています。