ショウのマイクロマウス研修

ショウのマイクロマウス制作-Part10

ショウのマイクロマウス研修

こんにちは、ショウです。
前回は1チャンネルのAD変換を設定しました。
今回は連続してAD変換を行います。STM32にはAD変換を連続的に行えるDMAという機能を使用してAD変換を行います。

DMA(ダイレクトメモリアクセスコントローラ)はCPUを介さずにメモリマップペリフェラルやメモリの間でプログラム可能なデータ転送を実行します。とリファレンスマニュアルに書いてあります。これによってCPUの処理を通さずにデータ転送ができます。
ADCの処理が終了したタイミングでDMAを行うことでADCの結果をメモリに保存します。

そのための設定をCubeMXでしていきます。

CubeMX

今回はADC1を使って変換を行います。ピンはPA0、PA1、PB12を使います。(PA0はADC2から変更)
Parameter Settingsのclockなどの設定は前回と同じです。
違うところはScan Conversion、Discontinuous Conversion、DMA Continuous Requests、Number of Conversion、RankのChannelです。
まずNumber of Conversionを一回のループで変換する回数に設定します。今回は3回変換を行うので3に設定しています。
RankのChannelはどこのピンをAD変換するかを設定しています。
Scan ConversionをEnableにすると連続変換ができるようになります。
Scan ConversionはNumber of Conversionが2以上の時にEnableにできるようになります。
DMA Continuous RequestsをEnableに設定します。
Discontinuous Conversionは変換開始をソフトから実行する場合に設定します。
ちなみにContinuous Conversionは変換終了をすると自動的に次の変換を開始します。

DMA SettingsのタブをクリックしてAddを押してDMAの設定をします。
Addを押すとDMA RequestでADC1を選択します。
Increment AddressのMemoryにチェックを入れます。これは連続してDMAを行う時に毎回保存するメモリを指定せずに、一回目に指定されたメモリの次のメモリに書き込みを行ってくれる設定です。
ModeをCircularに変更します。これはDMAをNumber of Conversionの回数行った時に最初の変換に戻るようにしてくれる設定です。

NVIC Settingsのタブに移動して、DMA1 channel1 global interruptのEnableにチェックを入れます。

これでDMAの設定はできました。

LLライブラリを使った複数チャンネルADC

ADC1の初期化を行います。
1チャンネルのADCと同じようにLL_ADC_Enable関数で有効化します。

DMAを一度停止させて、停止させている間に設定を書き込みます。
DMAの割り込みの有効化とDMAのデータの取得場所と転送先の指定、とデータサイズの指定をします。

設定が終わったらDMAを再開させます。

void ADC1_Start(void)
{
  LL_DMA_EnableIT_TC(DMA1,LL_DMA_CHANNEL_1);
  LL_ADC_Enable(ADC1);

  LL_DMA_DisableChannel(DMA1,LL_DMA_CHANNEL_1);

  LL_DMA_ConfigAddresses(DMA1,LL_DMA_CHANNEL_1,LL_ADC_DMA_GetRegAddr(ADC1,LL_ADC_DMA_REG_REGULAR_DATA),
                         (uint32_t)&adcConvertData,LL_DMA_DIRECTION_PERIPH_TO_MEMORY);

  LL_DMA_SetDataLength(DMA1,LL_DMA_CHANNEL_1,ADC_CONVERT_DATA_BUFFR_SIZE);

  LL_DMA_EnableChannel(DMA1,LL_DMA_CHANNEL_1);
}

LL_ADC_REG_StartConversionを実行するとRankに設定した順番でADCを行ってくれます。

stm32g4xx_it.cの中にDMA1_Channel1_IRQHandler関数が用意されます。その中でTCIFビットを確認し、TCIFビットが立っていたらTCIFビットのクリアを行います。

void DMA1_Channel1_IRQHandler(void)
{
  /* USER CODE BEGIN DMA1_Channel1_IRQn 0 */
  if(LL_DMA_IsActiveFlag_TC1(DMA1) == 1){
  LL_DMA_ClearFlag_TC1(DMA1);
  }

  /* USER CODE END DMA1_Channel1_IRQn 0 */

  /* USER CODE BEGIN DMA1_Channel1_IRQn 1 */

  /* USER CODE END DMA1_Channel1_IRQn 1 */
}

動作確認

PA0とPA1に前回と同じようにAD変換用の分圧抵抗をつけてテストします。

PA0は前回と同じ1kと2.2kで分圧しています。
PA1の方は1k抵抗2つで分圧しています。
TIM5_IRQHandlerの中でLL_ADC_REG_StartConversionを実行します。
mainの中でAD変換の結果を確認するとこのようになりました。
今回は分圧の計算をしていないのでAD変換の値をそのまま表示しています。

左からPA1、PA0、PA11の順で3回分のデータを取得できています。PA11は何もつないでいないので値が大きく揺れています。

これでDMAを使った連続変換ができるようになりました。

参考URL

STM32 + LL でADCでDMAを使用した複数チャンネル変換を動かしてみる | Sora's Activity Record
STM32マイコンのペリフェラル関連記事を一覧にまとめました。 前回はADCのシングル変換を行いました。 複数のデータを取りたいときや、ロボコンロボットの情報取得用センサーなどアナ...
Nucleo開発メモ(ADCを使う)
STM32F303K8というマイコンボードをシンセモジュール作りに使ってみようという話です。今回はADCを使ってボリュームつまみの値を読み取る話です。 今回はNucleoボードのA0ピンとA1ピンに可変抵抗を繋ぎ、可変抵抗の1-2端子間の電圧をAD変換によって取得し、それらの値でボード上のLEDの点滅速度を変える、とい...
タイトルとURLをコピーしました