STM32 F7 でDMAに苦戦

STM32 F7 (STM32 F730) でUARTにDMAを使おうとしてワナにはまったのでメモ。
今回は、DMAをCircular で動作させて、常にUARTからのデータを受信するようにする実装にした。
(たぶんよく使う実装)
IT受信(割り込み受信)は問題なかったが、DMAで受信できない問題が生じた。

はまった問題は2つの問題の複合 まず一つ目

【HALのエラー処理】

今回、常時受信の環境を作ろうとした。受信するデータのデータ源と、今回実装するコードを動かす F7との間でどちらが先に起動するかは明確ではない。
このとき、もしデータ源が先に起動して、データを 発信していた場合、HALがUARTを初期化したとたんにOverrunエラーが発生してしまう。
HALのUART割り込み処理は、エラー発生時にDMAを止めてしまうので、結果として永遠にDMA受信を 始めることができない(正確には初めてもすぐ止められる)。
以上が発生している現象。

対策

void USART2_IRQHandler(void)
{
  /* USER CODE BEGIN USART2_IRQn 0 */
  uint32_t isrflags = huart2.Instance->ISR;
  uint32_t errorflags = (isrflags & (uint32_t)(USART_ISR_PE | USART_ISR_FE | USART_ISR_ORE | USART_ISR_NE | USART_ISR_RTOF));
  errorflags |= (isrflags & USART_ISR_RXNE);

  /* USER CODE END USART2_IRQn 0 */

  HAL_UART_IRQHandler(&huart2);
  
  /* USER CODE BEGIN USART2_IRQn 1 */

  /* USER CODE END USART2_IRQn 1 */
}
HAL の割り込みハンドラがエラー時にDMAを止めてしまうのでエラーハンドラの前でエラーは全てクリアしてしまえば 止まらないという発想(ただし、到着データの信頼性は上位レイヤで確認するのが前提)。
RXNEをクリアするかどうかは悩ましいが今回はクリア。

 

 

二つ目

【データキャッシュ】

DMAはキャッシュを介さずメモリに書き込む、CPUからの読み出しはキャッシュを読みだす・・・・なにやってんだか。
正しくはキャッシュをクリアしてキャッシュされていないメモリから読み出すのだが、CPU内蔵SRAMしか使用していなければキャッシュの意味は薄い。 キャッシュなど止めてしまえ、で初期化時にコレ!
SCB_DisableDCache();