cancel
Showing results for 
Search instead for 
Did you mean: 

How to use Timers ?

Gnahore
Senior

Hi, I'm learning how to use timers by following digikey's tutorial : Getting Started with STM32 and Nucleo Part 6: Timers and Timer Interrupts | Digi-Key Electronics - YouTube

However at 9:41 in the video I don't understand the code : 

// If enough time has passed (1 second), toggle LED and get new timestamp
if (__HAL_TIM_GET_COUNTER(&htim16) - timer_val >= 10000)
{
HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_5);
timer_val = __HAL_TIM_GET_COUNTER(&htim16);
}

What does  __HAL_TIM_GET_COUNTER(&htim16) really do? Then what the condition if is testing? 

 

Thanks

1 ACCEPTED SOLUTION

Accepted Solutions
Issamos
Lead II

Hello @Gnahore 

This part of the code is testing if the difference between TIMER_CNT(now)  and TIMER_CNT went the TIMER start counting (timer_val)is equal to 10000. Which means that the TIMER has counted 1 Second. 

If so, the code toggle the led and update the timer_val with the new TIMER_CNT value to restart a 1 Second count .

Rq: 10000 is calculated depends on the timer frequency and other  conditions that are well explained in the tutorial.

Best regards.

II

View solution in original post

11 REPLIES 11
Imen.D
ST Employee

Hello @Gnahore,

The HAL_TIM_GET_COUNTER is used to get the current TIM Counter Register value on runtime (from the CNT register), and return 16-bit or 32-bit value of the timer counter register (TIMx_CNT).

Imen

When your question is answered, please close this topic by clicking "Accept as Solution".
Thanks
Imen
Issamos
Lead II

Hello @Gnahore 

This part of the code is testing if the difference between TIMER_CNT(now)  and TIMER_CNT went the TIMER start counting (timer_val)is equal to 10000. Which means that the TIMER has counted 1 Second. 

If so, the code toggle the led and update the timer_val with the new TIMER_CNT value to restart a 1 Second count .

Rq: 10000 is calculated depends on the timer frequency and other  conditions that are well explained in the tutorial.

Best regards.

II

> What does  __HAL_TIM_GET_COUNTER(&htim16) really do?

You can find out yourself, Cube is open source, so you can read its sources and/or step through the code in debugger.

https://github.com/STMicroelectronics/STM32CubeF3/blob/121e4039445ba59f284ebff013d8b3782d503e9f/Drivers/STM32F3xx_HAL_Driver/Inc/stm32f3xx_hal_tim.h#L1466

JW

Btw. there is also a problem with this code:

If you'd observe timer_val in a debugger, you'd see that it changes in this way: 0-10000-20000-30000-40000-50000-60000-0-10000-20000-... etc. It means, that every 7th interval (between 60000 and 0) is half the expected lenght, as it lasts only 0.5536 seconds. And yes, it's clearly visible on the LED blinking.

This is due to the facts that a) TIM16 is 16-bit timer; b) STM32 is a 32-bit mcu thus int type is 32-bit wide; c) integer promotion rules in C are at times really tricky (although they are logical and straightforward, but sometimes understanding logical and straightforward things requires significant effort).

Correctly, the 16-bit rollover should be handled like this:

 if ((uint16_t)(__HAL_TIM_GET_COUNTER(&htim16) - timer_val) >= 10000)

now timer_val will go like

... 50000-60000-4464-14464...

JW

@Issamos Thank you for your answers ! But I'm still very confused. HAL_TIM_GET_COUNTER() get the tim counter register value on runtime since the start of the timer with the function HAL_TIM_Base_Start(), right?  And timer_val was also set with HAL_TIM_GET_COUNTER(). So timer_val is a fixed value and HAL_TIM_Base_Start() is the one that inscrease.

Does HAL_TIM_GET_COUNTER() start at 0 when it is called in the test? Also does timer_val as for first value 0? I wonder if by the time, the timer started thanks to HAL_TIM_Base_Start() and the time the value is put in timer_val, the value of timer_val is really 0.

I'm slowly understanding but what happens when timer_val get 60000 as value? HAL_TIM_Base_Start() can't go above 65 536

 

Here is the full code : 

/* Includes ------------------------------------------------------------------*/
#include "main.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */

/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */

/* USER CODE END PTD */

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
/* USER CODE END PD */

/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */

/* USER CODE END PM */

/* Private variables ---------------------------------------------------------*/
TIM_HandleTypeDef htim16;

UART_HandleTypeDef huart2;

/* USER CODE BEGIN PV */

/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_USART2_UART_Init(void);
static void MX_TIM16_Init(void);
/* USER CODE BEGIN PFP */

/* USER CODE END PFP */

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */

/* USER CODE END 0 */

/**
* @brief The application entry point.
* @retval int
*/
int main(void)
{
/* USER CODE BEGIN 1 */
uint16_t timer_val;

/* USER CODE END 1 */

/* MCU Configuration--------------------------------------------------------*/

/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();

/* USER CODE BEGIN Init */

/* USER CODE END Init */

/* Configure the system clock */
SystemClock_Config();

/* USER CODE BEGIN SysInit */

/* USER CODE END SysInit */

/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_USART2_UART_Init();
MX_TIM16_Init();
/* USER CODE BEGIN 2 */

// Start timer
HAL_TIM_Base_Start(&htim16);

// Get current time (microseconds)
timer_val = __HAL_TIM_GET_COUNTER(&htim16);

/* USER CODE END 2 */

/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
// If enough time has passed (1 second), toggle LED and get new timestamp
if (__HAL_TIM_GET_COUNTER(&htim16) - timer_val >= 10000)
{
HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_5);
timer_val = __HAL_TIM_GET_COUNTER(&htim16);
}

/* USER CODE END WHILE */

/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}

 

Thanks for answering @waclawek.jan 

How does timer_val go back to 0 ? From what I understood HAL_TIM_GET_COUNTER don't go above 65 536 so at what moment 

HAL_TIM_GET_COUNTER(&htim16) - timer_val) >= 10000

can happen when timer_val reached 60 000 ? 

Gnahore
Senior

Any answer ?

Hello @Gnahore 

I don't have a clear answer to your question but I suggest you to close these post by choosing a best answer and copie your new request to a new post to give him more visibility.

Best regards.

II

How does timer_val go back to 0 ? From what I understood HAL_TIM_GET_COUNTER don't go above 65 536 so at what moment 

HAL_TIM_GET_COUNTER(&htim16) - timer_val) >= 10000

can happen when timer_val reached 60 000 ? 

In this case, the subtraction is between unsigned variables, and that, according to C99 conversion rules, results in an unsigned value. So, when TIM_CNT rolls over from 65535 to 0, the subtraction result is 0x0000'0000-0x0000'EA60 = 0xFFFF'15A0 and that is higher than 10000.

> does timer_val as for first value 0?

Well spotted - as an uninitialized local variable, timer_val has a "random" initial value, so that's another bug in that program. However, due to the just described unsigned subtraction and the range of TIMx_CNT, the first period won't last longer than 1s, and most probably (for most timer_val values) the program won't wait at all in the first period.

JW