Skip to main content
Visitor II
June 12, 2025
Question

STM32G0B1 DMA Capture Delay Issue with TIM1 Input Frequency Measurement

  • June 12, 2025
  • 2 replies
  • 902 views

Hello ST Team,

We are currently working with the STM32G0B1KCUX series MCU, which has 144 KB RAM and 256 KB Flash.
Our objective is to measure the frequency of an incoming signal using TIM1 in Input Capture mode with DMA (Channel 2). Below are the key configuration and issue details:

We are interested in capturing frequency using DMA mode without any interrupt callbacks. We need a way to synchronize the transfer completion to ensure the captured data is correct

i have Attached timer settings and code snippet

  1. Timer Configuration:

    • Timer: TIM1 (16-bit)

    • Clock Frequency: 64 MHz (no prescaler)

    • DMA: Used to capture values without interrupt

    • Slave Mode: Reset mode with trigger on TI1FP1

  2. Input Signal:

    • Frequency Range: 15.8 kHz to 16 kHz

    • Signal Period: Approximately 62.5 µs to 63.3 µs

  3. Observation:

    • When checking the DMA_ISR_TCIF2 flag before reading, the time between frequency measurements varies inconsistently — sometimes 1ms, 2ms, or 3ms.

    • However, if we remove the DMA complete flag check, the capture reads occur at a rate matching the system clock and signal input, i.e., much faster and more consistent.

      The Issue:

      We are confused why adding this DMA transfer complete flag check:

       
      if (!(DMA1->ISR & DMA_ISR_TCIF2)) return 0; DMA1->IFCR = DMA_ISR_TCIF2; // Clear flag

      results in millisecond-level delays between readings, even though the input signal is at ~63 µs intervals. Without this check, data comes in faster, matching expectations.

      avinpat_8_0-1749719404641.pngavinpat_8_1-1749719421732.pngavinpat_8_2-1749719481921.png

       

       

       

    This topic has been closed for replies.

    2 replies

    Super User
    June 12, 2025

    It appears that you've set up the slave-mode controller in Reset mode triggered from channel 1, i.e. the setup which is in RM called "PWM Input". That alone should be enough to measure frequency, you shouldn't need DMA for that. At the same time, in that setup, it's unlikely two successive readings would result in any significant difference - regardless of whether in us or ms - if the input signal's frequency is stable.

    So, either you don't show us relevant portions of the setup and relevant portions of code, or the input signal is intermittent.

    Also, note, that it's not unlikely that Cube/HAL interrupt handlers would execute for hundreds to thousands of cycles, i.e. up to tens of us.

    JW

    avinpat_8Author
    Visitor II
    June 12, 2025

    Hi thanks for the reply since we are reading this input frequency continuously what kind of setup or timer configuration would you recommend so that we can read efficiently with low latency any reference? please check the below attached code snippet

     

    Super User
    June 12, 2025

    > We are confused why adding this DMA transfer complete flag check:

    > if (!(DMA1->ISR & DMA_ISR_TCIF2)) return 0; DMA1->IFCR = DMA_ISR_TCIF2; // Clear flag

    > results in millisecond-level delays between readings,

    Because the flag is checked and cleared within the HAL_DMA_IRQHandler. You should leave it alone, or you should remove the call to HAL_DMA_IRQHandler if you want to handle it yourself and implement your own handling of the flag.

    avinpat_8Author
    Visitor II
    June 19, 2025

    Hi thanks for the reply i understood your point and i have made changes since i have commented out the irq handler and  i will be waiting in the polling method for the new data available once new data available i need to process as quickly as possible so will the below things are correct  

    So we need a capture in dma method only and i need to process as soon as possible 

    i need to reduce the overhead for calling interrupt callback and then process the freq

     

    // Disable DMA IRQ to prevent interrupt processing
    HAL_NVIC_DisableIRQ(DMA1_Channel2_3_IRQn);

    // Disable DMA transfer complete interrupt
    __HAL_DMA_DISABLE_IT(htim1.hdma[TIM_DMA_ID_CC1], DMA_IT_TC);

    // Clear any pending DMA flags
    __HAL_DMA_CLEAR_FLAG(htim1.hdma[TIM_DMA_ID_CC1], DMA_FLAG_TC2 | DMA_FLAG_HT2);

    // Start DMA in circular mode (runs continuously)
    if (HAL_TIM_IC_Start_DMA(&htim1, TIM_CHANNEL_1, (uint32_t *)captr_pwm, CAPTR_SAMPLE_COUNT) != HAL_OK)
    {
    printf("TIM1 IC Start Error\n\r");
    }

     

    static inline uint32_t captr_pulse_freq(void)
    {
    // Early exit if data not ready
    if (!(DMA1->ISR & DMA_ISR_TCIF2)) return 0;

    // Clear flag
    DMA1->IFCR = DMA_IFCR_CTCIF2;

    //process the freq 

    }

    void DMA1_Channel2_3_IRQHandler(void)
    {
    /* USER CODE BEGIN DMA1_Channel2_3_IRQn 0 */

    /* USER CODE END DMA1_Channel2_3_IRQn 0 */
    // HAL_DMA_IRQHandler(&hdma_tim1_ch1);
    /* USER CODE BEGIN DMA1_Channel2_3_IRQn 1 */
    /* USER CODE END DMA1_Channel2_3_IRQn 1 */
    }