2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

Nucleo F303K8 ADC で複数チャンネルを読む w/STM32CubeIDE

Last updated at Posted at 2023-08-19

ADCをもう少しだけ深く使ってみます。

以前複数チャンネルADCで苦労した記憶がありますので,自分のまとめとして書いておきます。

2つのチャンネルを一つずつ読む

テストのため,PA3とPA4 PA5とPA1を接続し,DAの出力をADで読みます。

PIN Arduino STM32
 7    A5     PA6 DAC2_OUT1 UnBuffer
 8    A2     PA5 DAC1_OUT2 UnBuffer --+
 9    A3     PA4 DAC1_OUT1 --+        |
10    A2     PA3 ADC1_IN4  --+        |
11    A1     PA1 ADC1_IN2  -----------+
...

ADC1 IN2 と IN4 を有効にします。

image.png

  • Scan Conversion 複数チャンネルをADすることのようです。Enable
  • Continuous は連続してADする場合。Disable
  • なぜか Discontinuous の設定項目もある。とりあえず Disable
  • DMA まずは Disable
  • End Of Conversion Selection いつ EOCフラグを立てるかの設定のようですね。1チャンネルごとにしたいので End of single conversion

image.png

  • Regular と Injection 2つの ADC があって,とにかく普通のは Regular です。
  • Number Of Conversion を 2 にすると,その下でやっと Channel 2 と 4 が出てきます。わかりにくいですが仕方ないですね。

image.png

main.c
  /* USER CODE BEGIN 2 */

  HAL_DAC_Init(&hdac1);

  HAL_DAC_SetValue(&hdac1, DAC1_CHANNEL_1, DAC_ALIGN_12B_R, 0x800);
  HAL_DAC_Start(&hdac1, DAC1_CHANNEL_1);

  HAL_DAC_SetValue(&hdac1, DAC1_CHANNEL_2, DAC_ALIGN_12B_R, 0x80);
  HAL_DAC_Start(&hdac1, DAC1_CHANNEL_2);

  HAL_ADCEx_Calibration_Start(&hadc1, ADC_SINGLE_ENDED);

  uint16_t result[8]= {0};

  HAL_ADC_Start(&hadc1);

  while ( !(ADC1->ISR & (1<<2)) ) {} // wait until EOC is 1
  result[0]=HAL_ADC_GetValue(&hadc1); // ADC1 channel 4 = DAC1 channel 1

  while ( !(ADC1->ISR & (1<<2)) ) {} // wait until EOC is 1
  result[1]=HAL_ADC_GetValue(&hadc1); // ADC1 channel 2 = DAC1 channel 2

  HAL_ADC_Start(&hadc1);

  while ( !(ADC1->ISR & (1<<2)) ) {} // wait until EOC is 1
  result[2]=HAL_ADC_GetValue(&hadc1); // ADC1 channel 4 = DAC1 channel 1

  while ( !(ADC1->ISR & (1<<2)) ) {} // wait until EOC is 1
  result[3]=HAL_ADC_GetValue(&hadc1); // ADC1 channel 2 = DAC1 channel 2

  /* USER CODE END 2 */

実行結果

image.png

DMAを使う場合

EOC設定をEnd of sequence of conversion にします。すべてのチャンネルを変換し終わったら,という感じですね。

image.png

DMA設定を追加します。

image.png

8要素の配列を用意しましたが,HAL_ADC_PollForConversion のあと,最初の2個に結果が入ります。

main.c
  uint16_t result[8]= {0};

  HAL_ADC_Start_DMA(&hadc1, (uint32_t *)&result, 2);

  HAL_ADC_PollForConversion(&hadc1, HAL_MAX_DELAY);

その後,再度 HAL_ADC_Start_DMA(&hadc1, (uint32_t *)&result, 2); して結果を待てば,再び result[0] result[1] に結果が入りました。

HAL_ADC_Start_DMA(&hadc1, (uint32_t *)&result, 2); では 2ch分読むように指定しているのですが,最後の引数を4にしたらどうなるでしょうか。結果,2ch分だけ,result[0]result[1]が更新されて戻ってきていました。

HAL_ADC_PollForConversion しない場合はどうなるのでしょうか。深くは検証できませんでしたが,DMAが終わっていれば結果が正しく入っていました。

たとえばAD前に準備が必要で,変換のタイミングを自分で決めたい場合にこの方法は有効ですね。

連続で変換する

要するにほったらかしでDMA結果を参照すればその時までに変換転送された値が読めるというものです。

Continous と DMA Continuous を Enable にします。EOCは single conversion にします。

image.png

Sampling Time を大きくします。ここでは61.5 Cyclesにしました。(理由はあとで)

image.png

DMA Mode を変更します。

image.png

main.c
  /* USER CODE BEGIN 2 */

  // DAC設定1 省略

  HAL_ADCEx_Calibration_Start(&hadc1, ADC_SINGLE_ENDED);

  uint16_t result[8] = {0};

  HAL_ADC_Start_DMA(&hadc1, (uint32_t *)&result, 2);

  // break 1 DAC設定1 が読める

  // DAC 設定 2 省略

  HAL_Delay(10);

  // break 2 DAC設定2 が読める

  // DAC 設定 3 省略

  HAL_Delay(10);

  // break 3 DAC設定3 が読める

  /* USER CODE END 2 */

result[0]result[1] を参照すればその時までにDMAされた変換値が入ります。

ADC の Sampling Time をあえて大きくしたのは,DMAが終了する前に次のADCが終了してしまい,フリーズのような状況に陥るのを防ぐためです。本当はきちんと計算しなくてはいけないのですが,システム 8MHz ADC は div 4 で設定した本件では 61.5 Cycles 必要だったということになります。

参考

2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?