cancel
Showing results for 
Search instead for 
Did you mean: 

How to reset STM32H7 timer/counter and how to set the encoder mode?

Louie88
Associate III

Hi,

I am new with the STM32H7 timer/counter. I found the LPTIM_PulseCounter example which was good starting point. But I have a couple of questions:

  1. How can a reset the counter manually (not via automatic reload) of LPTIMER1? I could not find any HAL_LPTIM_CounterClear(), HAL_LPTIM_Counter_Reset(), HAL_LPTIM_Counter_Write(0x0000) function in HAL LPTIM Generic Driver.
  2. As far as I think the LPTIMER1 is capable to count quadrature encoded signals. It has two inputs, I can set the ENCODER mode and I can start the encoder mode with HAL_LPTIM_Encoder_Start (LPTIM_HandleTypeDef * hlptim, uint32_t Period) function. But I guess the period parameter should be set to 0xFFFF in order not to allow autoreload function after PERIOD count.
  3. Does ENCODER mode work with 32-bit timers? No need to be LPTIMER.
  4.  I have STM32H747I-DISCO board. The input1 of the LPTIMER1 is in the Arduino connector PD12 (pin 10 of CN5). Is the Input2 of LPTIMER1 in the same CN5 connector but the next pin: pin 9 of CN5 (PD13)?
  5. Is there any example how to use LPTIMER1 as an encoder in STM32H747I-DISCO board?

Thanks for your help!

Louis

20 REPLIES 20
Louie88
Associate III

Hi TDK,

Thanks, its working now. But, the next problem is the 16-bit encoder counter overflows and I could not find a interrupt handler (callback!!!) which would handle the encoder over/underflow. I drive the encoder from 10kHz pulses for 10 seconds. Counting on CH1/CH2 rising edges are configured so the encoder would contain 200 000 pulses. But it contains 3392, which is right because it overflows 3 times (3 * 65536) + 3392 = 200 000. I could handle it except this stupid way:

uint32_t lastEncoderPulses = 0;
	while (1)
	{
		HAL_Delay(50);
		//+++++
		// TFS20210727	Read counter of TIMER4
		// Take care about overflow manually because no interrupt provided for counter overflow...
		//-----
		encoderPulses = __HAL_TIM_GetCounter(&htim4);
		if (encoderPulses < lastEncoderPulses)
			encoderPulsesOvf++;
		lastEncoderPulses = encoderPulses;
	}

I found the following callbacks for TIMER4 in the "Description of STM32G4 HAL and low-layer drivers" manual. Please note that this is for STM32G4 not STM32H7 device...

58.2.9 TIM Callbacks functions

This section provides TIM callback functions:

• TIM Period elapsed callback

• TIM Output Compare callback

• TIM Input capture callback

• TIM Trigger callback

• TIM Error callback

• TIM Index callback (Not found or not implemented)

• TIM Direction change callback (Not found or not implemented)

• TIM Index error callback (Not found or not implemented)

• TIM Transition error callback

This section contains the following APIs:

• HAL_TIM_PeriodElapsedCallback

• HAL_TIM_PeriodElapsedHalfCpltCallback

• HAL_TIM_OC_DelayElapsedCallback

• HAL_TIM_IC_CaptureCallback

• HAL_TIM_IC_CaptureHalfCpltCallback

• HAL_TIM_PWM_PulseFinishedCallback

• HAL_TIM_PWM_PulseFinishedHalfCpltCallback

• HAL_TIM_TriggerCallback

• HAL_TIM_TriggerHalfCpltCallback

• HAL_TIM_ErrorCallback

Which one is the counter over/underflow? None.

Yes, the reference manual contains the description of the registers and registers bit. But, what I am looking for is an Example APP or a document which describes what I need to do and why (initialization, start, stop, clear, overflow handling) in order to be able to use Encoder. I could not find such document. I do not think it even exists.

Thank you for your help. I appreciate it very much.

Louie

The update event happens on overflow/underflow, which is piped out to HAL_TIM_PeriodElapsedCallback. If your encoder can change directions, a better method would be to poll the CNT/UIFCPY directly in order to handle underflow/overflows.
The reference manual is the best source of information on the details of the encoder. Not sure the documentation you're looking for exists.
If you feel a post has answered your question, please click "Accept as Solution".
Louie88
Associate III

Thanks TDK for the explanations, but the HAL_TIM_PeriodElapsedCallback() is never called back (in my case). The TIMER4 encoder gets 200 000 pulses under 10 seconds. The TIMER4 counter should overflow 3 times. But, if I set a breakpoint into the HAL_TIM_PeriodElapsedCallback() - where I increment the ecnoderPulsefOvf (Overflow) variable - then then the breakpoint is never hit.

Maybe I am doing something wrong. In main.c: enable TIMER4 interrupt:

// Set the TIM4 priority
	HAL_NVIC_SetPriority(TIM4_IRQn, 0, 1);
 
	// Enable the TIM4 global Interrupt
	HAL_NVIC_EnableIRQ(TIM4_IRQn);

In main.c: start encoder with interrupt:

if(HAL_OK != HAL_TIM_Encoder_Start_IT(&htim4, TIM_CHANNEL_ALL))
	{
		Error_Handler();
	}

In main.c: Handling the callback event:

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
	// Works?
	encoderPulsesOvf++;
}

