Electrical – Clarification on interrupt triggered DMA transfer in an STM32

hal-librarystm32

I'm trying to learn about DMA and its use in the STM32L4S9VI platform. One thing I'm confused about is what binds the DMA transfer to any one specific interrupt? In the below example, I'm curious which UART interrupt triggers the transfer of the next byte into the transmit data register, as well as how the DMA determines which interrupt from UART was called. As I understand it, there is actually only 1 general USART2 interrupt line that goes to the DMA, so how does the DMA actually know that the interrupt is the one that signals that it's ready to have another byte put into the transmit data register? Does

HAL_UART_IRQHandler(&huart2);

take care of it?


Example:

/* Private variables ---------------------------------------------------------*/
extern UART_HandleTypeDef huart2;
DMA_HandleTypeDef hdma_usart2_tx;
char *msg = "Hello STM32 Lovers! This message is transferred in DMA Mode.\r\n";


/* USER CODE BEGIN PV */
/* Private variables ---------------------------------------------------------*/

/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void DMATransferComplete(DMA_HandleTypeDef *hdma);

/* USER CODE BEGIN PFP */
/* Private function prototypes -----------------------------------------------*/

/* USER CODE END PFP */

/* USER CODE BEGIN 0 */

/* USER CODE END 0 */

int main(void) {
  HAL_Init();

  Nucleo_BSP_Init();

  hdma_usart2_tx.Instance = DMA1_Channel7;
  hdma_usart2_tx.Init.Request = DMA_REQUEST_2;
  hdma_usart2_tx.Init.Direction = DMA_MEMORY_TO_PERIPH;
  hdma_usart2_tx.Init.PeriphInc = DMA_PINC_DISABLE;
  hdma_usart2_tx.Init.MemInc = DMA_MINC_ENABLE;
  hdma_usart2_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
  hdma_usart2_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
  hdma_usart2_tx.Init.Mode = DMA_NORMAL;
  hdma_usart2_tx.Init.Priority = DMA_PRIORITY_LOW;
  hdma_usart2_tx.XferCpltCallback = &DMATransferComplete;
  HAL_DMA_Init(&hdma_usart2_tx);

  /* DMA interrupt init */
  HAL_NVIC_SetPriority(DMA1_Channel7_IRQn, 0, 0);
  HAL_NVIC_EnableIRQ(DMA1_Channel7_IRQn);

  HAL_DMA_Start_IT(&hdma_usart2_tx,  (uint32_t)msg,  (uint32_t)&huart2.Instance->TDR, strlen(msg));
  //Enable UART in DMA mode
  huart2.Instance->CR3 |= USART_CR3_DMAT;

  /* Infinite loop */
  while (1);
}

void DMATransferComplete(DMA_HandleTypeDef *hdma) {
  if(hdma->Instance == DMA1_Channel7) {
    //Disable UART DMA mode
    huart2.Instance->CR3 &= ~USART_CR3_DMAT;
    //Turn LD2 ON
    HAL_GPIO_WritePin(LD2_GPIO_Port, LD2_Pin, GPIO_PIN_SET);
  }
}

Best Answer

In the STM32L4, there is both a DMA and a DMA multiplexer.

In a simpler chip like the STM32F3, there is just a basic DMA with direct lines to every DMA-capable peripheral. But I guess in the STM32L4, there are many more peripherals and it is unlikely a lot of them will be used with the DMA in any single application. Combined with the impracticality of running direct DMA lines to every peripheral, they chose to add a DMA mux in between the peripherals and the DMA so that amongst the numerous DMA-capable peripherals available, only the select few that are required at any one time could be routed to the DMA thus keeping the lines to the DMA small.

Each output of the DMA mux (you can think of it as parallel single-output muxes that have common inputs, but each output goes to a different line into the DMA) has a register that enables the output as well as selects which input (i.e. peripheral) to connect to.

From there you would have configure your DMA to behave appropriately for that peripheral while referencing that mux output (rather directly referencing the peripheral as you would in a basic DMA where the peripheral has a line directly to the DMA).

As I understand it, there is actually only 1 general USART2 interrupt line that goes to the DMA, so how does the DMA actually know that the interrupt is the one that signals that it's ready to have another byte put into the transmit data register?

Not every interrupt from a DMA-capable peripheral will trigger a DMA transfer. That wouldn't make sense in use. Each peripheral is designed so only specific interrupts will trigger a DMA transfer.

For example, for a USART, it only makes sense to trigger a DMA transfer when a byte is received or when a byte has finished transmitting so those are the only interrupts that trigger a DMA transfer and each one has a separate enable bit (the UART RX and TX each have a different DMA trigger line).

Which specific interrupts for a peripheral will trigger the DMA will be in in the peripheral specific section of the reference manual.