STM32F3のADCとDMAでアナログ値をポーリングする


ハード周り

Nucleo-F303REを使っている。

ADC周りの設定

Continuous Conversion ModeとDMA Continuous RequestをENABLEに設定する。

DMA周りの設定

優先度は適当に。Circularモードで、Half Word幅。ペリフェラル側はインクリメントせず、メモリ側はインクリメントする。

ソフト周り

バッファ

適当な場所で宣言しておく。

uint16_t ADC_buff[3];

スタックに置く際はオーバーフローやCCMRAMに注意(グローバルに置くのが無難)。
HAL_ADC_Start_DMAの引数がuint32_t*だからといって、決して32bitで宣言してはいけない。特別の理由がない限り、必ずDMAで設定した幅に従うように。

mainの後半付近(値読み出し処理)

/* USER CODE BEGIN 2 */

HAL_ADCEx_Calibration_Start(&hadc1, ADC_SINGLE_ENDED);

static uint16_t ADC_buff[3];
HAL_ADC_Start_DMA(&hadc1, (uint32_t *)ADC_buff, sizeof(ADC_buff) / sizeof(ADC_buff[0]));

hdma_adc1.Instance->CCR &= ~(DMA_IT_TC | DMA_IT_HT);
/* USER CODE END 2 */

/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
    printf("ADC %3hu %3hu %3hu\n", ADC_buff[0], ADC_buff[1], ADC_buff[2]);

    HAL_GPIO_TogglePin(LD2_GPIO_Port, LD2_Pin);
    HAL_Delay(100);

    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */

HAL_ADC_Start_DMAでADCとDMAを開始できる。ただ、バッファの長さが短く、DMA転送完了割り込みが頻繁に発生すると通常の処理もままならなくなるので、Transfer CompleteとHalf Transferを無効にしてある。

DMA転送で常時ADC変換が行われているので、好きなときにバッファを読めば最新のアナログ値を知ることができる。

感想

ADC+DMAはかなり悪い食い合わせ。せめてTIMも一緒にお召し上がりください。