cancel
Showing results for 
Search instead for 
Did you mean: 

Can I combine Encoder with Input Capture at DMA?

DMårt
Lead

Hi!

I have a STM32F373 processor and I have 2 Encoders and 3 Input Captures.

I have enabled DMA for input capture.

Timer 4:

0693W00000D1n2KQAR.png0693W00000D1n2PQAR.pngTimer 19:

0693W00000D1n2jQAB.png0693W00000D1n2tQAB.png 

And I have this code.

My questions are:

  1. Can I use Encoder together with Input Capture if Input Capture has DMA?
  2. What will DMA store inside the arrays input_capture[2]? Is it the counter value? I'm assuming it will be some kind of a counted value, right?
  3. Will this work?
static TIM_HandleTypeDef* tim4_handle;
static TIM_HandleTypeDef* tim19_handle;
volatile static uint32_t input_capture0[2] = {0};
volatile static uint32_t input_capture1[2] = {0};
volatile static uint32_t input_capture2[2] = {0};
static uint32_t pulse_count[4] = {0};
 
void STM32_PLC_Start_Counters(TIM_HandleTypeDef* htim4, TIM_HandleTypeDef* htim19) {
	/* Encoder - Prescaler does not effect encoder */
	if(HAL_TIM_Encoder_Start(htim4, TIM_CHANNEL_ALL) != HAL_OK)
		Error_Handler();
	if(HAL_TIM_Encoder_Start(htim19, TIM_CHANNEL_ALL) != HAL_OK)
		Error_Handler();
 
	/*
	 * Input capture for measuring frequency
	 * For TIM4 and TIM19
	 * Timer clock: 48 Mhz
	 * Prescaler: 4799
	 * Counter: 65535 (0xffff)
	 * Update frequency: 6.5535 Hz
	 * 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(htim4, TIM_CHANNEL_3, (uint32_t*)input_capture1, 2) != HAL_OK)
		Error_Handler();
	if(HAL_TIM_IC_Start_DMA(htim4, TIM_CHANNEL_4, (uint32_t*)input_capture0, 2) != HAL_OK)
		Error_Handler();
	if(HAL_TIM_IC_Start_DMA(htim19, TIM_CHANNEL_3, (uint32_t*)input_capture2, 2) != HAL_OK)
		Error_Handler();
 
	/* Save */
	tim4_handle = htim4;
	tim19_handle = htim19;
}
 
int16_t STM32_PLC_Encoder_Get(uint8_t i) {
	if(i == 0)
		return tim4_handle->Instance->CNT;
	else
		return tim19_handle->Instance->CNT;
}
 
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
	 */
	if(input_capture[1] > input_capture[0]) {
		return (float) 1/((input_capture[1] - input_capture[0])*0.0001f);
	} else if(input_capture[1] < input_capture[0]) {
		return (float) 1/((input_capture[1] + 0xFFFF - input_capture[0])*0.0001f);
	} else if(input_capture[1] == 0x7FFF && input_capture[0] == 0x7FFF){
		return (float) 1/(0xFFFF*0.0001f);
	} else {
		return 0;
	}
}
 
float STM32_PLC_Input_Capture_Get(uint8_t i) {
	if(i == 0)
		return compute_frequency((uint16_t*)input_capture0);
	else if(i == 1)
		return compute_frequency((uint16_t*)input_capture1);
	else
		return compute_frequency((uint16_t*)input_capture2);
}
 
void STM32_PLC_Input_Capture_Reset() {
	for(uint8_t i = 0; i < 2; i++){
		input_capture0[i] = 0;
		input_capture1[i] = 0;
		input_capture2[i] = 0;
	}
}
 
void STM32_PLC_Pulse_Count_Set(uint8_t i){
	pulse_count[i]++;
}
 
uint32_t STM32_PLC_Pulse_Count_Get(uint8_t i){
	return pulse_count[i];
}
 
void STM32_PLC_Pulse_Count_Reset(){
	memset(pulse_count, 0, sizeof(pulse_count));
}

STM32MP151AAC3 custom board with STM32-OS as operating system: https://github.com/DanielMartensson/STM32-Computer
1 ACCEPTED SOLUTION

Accepted Solutions

Is it totaly normal that I getting a number 65535 if I connect 3.3V to encoder plus? And I get only value 1 if I connect it to encoder minus.

If I not connect anything, I get the value 0. Why? I thougth encoder till remember the value.

Edit:

Now it's working!

static TIM_HandleTypeDef* tim4_handle;
static TIM_HandleTypeDef* tim19_handle;
static uint16_t encoder_pulses_per_revolution[2] = {0};
static int16_t encoder[2] = {0};
 
void STM32_PLC_Start_Encoder(TIM_HandleTypeDef* htim4, TIM_HandleTypeDef* htim19) {
	/* Encoder - Prescaler does not effect encoder */
	if(HAL_TIM_Encoder_Start(htim4, TIM_CHANNEL_ALL) != HAL_OK)
		Error_Handler();
	if(HAL_TIM_Encoder_Start(htim19, TIM_CHANNEL_ALL) != HAL_OK)
		Error_Handler();
 
	/* Save */
	tim4_handle = htim4;
	tim19_handle = htim19;
}
 
