0
\$\begingroup\$

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);
  }
}
\$\endgroup\$
  • \$\begingroup\$ Only specific interrupts from a peripheral (such as the byte received and byte finished transmitting interrupts) will trigger a DMA transfer. Not every interrupt from that peripheral will. Misunderstandings like this happen when you do not look past the pre-written libraries. Read the manual for the STM32 DMA and the USART. Look at what the registers actually do. \$\endgroup\$ – DKNguyen Jun 19 at 22:14
  • \$\begingroup\$ @DKNguyen Is there anywhere I can find which peripheral interrupts are routed to the DMA? I've looked around the reference manual and can't find anything, except for the part on DMAMUX giving me just a general overview, not hard numbers. \$\endgroup\$ – ccolton Jun 19 at 22:21
  • \$\begingroup\$ Which MCU are you using? \$\endgroup\$ – DKNguyen Jun 19 at 22:23
  • \$\begingroup\$ The datasheet is even less in depth about it, I really dug into the reference manual because it actually lists out the registers, but still won't actually tell me how anything is connected, which is quite frustrating. \$\endgroup\$ – ccolton Jun 19 at 22:24
  • \$\begingroup\$ Sorry, I was mistaken about the datasheet thing. It's all in the reference manual. For example, for the STM32F303 it is on Table 78 and 79. Which MCU are you using? \$\endgroup\$ – DKNguyen Jun 19 at 22:25
1
\$\begingroup\$

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.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.