cancel
Showing results for 
Search instead for 
Did you mean: 

Why DMA half transfer and transfer complete interrupts cannot be independently closed?

xiewenliang
Associate II

Controller:STM32G473RET6

IDE:STM32CubeMX+Keil(LL library)

Using DMA1 channel 1, copy the data collected by the ADC during half transfer interrupts and transfer complete interrupts.Discovered that half transmission interrupts and full transmission interrupts cannot be used independently.

Specifically reflected in:

(1)When DMA1 is initialized, if the half transfer interrupt is turned on and the  transfer complete interrupt is turned off, the full transfer interrupt can still be triggered
LL_DMA_EnableIT_HT(DMA1,LL_DMA_CHANNEL_1);
LL_DMA_DisableIT_TC(DMA1,LL_DMA_CHANNEL_1);
(2)During DMA1 initialization, if the half transfer interrupt is turned off and the transfer complete  interrupt is turned on, the half transfer interrupt can still be triggered
LL_DMA_EnableIT_TC(DMA1,LL_DMA_CHANNEL_1);
LL_DMA_DisableIT_HC(DMA1,LL_DMA_CHANNEL_1);
dma.pngtimer.png
 
 
1 ACCEPTED SOLUTION

Accepted Solutions
TDK
Guru

The HT flag still gets set even if it doesn't trigger the IRQ. So when your program runs, this happens:

  • HT gets set (IRQ isn't triggered as HTIE isn't set)
  • TC gets set, which triggers the IRQ handler being run
  • TC flag is processed
  • HT flag is processed (since you don't check for HTIE being set)

In your IRQ, you should check for HT being enabled AND being set. And only then act upon it. HAL does this.

https://github.com/STMicroelectronics/stm32g4xx_hal_driver/blob/7c2e19ec21714f0d993ae5bfe8859a45debcfdd6/Src/stm32g4xx_hal_dma.c#L747

You should also set the interrupts you want before enabling the stream, to avoid calling them when you don't want to. Seems like you're using a timer to trigger the ADC here, so shouldn't be the case.

If you feel a post has answered your question, please click "Accept as Solution".

View solution in original post

7 REPLIES 7
TDK
Guru

> When DMA1 is initialized, if the half transfer interrupt is turned on and the  transfer complete interrupt is turned off, the full transfer interrupt can still be triggered

How are you seeing this behavior exactly? Are you using your own IRQ handler or HAL's? Showing code would be informative.

Likely to be a software program bug, not a silicon hardware issue.

If you feel a post has answered your question, please click "Accept as Solution".

Yeah! I used DMA IRQ handler.I think that interrupt should not be triggered if it is not enabled.

/****************************part 1*****************************/
*DisableIT_TC,
*EnableIT_HT
****************************************************************/
  MX_GPIO_Init();
  MX_DMA_Init();
  MX_ADC3_Init();
  MX_OPAMP3_Init();
  MX_TIM1_Init();
  MX_UART4_Init();
  /* USER CODE BEGIN 2 */
  LL_ADC_REG_SetDMATransfer(ADC3,LL_ADC_REG_DMA_TRANSFER_UNLIMITED);
  LL_ADC_REG_StartConversion(ADC3);
  Activate_ADC(ADC3);
  Activate_OPAMP(OPAMP3);
  LL_DMA_DisableIT_TC(DMA1,LL_DMA_CHANNEL_1);
  LL_DMA_EnableIT_HT(DMA1,LL_DMA_CHANNEL_1);
  LL_TIM_EnableCounter(TIM1);

void DMA1_Channel1_IRQHandler(void)
{
  /* USER CODE BEGIN DMA1_Channel1_IRQn 0 */
  if((DMA1->ISR & DMA_ISR_TCIF1_Msk) == DMA_ISR_TCIF1_Msk)
  {
    LL_DMA_ClearFlag_TC1(DMA1);//The program can run here!!!why?TC interrupt was disable
    LL_GPIO_TogglePin(LED_GPIO_Port,LED_Pin);
  }
	
  if((DMA1->ISR & DMA_ISR_HTIF1_Msk) == DMA_ISR_HTIF1_Msk)
  {
    LL_DMA_ClearFlag_HT1(DMA1);
  }
}
/****************************part 2*****************************/
*DisableIT_HT,
*EnableIT_TC
****************************************************************/
  MX_GPIO_Init();
  MX_DMA_Init();
  MX_ADC3_Init();
  MX_OPAMP3_Init();
  MX_TIM1_Init();
  MX_UART4_Init();
  /* USER CODE BEGIN 2 */
  LL_ADC_REG_SetDMATransfer(ADC3,LL_ADC_REG_DMA_TRANSFER_UNLIMITED);
  LL_ADC_REG_StartConversion(ADC3);
  Activate_ADC(ADC3);
  Activate_OPAMP(OPAMP3);
  LL_DMA_EnableIT_TC(DMA1,LL_DMA_CHANNEL_1);
  LL_DMA_DisableIT_HT(DMA1,LL_DMA_CHANNEL_1);
  LL_TIM_EnableCounter(TIM1);

void DMA1_Channel1_IRQHandler(void)
{
  /* USER CODE BEGIN DMA1_Channel1_IRQn 0 */
  if((DMA1->ISR & DMA_ISR_TCIF1_Msk) == DMA_ISR_TCIF1_Msk)
  {
    LL_DMA_ClearFlag_TC1(DMA1);
  }
	
  if((DMA1->ISR & DMA_ISR_HTIF1_Msk) == DMA_ISR_HTIF1_Msk)
  {
    LL_DMA_ClearFlag_HT1(DMA1);//The program can run here!!!why?HT interrupt was disable
    LL_GPIO_TogglePin(LED_GPIO_Port,LED_Pin);
  }
}

 

Piranha
Chief II

Probably those interrupts were enabled and triggered before your code disabled them.

TDK
Guru

The HT flag still gets set even if it doesn't trigger the IRQ. So when your program runs, this happens:

  • HT gets set (IRQ isn't triggered as HTIE isn't set)
  • TC gets set, which triggers the IRQ handler being run
  • TC flag is processed
  • HT flag is processed (since you don't check for HTIE being set)

In your IRQ, you should check for HT being enabled AND being set. And only then act upon it. HAL does this.

https://github.com/STMicroelectronics/stm32g4xx_hal_driver/blob/7c2e19ec21714f0d993ae5bfe8859a45debcfdd6/Src/stm32g4xx_hal_dma.c#L747

You should also set the interrupts you want before enabling the stream, to avoid calling them when you don't want to. Seems like you're using a timer to trigger the ADC here, so shouldn't be the case.

If you feel a post has answered your question, please click "Accept as Solution".

Yes,you are right.I used a timer to trigger the ADC.And in IRQ,check for HT being enabled & being set  has been resolved this bug.

void DMA1_Channel1_IRQHandler(void)
{
  /* USER CODE BEGIN DMA1_Channel1_IRQn 0 */
  if((DMA1->ISR & DMA_ISR_TCIF1_Msk) == DMA_ISR_TCIF1_Msk && LL_DMA_IsEnabledIT_TC(DMA1,LL_DMA_CHANNEL_1))
  {
	 LL_DMA_ClearFlag_TC1(DMA1);
     LL_GPIO_TogglePin(LED_GPIO_Port,LED_Pin);
  }
	
   if((DMA1->ISR & DMA_ISR_HTIF1_Msk) == DMA_ISR_HTIF1_Msk && LL_DMA_IsEnabledIT_HT(DMA1,LL_DMA_CHANNEL_1))
  {
	  LL_DMA_ClearFlag_HT1(DMA1);
  }
	
}

But I cannot understand why check for HTIE being set in IRQ。Obviously  HTIE was disabled.

LL_DMA_DisableIT_HT(DMA1,LL_DMA_CHANNEL_1);

Also  simulated by Keil,I see HTIE was disabled.

dma.png

As TDK said above, DMA sets the Half-Transfer flag regardless of whether interrupt is enabled or not. This flag is then input to an AND gate, other input of that gate is the HT-enable bit, and output of that gate is ORed together with other DMA interrupt sources and the result is fed to NVIC.

This solution allows to use software polling of the DMA flags, i.e. working without interrupts.

JW

Oh, I see now!:grinning_face:Thank you and TDK!