float STM32_PLC_Encoder_Get(uint8_t i) {
	/* Safety */
	if(encoder_pulses_per_revolution[i] == 0)
		encoder_pulses_per_revolution[i] = 1;
	float pulses = (float)encoder_pulses_per_revolution[i];
	return ((float)STM32_PLC_Encoder_Get_Raw(i))/pulses;
}
 
int16_t STM32_PLC_Encoder_Get_Raw(uint8_t i) {
	if(i == 0)
		encoder[i] += __HAL_TIM_GET_COUNTER(tim4_handle);
	else
		encoder[i] += __HAL_TIM_GET_COUNTER(tim19_handle);
	return encoder[i];
}
 
void STM32_PLC_Encoder_Set_Pulses_Per_Revolutions(uint8_t i, uint16_t pulses_per_revolution) {
	encoder_pulses_per_revolution[i] = pulses_per_revolution;
}

STM32MP151AAC3 custom board with STM32-OS as operating system: https://github.com/DanielMartensson/STM32-Computer

View solution in original post

8 REPLIES 8
TDK
Guru

Yes.

IC will capture the CNT value at the time of the event, which is then transferred by DMA.

If you feel a post has answered your question, please click "Accept as Solution".

So in this case, combining Encoder with IC....bad idea?

Do you have another solution?

I think I need to have DMA because if I using interrupts, then the interrupts will...well...interrupt other parts of the code.

STM32MP151AAC3 custom board with STM32-OS as operating system: https://github.com/DanielMartensson/STM32-Computer
It doesn't seem very useful to me.
Solution for what? I don't see you explaining what you want anywhere. There are plenty of other timers on the chip.
If you feel a post has answered your question, please click "Accept as Solution".

Why does it not seems useful? Encoder + IC?

I'm using IC because I want to measure frequecy.

I'm using encoder because I want to measure position.

STM32MP151AAC3 custom board with STM32-OS as operating system: https://github.com/DanielMartensson/STM32-Computer

Use one timer for the encoder and use another timer to measure frequency.

It may be possible to hook up IC to transfer the CNT value from another timer instead, but it's probably not something that HAL supports out of the box.

If you feel a post has answered your question, please click "Accept as Solution".

So what is TIM_UP for something in DMA?

Is that for encoder?

STM32MP151AAC3 custom board with STM32-OS as operating system: https://github.com/DanielMartensson/STM32-Computer

Ok! I have split up now. Now I have 2 different timers for input capture and two different timers for encoders. I hope this will work for Input Capture.

volatile static uint32_t input_capture0[2] = {0};
volatile static uint32_t input_capture1[2] = {0};
 
void STM32_PLC_Start_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
	 */
	if(input_capture[1] > input_capture[0]) {
		return (float) 1/((input_capture[1] - input_capture[0])*0.0001f);
	} else if(input_capture[1] < input_capture[0]) {
		return (float) 1/((input_capture[1] + 0xFFFF - input_capture[0])*0.0001f);
	} else if(input_capture[1] == 0x7FFF && input_capture[0] == 0x7FFF){
		return (float) 1/(0xFFFF*0.0001f);
	} else {
		return 0;
	}
}
 
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);
}
 

STM32MP151AAC3 custom board with STM32-OS as operating system: https://github.com/DanielMartensson/STM32-Computer

Is it totaly normal that I getting a number 65535 if I connect 3.3V to encoder plus? And I get only value 1 if I connect it to encoder minus.

If I not connect anything, I get the value 0. Why? I thougth encoder till remember the value.

Edit:

Now it's working!

static TIM_HandleTypeDef* tim4_handle;
static TIM_HandleTypeDef* tim19_handle;
static uint16_t encoder_pulses_per_revolution[2] = {0};
static int16_t encoder[2] = {0};
 
void STM32_PLC_Start_Encoder(TIM_HandleTypeDef* htim4, TIM_HandleTypeDef* htim19) {
	/* Encoder - Prescaler does not effect encoder */
	if(HAL_TIM_Encoder_Start(htim4, TIM_CHANNEL_ALL) != HAL_OK)
		Error_Handler();
	if(HAL_TIM_Encoder_Start(htim19, TIM_CHANNEL_ALL) != HAL_OK)
		Error_Handler();
 
	/* Save */
	tim4_handle = htim4;
	tim19_handle = htim19;
}
 
float STM32_PLC_Encoder_Get(uint8_t i) {
	/* Safety */
	if(encoder_pulses_per_revolution[i] == 0)
		encoder_pulses_per_revolution[i] = 1;
	float pulses = (float)encoder_pulses_per_revolution[i];
	return ((float)STM32_PLC_Encoder_Get_Raw(i))/pulses;
}
 
int16_t STM32_PLC_Encoder_Get_Raw(uint8_t i) {
	if(i == 0)
		encoder[i] += __HAL_TIM_GET_COUNTER(tim4_handle);
	else
		encoder[i] += __HAL_TIM_GET_COUNTER(tim19_handle);
	return encoder[i];
}
 
void STM32_PLC_Encoder_Set_Pulses_Per_Revolutions(uint8_t i, uint16_t pulses_per_revolution) {
	encoder_pulses_per_revolution[i] = pulses_per_revolution;
}

STM32MP151AAC3 custom board with STM32-OS as operating system: https://github.com/DanielMartensson/STM32-Computer