Electronic – How to use SysTick_Handler (an HAL library function) in order to have a time base

chal-librarymicrocontrollerstm32stm32cubemx

In actual I need to measure speed of motor.
I have followed a procedure, i.e

  1. use Encoder mode to get pulses from sensor.
  2. count number of these pulses in 1 sec~1000msec using SysTick_Handler(ISR). Means use SysTick_Handler function as a time base to count pulses in 1000msec.

Now, I am bit confused about how to encorporate step no. 2 in codes. Because I have been taught that Systick Handler(ISR) is called every 1 millisecond. And if it is so, while passing through lines of codes inside Handler, will the duration of 1 millisecond sec not get passed. Will the Systick_Handler not get called again before even completely counting for 1 millisecond. Also, how do I make sure that the Systick_Handler counts for only one second and then again starts counting afresh after duration of 1 sec gets over.

This is the Handler function.

void SysTick_Handler(void)
{
  HAL_IncTick();
  HAL_SYSTICK_IRQHandler();
  Encoder_Start();                     //encoder mode start

  counter=Encoder_Read(void);          //reading counter(defined globally and shared by handler and main)

  Encoder_Stop();                      //encoder mode stop

} 

And this is the main

    main.c
    .
    .
    .
    uint32_t Encoder_Read(void)         //reads counts from sensor
    {
        return TIM3->CNT;
    }

    void Encoder_Start(void)            
    {
        HAL_TIM_Encoder_Start(&htim3, TIM_CHANNEL_ALL);
    }

    void Encoder_Stop(void)
    {
        HAL_TIM_Encoder_Stop(&htim3, TIM_CHANNEL_ALL);
    }
    main()
{
 .
 .
    while()                                                              
    {
      speed=counter*constant;              //speed, counter is used here

      printf("\n%d",speed);                //print speed using semihosting on eclipse
      PWM code;
      PWM code;
      PWM code;
    }
.
.
}

My original question was this

Development board is STM32F407, OS is Linux(Ubuntu), code is generated using STM32CubeMX.

Any ideas about this?

Or any other alternative, I need to have a time base of 1 sec to measure the number of counts from sensor(LM393 based) and use this time base again and again to measure the speed and display it every second.

Best Answer

What you're looking for is probably just a basic scheduler. Example code:

static volatile uint32_t ms_ticks = 0;
static volatile bool tick_1ms_elapsed = false;
static volatile bool tick_1000ms_elapsed = false;

//! The interrupt handler for the SysTick module
void SysTick_Handler(void)
{
    ms_ticks++;

    tick_1ms_elapsed = true;

    if (ms_ticks % 1000 == 0) {
        tick_1000ms_elapsed = true;
    }
}

void main(void) {

    // Setup SysTick Timer for 1ms interrupts
    if (SysTick_Config(sysclk_get_cpu_hz() / 1000)) {
        while (true) {  /* no error must happen here, otherwise this board is dead */ }
    }

    while(true) {

        if (tick_1ms_elapsed) {
            ... Do something every ms
            tick_1ms_elapsed = false; // Reset the flag (signal 'handled')
        }

        if (tick_1000ms_elapsed) {
            ... Do something every second
            if (state == STATE_1) {
                DoTaskOne;
                state = STATE_2;
            }
            else if (state == STATE_2) {
                DoTaskTwo;
                state = STATE_3;
            }
            tick_1000ms_elapsed = false;  // Reset the flag (signal 'handled')
        }
    }
}

What does this do?

  • We initialize the Systick timer to trigger an interrupt every millisecond.
  • Since having long interrupt handlers is a no go, the only thing we do is to handle a flag which tells our main routing (which is handled during normal program flow and not within the interrupt routine) that 1 millisecond has passed
  • Additionally we increment a counter 'ms_ticks' which knows the current 'time' (time as in milliseconds since program start). We can always query that timer to know how much time has passed.

What your next tasks are going to be (at least if I understand you right):

  • Since you want to handle three events which happen after each other each second, you will need to create a state machine which runs inside the 1000ms tick handler.
  • Switch from one state to the next whenever you've completed the task for the current run, then wait until the flag arrives the next time and you will know another second has passed.