UART、ADC諸々のDMAがうまく動かない時の対処法メモ
結論
CubeMX v6.2.1現在の生成コードが間違ってる場合がある。
MCUや使用するペリフェラルによって、イニシャライズの順序が変わる場合があります。
この時DMAのInitの順番が変わると、DMAの動作が正常にならない場合があります。
生成されるダメなInitコードの例
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_ADC1_Init();
MX_DAC1_Init();
MX_FDCAN1_Init();
MX_SPI2_Init();
MX_TIM2_Init();
MX_TIM3_Init();
MX_USART1_UART_Init();
//DMA初期化がペリフェラル初期化の前にいたり後ろにいたりする
MX_DMA_Init();
MX_I2C2_Init();
MX_USART2_UART_Init();
MX_DMA_Init();
がDMAを使いたいペリフェラルの初期化よりも後に実行されるとその前に初期化が実行されたペリフェラルでDMAが正常に機能しない。
上の場合だとADC~USART1までのDMAが正常に機能しない可能性があります。
修正する
DMAの初期化を、ペリフェラルの前に移動します。
/* Initialize all configured peripherals */
MX_GPIO_Init();
//DMAを使いたいペリフェラル初期化よりも前に持ってくる
MX_DMA_Init();
MX_ADC1_Init();
MX_DAC1_Init();
MX_FDCAN1_Init();
MX_SPI2_Init();
MX_TIM2_Init();
MX_TIM3_Init();
MX_USART1_UART_Init();
MX_I2C2_Init();
MX_USART2_UART_Init();
#何が起きてるのか
コードの話
DMA_Initの中には、クロックの設定とNVIC割り込みに関する初期化が入っています。
/* DMA controller clock enable */
__HAL_RCC_DMA1_CLK_ENABLE();
/* DMA1_Channel1_IRQn interrupt configuration */
HAL_NVIC_SetPriority(DMA1_Channel1_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(DMA1_Channel1_IRQn);
そのためペリフェラル初期化→DMA初期化の順に行ってしまうと、DMAの各種設定が反映されません。
レジスタの状態
例としてUARTのDMA(DMA1 Ch5)を、サーキュラモード、メモリインクリメントで設定します。
正しい順序で初期化を行った場合
CIRC(Circular)とMINC(Momery increment)の設定が反映されています。