In stm32h7xx_it.c: defining TIMER4 interrupt handler:

void TIM4_IRQHandler(void)
{
  HAL_TIM_IRQHandler(&htim4);
}

So what do you think? What am I doing wrong?

Thanks for your help!

Louis

It doesn't look like HAL_TIM_Encoder_Start_IT actually enable the update interrupt. You can do this manually after starting the encoder:

/* Enable the TIM Update interrupt */
__HAL_TIM_ENABLE_IT(&htim4, TIM_IT_UPDATE);

HAL_TIM_Encoder_Start_IT does enable the CC1 and CC2 interrupts, which are going to cause HAL_TIM_IC_CaptureCallback to get called. It looks like this is the way HAL intends you to use the encoder in timer mode. Set CCR1 to 0 and CCR2 to half-range to be able to detect overflows. Check for htim->Channel == HAL_TIM_ACTIVE_CHANNEL_1 or HAL_TIM_ACTIVE_CHANNEL_2 to see which is getting called.

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

Hi TDK,

Genius! That solved my interrupt problem. Many thanks for the suggestion.

However, as I mentioned it earlier, if I enable TIMER4 CH1 = PD12 and CH2 = PD13 then the touch screen initialization returns error. I checked it and I found this is because the I2C controller of the touch screen uses PD12/13 as data/clock line. That means TIMER4 can't be used with touch screen at the same time. Too bad!

I also found that TIMER8 can be used. The CH1 and CH2 of TIMER8 can be PC6/7 ports. PC6/7 are used in camera driver which is not needed. The problem is when I try to enable the over/underflow interrupts for TIMER8 I get an error : TIM8_IRQn is not defined:

// Set the TIM8 priority
HAL_NVIC_SetPriority(TIM8_IRQn, 0, 1);
 
/* TDK: Enable the TIM Update interrupt */
__HAL_TIM_ENABLE_IT(&htim8, TIM_IT_UPDATE);
 
// Enable the TIM4 global Interrupt
HAL_NVIC_EnableIRQ(TIM8_IRQn);

I checked it and it is true. I have the following IRQ definitions only:

  TIM8_BRK_TIM12_IRQn         = 43,     /*!< TIM8 Break Interrupt and TIM12 global interrupt                   */
  TIM8_UP_TIM13_IRQn          = 44,     /*!< TIM8 Update Interrupt and TIM13 global interrupt                  */
  TIM8_TRG_COM_TIM14_IRQn     = 45,     /*!< TIM8 Trigger and Commutation Interrupt and TIM14 global interrupt */
  TIM8_CC_IRQn                = 46,     /*!< TIM8 Capture Compare Interrupt                                    */

My stupid question is which one I can use instead of TIM8_IRQn? Why does the HAL support different the TIMER8 and TIMER4?

Many thanks for your help.

Best regards,

Louis

The update interrupt will be sent to TIM8_UP_TIM13_IRQn as explained in the comment. Function names for them are in the vector table, which is typically included in your startup_*.s file. In this case, TIM8_UP_TIM13_IRQHandler.
TIM8 Interrupts being broken up isn't due to HAL, it's due to the silicon hardware and was a design choice.
If you feel a post has answered your question, please click "Accept as Solution".
Louie88
Associate III

Hi TDK,

Yes, I did that. The TIM8_UP_TIM13_IRQn was my first pick (before I asked you):

// Set the TIM8 priority
HAL_NVIC_SetPriority(TIM8_UP_TIM13_IRQn, 0, 1);
 
/* TDK: Enable the TIM Update interrupt */
__HAL_TIM_ENABLE_IT(&htim8, TIM_IT_UPDATE);
 
// Enable the TIM4 global Interrupt
HAL_NVIC_EnableIRQ(TIM8_UP_TIM13_IRQn);

The callback never hit:

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
	// Other timers can use this callback
	if (htim->Instance == TIM8)
		encoderPulsesOvf++;
}

Even it falls into a infinitive loop:

0693W00000D10lLQAR.pngIf I comment out "__HAL_TIM_ENABLE_IT(&htim8, TIM_IT_UPDATE)" then there is no inf. loop, but the callback is never hit.

I guess because the used the TIMER8 update IRQ, we do not need to enable it again. This seems to me logical, but why not the callback is not hit?

Any idea?

Thanks,

Louis

TDK
Guru

It's in an interrupt handler that you didn't define so it defaults to Default_Handler.

Ensure TIM8_UP_TIM13_IRQHandler is defined appropriately.

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

Hi TDK!

Super, as always, you are right, I used void TIM8_IRQHandler(void) which does not exist. Defining void TIM8_UP_TIM13_IRQHandler(void) solved the problem. One note: I still have to call __HAL_TIM_ENABLE_IT(&hTimer8, TIM_IT_UPDATE). Without this the callback function is never hit.

Both the ENCODER (TIMER8) and the touch screen works. Many thanks for your help.

Now the only thing left: how to measure the frequency of signals counted by TIMER8? Can I attach another timer (in order to measure the frequency) to the same pins (PC6/PC7) which are already used by TIMER8? Or I have to wire the signal connected to PC6/PC7 to other pins?

Thanks,

Louis

You attach those signals to another timer and use the other timer in input capture mode. Should be quite a few examples around of code which measure frequency.
If you feel a post has answered your question, please click "Accept as Solution".