Arduino millis() in stm32

17,234

Solution 1

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.

Solution 2

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

Solution 3

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.

Solution 4

I would suggest setting up your own timer.

To make a timer you must configure a prescalar and period in CubeMX or manually.
Clock Configuration

Because my clock is 72MHz this means I want a prescalar of 72MHz / 1MHz - 1 = 71 Consequently my period will be 1MHz / 1kHz - 1 = 999 because I want the interrupt to trigger once every 1 millisecond.
Prescalar Calculation

Here is how that looks in CubeMX.
Timer Configuration

Then you want to add a counter increment in the timer callback function.

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
  /* USER CODE BEGIN Callback 0 */
  if (htim->Instance == TIM10) {
    counter++;
  }
  /* USER CODE END Callback 0 */
  if (htim->Instance == TIM1) {
    HAL_IncTick();
  }
  /* USER CODE BEGIN Callback 1 */

  /* USER CODE END Callback 1 */
}

Solution 5

You need to initialise SysTick first, to tick at 1ms by initialising it with SystemCoreClock (Hz)/1000.

Share:
17,234
Admin
Author by

Admin

Updated on June 11, 2022

Comments

  • Admin
    Admin almost 2 years

    I am trying to port some Arduino library to stm32. In Arduino, millis() returns the number of milliseconds since boot. Is there an equivalent function in stm32? I am using stm32f0 MCU.