Project_OKI’s diary

エンジニアの勉強ブログ

STM32マイコン24(DMAでAD変換)

STM32 (DMAでAD変換)

1.本日の内容

 (1) STM32マイコン(nucleof401re)を使用して、DMAを使用してAD変換を行う。

 

動作:

 

 ※AD変換のDMAとは

  複数のセンサの値を取り込みたい場合、

  通常のAD変換で変換し順番に読み出しを行うと、効率が悪く時間がかかる。

  そこで、複数の入力の対応や高速に処理したい場合、DMA転送を行うとよい。

 

  DMAは、Direct Memory Accessの略で、

  CPUを介さずにデバイス間でデータ転送を行うことができる技術のことである。

  CPUがデジタルデータを処理する必要がなくなり、処理速度が向上できる。

 

  AD変換時、DMAにより格納するためのメモリ領域を指定し、

  DMAコントローラによって自動的にデータを転送するように設定する。

  これにより、AD変換結果を高速かつ効率的に処理することができる。

 

・目次

 

2.内容

​​(1) やる内容の詳細​

 ・CubeIDEでAD変換及びDMAの設定を行う。

 ・AD変換を行い、PA4(A2)とPB0(A3)の電圧を読み取る。

 ・読み取った値をTeratermに表示する。

 

(2) CubeIDEの設定

 ・File→New ProjectでSTM32F401を選択し、新しいプロジェクトを作成する。

  →参照:CubeIDEの使い方(起動~デバック実行) - Project_OKI’s diary

 ・カウント確認用にprintfを使用する為、下記記事のUARTのピンを設定する。

  →STM32マイコン_2(UART通信:TeraTermにHellow表示) - Project_OKI’s diary

UART

 

 ・CubeIDEのAD変換とDMAの設定 (※CubeMXもCubeIDEも基本設定内容は同じ)

  (a) Pin設定画面のPA4をADC1_IN4、PB0をADC1_IN8に設定する。 

ADC設定1

  (b) Analog→ADC1を選択→DMA Settingタブに移動する。

  (c) Addを押し、DMA RequestをADC1に設定する。

 

ADC設定2(DMA設定)

  (d) Parameter Settingタブに移動し、下記設定にする。

項目 説明
Mode Independent mode
Clock Prescaler PCLK2 divided by 2
Resolution 12bit(15 ADC Clock cycles)
Data Alignment Right alignment
Scan Conversion Mode Enable
Continuous Conversion Mode Disable
Discontinuous Conversion Mode Disable。
DMA Continuous Requests Enable
End Of Conversion Selection EOS flag at the end of all conversions
ADC_Regular_ConversionMode  
Number Of Conversion 2
External Trigger Conversion Source Regular Conversion launched by software
External Trigger Conversion Edge none
Rank 1
 Channel Channel4
 Sampling Time 3 Cycles
Rank 2
 Channel Channel8
 Sampling Time 3 Cycles
ADC_Injected_ConversionMode
Number Of Conversions 0
WatchDog
 Enable Analog WatchDog Mod

 

ADC設定3


  (e) NVIC Settingタブに移動し、ADC1 global interruptのEnabledにチェックを入れる。

ADC設定4

   (g) System→NVICを選択し、ADC1 global interruptとUSART2 global interruptの

    Preemption Priorityを1にする。

ADC設定5

   (h) 黄色い歯車マークを押し、ソースの生成を行う。

   (i) main.cファイルが開かれたら、トンカチマークを押し、ビルドする。

   →エラーなどが出ないことを確認する。

 

(3) プログラムの作成

動作:

 ・以下の動作をループする。

 ・AD変換(DMA)スタート

 ・printfでPA4の値を出力

 ・printfでPB0の値を出力

 ・AD変換(DMA)終了

 ・1000ms待つ。

 

※printfについては、下記記事を参照。 

 この記事のprintf.c及びprintf.hを使用している。

 ・STM32マイコン22(printfのソースファイル、ヘッダファイルの作成)
main.c
/* USER CODE BEGIN Includes */
#include "printf.h"
/* USER CODE END Includes */
/* USER CODE BEGIN PD */
//AD変換の数
#define  ADSIZE 2
/* USER CODE END PD */
/* USER CODE BEGIN 0 */
//AD変換用変数の用意
uint16_t adcval[ADSIZE];
/* USER CODE END 0 */
  /* USER CODE BEGIN 2 */
  setbuf(stdout,NULL);
  printf("START");
  /* USER CODE END 2 */
    /* USER CODE BEGIN 3 */
	  HAL_ADC_Start_DMA(&hadc1,(uint32_t *)adcval,ADSIZE);
	  printf("ADC1=%d\n",adcval[0]);
	  printf("ADC2=%d\n",adcval[1]);
	  HAL_ADC_Stop_DMA(&hadc1);
	  HAL_Delay(1000);
  }
  /* USER CODE END 3 */
/* USER CODE BEGIN 4 */
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)
{
  if (hadc->Instance == ADC1)
  {
	  printf("ADC END\n");
  }
}
/* USER CODE END 4 */
 
動作確認
 
 
(4) プログラムの説明
 (a) #define ADSIZE 2
  ・2をADSIZEという名前に置き換える。
 
 (b)  uint16_t adcval[ADSIZE];
  AD変換した値を受け取るための配列を用意する。
 
 (c) HAL_ADC_Start_DMA(&hadc1,(uint32_t *)adcval,ADSIZE); 
 ・ADCの変換を開始する。
 ・DMAによりADCからの変換結果が直接メモリに転送されるようにする。
 引数:
  ADC_HandleTypeDef *hadc: ADCハンドル構造体へのポインタ
  uint32_t *pData: DMA転送用のデータバッファへのポインタ
  uint32_t Length: DMA転送のデータ数(バイト数)
  ※adcvalにAD変換値が格納される。
 
 (d) HAL_ADC_Stop_DMA(&hadc1);
 ・HAL_ADC_Stop_DMAは、DMAを介してデータを転送しているADCを停止する。
 ・DMA転送中にADCの変換を停止できる。
 ・DMA転送が停止すると、ADCからの変換結果の収集も停止し、
  これにより、CPUの負荷が軽減される。
 
 (d) void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)
 ・ADCの変換が完了したときに呼び出されるコールバック関数
 ・DMAによってADCからの変換結果が直接メモリに転送される際に使用される。
 ・ADC変換が完了する度に、DMA割り込みが発生し、
  この関数が自動的に呼び出される。
 ・この関数をカスタマイズすることで、変換結果を処理することができます。
  今回は、printfで呼び出しの確認のみしている。
 
参考記事:
 
実装動画
 

3.関連記事

関連記事一覧:
 
組み込みC言語