Arduino millis() in stm32

You could use HAL_GetTick(): this function gets current SysTick counter value (incremented in SysTick interrupt) used by peripherals drivers to handle timeouts.


I would suggest to do it with timer. In this way you also can get 1us step, just control your time step size. Anyway most of STM32 MCU's has 8 or more timers, so in most cases you are free to take one. I'll show very simple basic idea how to do it.

Just create timer:

uint32_t time = 0;

void enable_timer(void){
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM16, ENABLE);
    TIM_TimeBaseInitTypeDef timerInitStructure;

    /* if MCU frequency 48 MHz, prescaler of value 48 will make 1us counter steps
    timerInitStructure.TIM_Prescaler = 48;

    timerInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
    /*how often you'll get irq*/
    timerInitStructure.TIM_Period = 0xFFFF; // will get irq each 65535us on TIMx->CNT overflow
    timerInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
    TIM_TimeBaseInit(TIM16, &timerInitStructure);
    TIM_Cmd(TIM16, ENABLE);
    NVIC_InitTypeDef NVIC_InitStruct;
    NVIC_InitStruct.NVIC_IRQChannel = TIM16_IRQn;
    /*for more accuracy irq priority should be higher, but now its default*/
    NVIC_InitStruct.NVIC_IRQChannelPriority = 0;
    NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
    TIM_ClearITPendingBit(TIM16,TIM_IT_Update);
    NVIC_Init(&NVIC_InitStruct);
    TIM_ITConfig(TIM16,TIM_IT_Update,ENABLE);
}

at IRQ you have to control overflows of timer counter and update your global time

void TIM16_IRQHandler(void){
if (TIM_GetITStatus(TIM16, TIM_IT_Update) != RESET){
    TIM_ClearITPendingBit(TIM16, TIM_IT_Update);
    time +=65535;
}

}

And real time will be :

uint32_t real_time_us = time + (uint32_t)TIM16->CNT;

But if you are free to use 32 bit timer you can even do it without IRQ, just simply time= TIMx->CNT. Yea it depends on timer configuration and your needs, also you have to know that uint32_t time variable also can overflow, but that's a details, it can be managed easily.


SysTick is an ARM core peripheral provided for this purpose. Adapt this to your needs:

Firstly, initialise it

// Initialise SysTick to tick at 1ms by initialising it with SystemCoreClock (Hz)/1000

volatile uint32_t counter = 0;
SysTick_Config(SystemCoreClock / 1000);

Provide an interrupt handler. Your compiler may need interrupt handlers to be decorated with additional attributes.

SysTick_Handler(void) {
  counter++;
}

Here's your millis() function, couldn't be simpler:

uint32_t millis() {
  return counter;
}

Some caveats to be aware of.

  1. SysTick is a 24 bit counter. It will wrap on overflow. Be aware of that when you're comparing values or implementing a delay method.

  2. SysTick is derived from the processor core clock. If you mess with the core clock, for example slowing it down to save power then the SysTick frequency must be manually adjusted as well.