cancel
Showing results for 
Search instead for 
Did you mean: 

DMA interrupt not triggering after init

Klassic
Associate III

After setting configuration registers in HAL_DMA_Start_IT, DMA fails to fire back interrupt, HAL_DMA_IRQHandler(). The TransferComplete call back routine is not called but only once after reset since HAL_DMA_IRQHandler() is called only once after initialization. Flags CC1DE and CC1IE are set after initialization and never change there after. I am trying to read a parallel ADC through GPIO using DMA with interrupt and timer input capture. I am using STM32L496ZG ucontroller and used CUBEMX to generate code.

Also, I am using Timer2 with input capture mode to request DMA transfer. And using MCO to generate 2 MHz to feed to PA0 for timer2 ch1.

I searched the forum and checked almost everything. I used latest  CUBEMX 6.11.1 version.

Your help is greatly appreciated.
Thanks

Here is my initzn part;

 

 

 

 HAL_Init();
  /* Configure the system clock */
  SystemClock_Config();

  /* Initialize all configured peripherals */
  MX_DMA_Init();
  MX_GPIO_Init();
  MX_TIM2_Init();
  MX_USART2_UART_Init();
	if(DWT_Delay_Init())
	HAL_UART_Transmit(&huart2, (uint8_t *)"\r\nClkTick started", 17, HAL_MAX_DELAY);
	else
	HAL_UART_Transmit(&huart2, (uint8_t *)"\r\nClkTicks fail to start", 4, HAL_MAX_DELAY);

  /* USER CODE BEGIN 2 */
  if (HAL_DMA_Start_IT(htim2.hdma[TIM_DMA_ID_CC1], &GPIOE->IDR, (uint32_t)&aDST_Buffer, BUFFER_SIZE) != HAL_OK)
  {
    /* Transfer Error */
    Error_Handler();
  }

  // Attach DMA callback functions
  htim2.hdma[TIM_DMA_ID_CC1]->XferHalfCpltCallback = HalfTransferComplete;
  htim2.hdma[TIM_DMA_ID_CC1]->XferCpltCallback = TransferComplete;
  htim2.hdma[TIM_DMA_ID_CC1]->XferErrorCallback = TransferError;

  // Enable timer to trigger DMA transfer - CC1DE bit
  __HAL_TIM_ENABLE_DMA(&htim2, TIM_DMA_CC1);
  // Enable timer input capture
  HAL_TIM_IC_Start_IT(&htim2, TIM_CHANNEL_1);

  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
  }

 

 

Klassic_0-1718361144991.png           DMA Req setting: >Mode: Normal. 

 

 

 

And this is the data transfer callback routines:

 

 

 

static void HalfTransferComplete(DMA_HandleTypeDef *hdma_tim2_ch1) {
    int position = 0;
    LastITHalfComplete = 1;
    /*Copy the first part of the received buffer */
    for (int i = 0; i < HALF_BUFFER_SIZE; i++) {
        aFull_Buffer[FullDataIndex] = aDST_Buffer[i+position];
        FullDataIndex++;
        //HAL_GPIO_TogglePin(GPIOE, GPIO_PIN_1);
    }
}
static void TransferComplete(DMA_HandleTypeDef *hdma_tim2_ch1)
{
    int position = HALF_BUFFER_SIZE;
    LastITHalfComplete = 0;

    /* Copy the second part of the received buffer */
    for (int i = 0; i < HALF_BUFFER_SIZE; i++) {
    aFull_Buffer[FullDataIndex] = aDST_Buffer[i+position];
        FullDataIndex++;
        HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_0);
    }
    transferComplete = 1;
}

static void TransferError(DMA_HandleTypeDef *hdma_tim2_ch1) {
    HAL_GPIO_TogglePin(GPIOB,GPIO_PIN_14);
}

 

 

 

15 REPLIES 15
If you check the startup code in startup_stm32l496xx.s, you see that every interrupt handler is predefined by a unique name in the interrupt vector table like so

.word  EXTI0_IRQHandler
 
and then mapped to a default implementation Default_Handler (which is an infinite loop) by using some gcc assembler magic:

    .weak   EXTI0_IRQHandler
    .thumb_set EXTI0_IRQHandler,Default_Handler
 
If you (or STM32Cube) implements a specific handler, define a C function with exact the handler's original name ( EXTI0_IRQHandler).
 
So, if your code ends up in Default_Handler, it means that the MCU raised an interrupt for which there is no specific handler implemented. Root cause can be a spelling error or simply a forgotten handler.
 
In the Default_Handler, you may inspect IPSR register to find out the original interrupt number, see  PM0214
STM32 Cortex®-M4 MCUs and MPUs programming manual. SEGGER has a nice wiki on faults: Cortex-M Fault - SEGGER Wiki
hth
KnarfB

> Can you elaborate this ?
> only TIM1 and TIM8 can trigger DMA2 streams.

> How to make TIM1 to trigger DMA2 transfer?

Sorry, I mis-read the STM32 model you are using.

In 'L496, both DMAs can access GPIOs, but Cube/HAL and CubeMX probably don't support timer-triggered transfers between arbitrary addresses in the memory space. You may need to use register-level programming for that, or some workaround.

I don't use Cube/CubeMX.

JW


@waclawek.jan wrote:

You may need to use register-level programming for that, or some workaround.


Oh thats bad news. 

Thanks @KnarfB
Tried looking for ipsr number. But can't get it. Can u plz give me a clue how to look for it? Sorry for my weak skills.

@KnarfB Tried your solution. That fixed it. Now the program doesn't loop around Default_Handler anymore. 

Actually, I didn't wrote any void DMA2_Channel5_IRQHandler(void) routine.  Now the program visits  DMA2_Channel5_IRQHandler() function once.

Thanks  KnarfB for nice solution.

Now back to original problem. The program executes this DMA2_Channel5_IRQHandler() only once and and never comes back to it. So no change in SRAM variable after first transfer.

I think the timer is not triggering it to happen... 

Klassic
Associate III

Seems like HAL libraries have still loop holes to be fixed. Jan, you are right.

I used LL library for Timer1 along with DMA and it worked. I can see the change in GPIO inputs during debug.

Klassic_0-1725030496578.png

Thanks for supporting me.