user6064424
user6064424

Reputation:

Arduino millis() in stm32

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.

Upvotes: 12

Views: 27260

Answers (8)

j.ramezanzadeh
j.ramezanzadeh

Reputation: 11

HAL library use a Timer(you can select it in the STM32CubeMX) to generate a Tick counter. every Tick takes 1ms. you can use it as follow to measure elapsed time:

   uint32_t startTime = HAL_GetTick();
                .
                .
                .
   uint32_t endTime = HAL_GetTick();
   uint32_t elapsedTime = endTime-startTime; // in ms 

Upvotes: 1

nbout
nbout

Reputation: 1269

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

Upvotes: 18

Danijel
Danijel

Reputation: 11

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

Upvotes: 1

bradleykohler96
bradleykohler96

Reputation: 113

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 */
}

Upvotes: 2

David.O
David.O

Reputation: 104

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.

Upvotes: 3

adrianzx
adrianzx

Reputation: 21

Well, I think I need more information for a proper answer, but I will give you my best shot.

A consideration you need to have for your application, if you are making a high resolution measurements (need exact time), you will need to provide an external crystal for the accuracy since the internal clocks of the MCU are not quite accurate.

Having that in mind, what you shall do is the following:

  1. Configure a TIM so it can execute an interruption every 1ms
  2. Enable the TIM interrupt,
  3. In the TIM interrupt, increase a counter ( this will be your time) that is defined as a global variable for this module.

void interrupt TIMX_interrupt(void){ counter++; // this will have the time count in MS. }

  1. Create a Function named millis() that return the counter something like:

uint32_t millis(void){ return counter; }

In this way you could use the same function in this MCU.

Upvotes: 0

Tom
Tom

Reputation: 929

In some situations you may not use SysTick for this purpose. For example when using FreeRTOS, which already implements SysTick. In this case, run your code in a task, and you can use vTaskDelay. Depending on what you would like to do, a software timer can also make the trick: http://www.freertos.org/FreeRTOS-Software-Timer-API-Functions.html

In case you cannot use SysTick, and you don't have FreeRTOS or similar, you can setup a Timer with an interrupt and place your code in the appropriate callback.

Upvotes: 0

Andy Brown
Andy Brown

Reputation: 12999

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.

Upvotes: 17

Related Questions