cancel
Showing results for 
Search instead for 
Did you mean: 

Time-based input capture

bobsmith405
Associate II

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.

 

9 REPLIES 9

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.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..

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.

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

 

I think this is pretty close to what I'm looking for.  I think the important part is that if there's no half- or full-complete interrupt, stopping the DMA with HAL_TIM_IC_Stop_DMA() will transfer whatever data had been captured up to that point - is that true?

This application boils down to a pulse counter - we're looking to store the total number of pulses received, the intervals between those pulses, and the number of pulses received in a given timeframe. 

"DMA with HAL_TIM_IC_Stop_DMA() will transfer"

No, it would not. Do transfer yourself. 

What is not clear, if data lost is critical, I think two input capture processes using two timers may be better option, than stopping one for data manipulation would not interrupt data flow since secondary runs.

"we're looking to store the total number of pulses received, the intervals between those pulses, and the number of pulses received in a given timeframe"

Counting non-zero in data buff provides number of pulses received, subtracting value-N from value-N+1 gives interval in timers ticks.

 

bobsmith405
Associate II

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

bobsmith405
Associate II

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.

Saket_Om
ST Employee

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).

To give better visibility on the answered topics, please click on "Accept as Solution" on the reply which solved your issue or answered your question.
Saket_Om
Francois VILMAIN
ST Employee

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 .