Skip to main content
Visitor II
April 26, 2025
Question

Time-based input capture

  • April 26, 2025
  • 5 replies
  • 1365 views

Hi all, 

I have an application where I'm trying to use input capture to capture pulse intervals in a specific period of time.  At maximum, the pulses will happen frequently enough that I can't use the straight interrupt capture with HAL_TIM_IC_Start_IT, as it will starve out other tasks.  My thought is to use a DMA engine with HAL_TIM_IC_Start_DMA.  At the moment, the DMA interrupt triggers when the data buffer is full.  However, since I need to record over a specific period, this isn't sufficient - in that period there may be no events, or less than one buffer's worth of data.  What I'm thinking is something like this (please pardon the pseudocode):

HAL_TIM_Base_Start_IT(tim1); //start timer to measure period
HAL_TIM_IC_Start_DMA(tim2); //start input capture
while(1) //handle other tasks while waiting on input capture
{
 //do other things here
}

//input capture period timer has elapsed, so stop capture and store data
base_time_interrupt()
{
 //stop IC
 HAL_TIM_IC_Stop_DMA();
 //DMA input capture data from peripheral
 //get number of samples captured
}

Is this possible, or is there another viable option to gather this data?  If this is possible, what needs to be done? 

Some implementation details:

I'm using the STM32G474RE on the NUCLEO-G474R board.  I'm using STM32CubeIDE configuration utility to set up and configure the peripherals, and using TIM2 CH3 for the input capture.

 

    This topic has been closed for replies.

    5 replies

    Graduate II
    April 27, 2025

    What frequency?

    The PWM Input mode uses two channels (off one pin) to measure Frequency and Duty

    You can also free-run a TIM, and have it time stamp pulses, and use DMA as a means to build a list, at quite significant rates.

    Visitor II
    April 27, 2025

    I'm looking at frequencies between 500khz and 1MHz, but it's not a consistent signal - over a set period of time I could have zero pulses or many.  

    WRT free-running a TIM, my impression is that that is what the TIM input capture mode does.  Are you suggesting something different?  My problem is that the DMA operation is triggered when it has filled the buffer by timestamping a set number of pulses, but I need to get to the count and data at a given rate regardless of whether the buffer is full or not.

    WRT to PWM, I don't need the extra information (freq + pw), and I think I'd still have the same question of how to prematurely trigger the DMA to return the data from the peripheral to local memory.

    Explorer
    April 27, 2025

    I'd reserve two buffers. 

    Start DMA, in circular mode with buf-0, and sample data as in any real-time application like audio etc, when two interrupts -half complete -full complete tels which half of buffer just filled. Copy data and zero content.

    If no interrupt in a while -secondary timer as watch clock to time interval, than stop dma and restart immediately pointing to buf-1, so minimum data lost during switching over.

    Examine content buf-0 . What ever is not 0 is last sampled data

    Tell more about application, sure there possibility of another solution

     

    Visitor II
    April 27, 2025

    I see, this is what I was looking for.  Thanks for your help!

    Visitor II
    May 7, 2025

    Hi all,

    I thought the answer above was the solution, but after testing I don't think this is the case.  I thought that the sequence of events would be like this:

    1. TIM2 input capture starts with DMA (512 samples)

    2. Input capture receives 100 samples

    3. TIM5 elapses - TIM2 DMA interrupt has not occurred because not enough samples have been captured

    4. I use the DMA CPAR register to read 100 nonzero samples from the peripheral memory

     

    However, step 4 doesn't work properly.  CPAR points to the TIM2 CCRx register, which only has the current value, so I can't calculate the number of captures that have occurred to this point.  I think this makes sense, as the DMA only works when the DMA is set to not increment the source address. 

    I'd like to know if this approach is at all possible or if I need a different method.

    Technical Moderator
    May 8, 2025

    Hello @bobsmith405 

    I reported your question internally and will get back to you as soon as possible. 

    Internal ticket number: 209322 (This is an internal tracking number and is not accessible or usable by customers).

    ST Employee
    May 12, 2025

    Hello,

    I don't understand why you use the DMA CPAR register to retrieve the samples. When you use the capture in DMA mode, the DMA transfer direction is peripheral to memory meaning that every time an active edge is detected on the timer input channel, the counter value is sampled, stored into the capture/compare register CCRx. The DMA transfers the content of the CCRx register (source address) to the destination address(initially the start address of a buffer allocated by the application). destination address is incremented by the DMA once the sample has been transferred. This operation is repeated until the desired number of samples have been DMA transferred. If you don't want to wait for the end of the DMA transfer, your solution should work but then, when the period interrupt arises, you retrieves the sample directly in the destination buffer of the DMA transfer. Note that to retrieve the number of samples transferred by the DMA you can read DMA_CNDTRx (it is decremented after each single DMA).

    Below is a pseudo code illustrating this description, hope this will help:

    #define NB_SAMPLES      512U

    #define NULL_SAMPLE    0x50505050UL

    uint32_t Samples[NB_SAMPLES]

    Fill in Samples with NULL_SAMPLE

    HAL_TIM_Base_Init(htimy)

    HAL_TIM_IC_Init(htimx)

    HAL_TIM_IC_ConfigChannel(htimx, &input_channel_config, TIM_CHANNEL_1)

    HAL_TIM_IC_Start_DMA(htimx, TIM_CHANNEL_1, Samples, NB_SAMPLES)

    HAL_TIM_Base_Start_IT(htimy) // period interrupt

    Upon TIMy period interrupt stop the DMA transfer, possibly stop TIMy, and read the samples into the Samples buffer from index 0 till NULL_SAMPLE .