STM32L010 ADCの使い方(DMA / TIM EVENT)


ADCを使用してみます。 最初にDMA転送を使用したADCの読み出しを実現してみます。

1. デバイスの設定(ADC / DMA)

1.1. ADCの設定

AD7とAD6をAD入力として設定します。
Parameter Settings は Continuous Convertion ModeDMA Continuous RequestsEnabledに設定します。






DMA Settingsを以下の様に設定します。
Direction Peripheral To Memory
Mode Circular
Increment Address Memory にチェック
DMA転送先はuint16_tの配列なのでインクリメント設定とします。


今回、読みだしたAD値をsprintfで文字列にしてUSARTに出力させます。
しかし、デフォルト設定だとFROMのサイズオーバーになってしまうため、OptimizationをOptimize for size(-Os)に変更します。


また、RAMの容量も不足してしまうので、Minimum Heap SizeMinimum Stack Sizeをそれぞれ0x100 0x200に変更します。


2. コーディング

2.1. DMA開始処理

USER CODE PV BEGINの下にDMA転送先となる外部変数を追加します。
ここでは uint16_t g_uhADC[2]とします。
/* USER CODE BEGIN PV */
uint16_t	g_uhADC[2] = {0, 0};

/* USER CODE END PV */
				
USER CODE BEGIN 2の下に、HAL_ADC_Start_DMAを記述します。
これでADCのDMA転送が開始されます。
割込みを有効とすると、割込みで処理が占有されてしまうため、TCIEHTIEをDisableにします。
  /* USER CODE BEGIN 2 */
  pDMA = hadc.DMA_Handle;
  HAL_ADC_Start_DMA(&hadc, (uint32_t *)g_uhADC, sizeof(g_uhADC) / sizeof(g_uhADC[0]));
  (*(*pDMA).Instance).CCR &= ~(DMA_IT_TC | DMA_IT_HT);

  /* USER CODE END 2 */
				
USER CODE BEGIN 3の下に結果をUSARTで送信する処理を追加します。
関数名はHAL_TIM_PeriodElapsedCallback固定です。
今回は簡単にHAL_UART_Transmit_IT関数を使用しての送信とします。
    /* USER CODE BEGIN 3 */
	sprintf(msg,"%04X %04X\r", g_uhADC[0], g_uhADC[1]);
	HAL_UART_Transmit_IT(&huart2, (uint8_t *)msg, strlen(msg));
				
コーディングはここまでです。

これで動作しますが、、、懸念点が一つあります。
Sampling Timeを1.5Cyclesに設定していますので、AHB/APB Busをかなり占有してしまう可能性があり、他のPeripheralが動作し辛い状況になりえます。
DMAで連続転送を行う場合は、Sampling Timeを下げた方が良いでしょう。

次にAHB/APB Busに負担をかけないよう、TIM2のEVENTと連動させてみます。



3. デバイスの設定(ADC / DMA / TIM2)

3.1. ADCの設定

ADCのParametersを変更します。
TIM2 EVENTをトリガとしてADC開始とさせるので、Continuouos Conversion ModeDisableにしておきます。
External Trigger Conversion SourceTimer2 Trigger Out eventに設定します。




3.2. TIM2の設定

TIM2を追加します。
わかりやすいように1秒毎にAD変換するようにします。
Prescaler3199
Counter Period9999
とすることで1秒設定となります。
Trigger Event SelectionUpdate Eventに設定します。







4. コーディング

4.1. TIM2 / DMA開始処理

最初にHAL_TIM_GenerateEventを呼び出しTrigger Sourceを設定します。
次にHAL_ADC_Start_DMAを呼び出しDMAを開始します。
最後にトリガとなるTIM2をHAL_TIM_Base_Startで起動します。
今回はTIM2で1秒毎にDMA転送となりますので、TCIEHTIEをDisableにする必要はありません。
  /* USER CODE BEGIN 2 */
  HAL_TIM_GenerateEvent(&htim2, TIM_EVENTSOURCE_UPDATE);
  HAL_ADC_Start_DMA(&hadc, (uint32_t *)g_uhADC, sizeof(g_uhADC) / sizeof(g_uhADC[0]));
  HAL_TIM_Base_Start(&htim2);

  /* USER CODE END 2 */
				
コーディングはここまでです。

TIM2のUpdate EventでAD変換 / DMA転送を行いますので、AHB / APB Busが占有されることはありません。


今回の回路図は以下の通りです。