cancel
Showing results for 
Search instead for 
Did you mean: 

Input Capture: How can I compare the values in a circular DMA buffer?

DMårt
Senior III

Hi!

I have Input Capture enabled with DMA. It works.

My buffer is 2 elements and it's a circular buffer. Each element in the buffer gets the counter value from a timer and the counter value goes from 0 to 65535 at 6.5535 seconds.

Question:

I want to compare the difference between the buffer's 2 elements. How can I do that?

Assume that element 0 is 60000 and element 1 is 1000, then the difference would be 65535 - 60000 + 1000 + 1 because the counter value is unsinged 16-bit.

But I don't know which index in the buffer that has the latest updated vale. Do you know?

static uint16_t input_capture0[2] = {0};
static uint16_t input_capture1[2] = {0};
 
void STM32_PLC_Input_Capture(TIM_HandleTypeDef* htim17, TIM_HandleTypeDef* htim16) {
	/*
	 * Input capture for measuring frequency
	 * For TIM17 and TIM16
	 * Timer clock: 48 Mhz
	 * Prescaler: 4799
	 * Counter: 65535 (0xffff)
	 * Update frequency: 0.1526 Hz (1/0.1526 = 6.5535 seconds)
	 * Example: For every second, it will count 10000
	 * Lowest frequency measurement: 1/(0xFFFF*0.0001) = 0.1526 Hz
	 * Highest frequency measurement: 1/(1*0.0001) = 10000 Hz
	 */
	if(HAL_TIM_IC_Start_DMA(htim16, TIM_CHANNEL_1, (uint32_t*)input_capture1, 2) != HAL_OK)
		Error_Handler();
	if(HAL_TIM_IC_Start_DMA(htim17, TIM_CHANNEL_1, (uint32_t*)input_capture0, 2) != HAL_OK)
		Error_Handler();
}
 
static float compute_frequency(uint16_t input_capture[]) {
	/*
	 * Typical worst case scenarios:
	 * T1: 0xFFFF - T0: 0x0
	 * T1: 0x0    - T0: 0xFFFF
	 * T1: 0x7FFF - T0: 0x7FFF
	 * T1: 0x0	  -	T0: 0x0
	 */
	uint16_t difference;
	if(input_capture[1] > input_capture[0]) {
		difference = input_capture[1] - input_capture[0];
		return (float) 1/(difference*0.0001f);
	} else if(input_capture[1] < input_capture[0]) {
		difference = 0xFFFF - input_capture[1] + input_capture[0] + 1;
		return (float) 1/(difference*0.0001f);
	} else {
		return 1/(65335*0.0001f);
	}
}
 
float STM32_PLC_Input_Capture_Get(uint8_t i) {
	if(i == 0)
		return compute_frequency((uint16_t*)input_capture0);
	else
		return compute_frequency((uint16_t*)input_capture1);
}

7 REPLIES 7

Which STM32?

> But I don't know which index in the buffer that has the latest updated vale.

Observe content of DMA NDTR/CNDTR register, beware of the late write in case of dual-port DMA.

I personally wouldn't go for a 2-element buffer.

JW

So you would use a longer buffer? Like 1000?

I don't understand.  According to the reference manual, this htim17->hdma->Instance->CNDTR, does not tell me at what index the DMA is going to write inside the buffer?

Which STM32?

CNDTR indicates you are using a model with single-port DMA. Description of CNDTR in different STM32 models which use it differs, but most if not all explain that it decrements after each transfer.

JW

0693W00000Dq0HhQAJ.pngwith the caveat I mentioned above. I don't have experience with the single-port DMA in this regard.

JW

So if my reference manual says

 post-decrementing of the programmed DMA_CNDTRx register
This register contains the remaining number of data items to transfer (number of AHB 
‘read followed by write’ transfers)

That means if I have 2 bytes buffer and the DMA have already filled 1 index at the buffer, that means CNDTR will show 1?

And when the circular buffer have been filled, then CNDTR = 0 and then directly CNDTR = 2 because not it's starting at index 0 again?

I can intepret CNDTR as how many elements it has left to write?

Yes.

JW