Help! TIM3 hardware timer is running 10* faster than configured

Post here all questions related to STM32 core if you can't find a relevant section!
Bambo
Posts: 60
Joined: Wed Jan 15, 2020 8:36 pm

Help! TIM3 hardware timer is running 10* faster than configured

Post by Bambo »

Hi, i've got an issue with the harwdare timer running 10* as fast as the configured amount. I have configured the timer to run at 16000Hz (around 62 microseconds per tick) but when measuring it, its ticking at around 6 microseconds.

Here's how i'm configuring a hardware timer (TIM3) using the https://github.com/stm32duino/wiki/wiki ... er-library library:

Code: Select all

       
        m_timer.pause();
        m_timer.setMode(1, TIMER_OUTPUT_COMPARE, NC);
        m_timer.setOverflow(16000, HERTZ_FORMAT);
        m_timer.detachInterrupt();
        m_timer.attachInterrupt(SampleTimer_Callback);
        m_timer.resume();
And i changed the configuration of the system clock to the following:

Code: Select all

#pragma once

extern "C" void SystemClock_Config(void) {
    RCC_OscInitTypeDef RCC_OscInitStruct = {};
    RCC_ClkInitTypeDef RCC_ClkInitStruct = {};
    RCC_PeriphCLKInitTypeDef PeriphClkInit = { 0 };

    /* Configure LSE Drive Capability */
    HAL_PWR_EnableBkUpAccess();
    __HAL_RCC_LSEDRIVE_CONFIG(RCC_LSEDRIVE_LOW);
    /* Initializes the CPU, AHB and APB busses clocks */
    RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_LSE | RCC_OSCILLATORTYPE_MSI;
    RCC_OscInitStruct.LSEState = RCC_LSE_ON;
    RCC_OscInitStruct.MSIState = RCC_MSI_ON;
    RCC_OscInitStruct.MSICalibrationValue = 0;
    RCC_OscInitStruct.MSIClockRange = RCC_MSIRANGE_6;
    RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
    RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_MSI;
    RCC_OscInitStruct.PLL.PLLM = 1;
    RCC_OscInitStruct.PLL.PLLN = 40;
    RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV7;
    RCC_OscInitStruct.PLL.PLLQ = RCC_PLLQ_DIV2;
    RCC_OscInitStruct.PLL.PLLR = RCC_PLLR_DIV2;
    if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) {
        Error_Handler();
    }
    /* Initializes the CPU, AHB and APB busses clocks */
    RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_SYSCLK
        | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2;
    RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
    RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
    RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
    RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;

    if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_4) != HAL_OK) {
        Error_Handler();
    }

    PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_SDMMC1 | RCC_PERIPHCLK_SAI1;
    PeriphClkInit.Sdmmc1ClockSelection = RCC_SDMMC1CLKSOURCE_PLLSAI1;
    PeriphClkInit.Sai1ClockSelection = RCC_SAI1CLKSOURCE_PLLSAI1;
    PeriphClkInit.PLLSAI1.PLLSAI1Source = RCC_PLLSOURCE_MSI;
    PeriphClkInit.PLLSAI1.PLLSAI1M = 1;
    PeriphClkInit.PLLSAI1.PLLSAI1N = 16;
    PeriphClkInit.PLLSAI1.PLLSAI1P = RCC_PLLP_DIV17;
    PeriphClkInit.PLLSAI1.PLLSAI1Q = RCC_PLLQ_DIV8;
    PeriphClkInit.PLLSAI1.PLLSAI1R = RCC_PLLR_DIV2;
    PeriphClkInit.PLLSAI1.PLLSAI1ClockOut = RCC_PLLSAI1_SAI1CLK | RCC_PLLSAI1_ADC1CLK| RCC_PLLSAI1_48M2CLK;
    if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK) {
        Error_Handler();
    }


    /* Configure the main internal regulator output voltage */
    if (HAL_PWREx_ControlVoltageScaling(PWR_REGULATOR_VOLTAGE_SCALE1) != HAL_OK) {
        Error_Handler();
    }

    /* Enable MSI Auto calibration */
    HAL_RCCEx_EnableMSIPLLMode();
}
I'm not sure how to fix the clock issue, the hardware timer must run at 16000hz, please help!

Edit:
calling getTimerClkFreq() returns "16608535"
by ABOSTM » Fri Apr 23, 2021 9:56 am
Have you test my sketch ? is it working ?
void TimerCallback()
{
uint32_t elapsed = micros() - timestamp;
Serial2.println(elapsed);
timestamp = micros();
}
I strongly suggest to not use print function in your interrupt callback, because is a long processing probably larger than the 62microseconds you are expecting. As a general rule, interrupt processing should be as short as possible, like writing some global variable, but not sending data on any bus.

The fact that you add a breakpoint will break the behavior: when processor is stopped (debugger break), some hardware continue to work, this is the case of timer (HardwareTimer) and I guess the same for micros() timer. So In such situation I can not guarantee any constant value.

Use pin toggle like I did and check with oscillo/logical-analyseur and I am convinced it will work.
Also you can store your measured value in callback in a global variable and print that variable regularly in loop() (so out of any interrupt)
Go to full post
mlundin
Posts: 75
Joined: Wed Nov 04, 2020 1:20 pm
Answers: 6
Location: Sweden

Re: Help! TIM3 hardware timer is running 10* faster than configured

Post by mlundin »

What processor is this ?
How do you measure the actual timer overflow frequency ?
Whats the value of SystemCoreClock ?
ABOSTM
Posts: 28
Joined: Wed Jan 08, 2020 8:40 am
Answers: 2

Re: Help! TIM3 hardware timer is running 10* faster than configured

Post by ABOSTM »

Besides mlundin questions, we also miss version of core you used.
Note: there is a new release 2.0 that just came out recently. I suggest you to use it.
m_timer.pause();
It looks like there was some previous configuration of HardwareTimer ...
So you provided some piece of you sketch, but it is much simplifier if you can provide a complet sketch (but minimal, meaning with only the HardwareTimer that reproduce your problem) so that we can try to reproduce easily.

I used the sketch below on a Nucleo_L476RG with your clock config and your 16000 HZ config of Hardwaretimer,
and it works perfectly: led/pin is toggled each 62ms (toggle is performed in callback)

This is a mix of your code and example https://github.com/stm32duino/STM32Exam ... llback.ino

Code: Select all

extern "C" void SystemClock_Config(void) {
    RCC_OscInitTypeDef RCC_OscInitStruct = {};
    RCC_ClkInitTypeDef RCC_ClkInitStruct = {};
    RCC_PeriphCLKInitTypeDef PeriphClkInit = { 0 };

    /* Configure LSE Drive Capability */
    HAL_PWR_EnableBkUpAccess();
    __HAL_RCC_LSEDRIVE_CONFIG(RCC_LSEDRIVE_LOW);
    /* Initializes the CPU, AHB and APB busses clocks */
    RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_LSE | RCC_OSCILLATORTYPE_MSI;
    RCC_OscInitStruct.LSEState = RCC_LSE_ON;
    RCC_OscInitStruct.MSIState = RCC_MSI_ON;
    RCC_OscInitStruct.MSICalibrationValue = 0;
    RCC_OscInitStruct.MSIClockRange = RCC_MSIRANGE_6;
    RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
    RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_MSI;
    RCC_OscInitStruct.PLL.PLLM = 1;
    RCC_OscInitStruct.PLL.PLLN = 40;
    RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV7;
    RCC_OscInitStruct.PLL.PLLQ = RCC_PLLQ_DIV2;
    RCC_OscInitStruct.PLL.PLLR = RCC_PLLR_DIV2;
    if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) {
        Error_Handler();
    }
    /* Initializes the CPU, AHB and APB busses clocks */
    RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_SYSCLK
        | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2;
    RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
    RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
    RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
    RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;

    if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_4) != HAL_OK) {
        Error_Handler();
    }

    PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_SDMMC1 | RCC_PERIPHCLK_SAI1;
    PeriphClkInit.Sdmmc1ClockSelection = RCC_SDMMC1CLKSOURCE_PLLSAI1;
    PeriphClkInit.Sai1ClockSelection = RCC_SAI1CLKSOURCE_PLLSAI1;
    PeriphClkInit.PLLSAI1.PLLSAI1Source = RCC_PLLSOURCE_MSI;
    PeriphClkInit.PLLSAI1.PLLSAI1M = 1;
    PeriphClkInit.PLLSAI1.PLLSAI1N = 16;
    PeriphClkInit.PLLSAI1.PLLSAI1P = RCC_PLLP_DIV17;
    PeriphClkInit.PLLSAI1.PLLSAI1Q = RCC_PLLQ_DIV8;
    PeriphClkInit.PLLSAI1.PLLSAI1R = RCC_PLLR_DIV2;
    PeriphClkInit.PLLSAI1.PLLSAI1ClockOut = RCC_PLLSAI1_SAI1CLK | RCC_PLLSAI1_ADC1CLK| RCC_PLLSAI1_48M2CLK;
    if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK) {
        Error_Handler();
    }


    /* Configure the main internal regulator output voltage */
    if (HAL_PWREx_ControlVoltageScaling(PWR_REGULATOR_VOLTAGE_SCALE1) != HAL_OK) {
        Error_Handler();
    }

    /* Enable MSI Auto calibration */
    HAL_RCCEx_EnableMSIPLLMode();
}


/*
  Timebase callback
  This example shows how to configure HardwareTimer to execute a callback at regular interval.
  Callback toggles pin.
  Once configured, there is only CPU load for callbacks executions.
*/

#if !defined(STM32_CORE_VERSION) || (STM32_CORE_VERSION  < 0x01090000)
#error "Due to API change, this sketch is compatible with STM32_CORE_VERSION  >= 0x01090000"
#endif

#if defined(LED_BUILTIN)
#define pin  LED_BUILTIN
#else
#define pin  D2
#endif

void Update_IT_callback(void)
{ // Toggle pin. 
  digitalWrite(pin, !digitalRead(pin));
}


void setup()
{
  TIM_TypeDef *Instance = TIM3;
  // Instantiate HardwareTimer object. Thanks to 'new' instanciation, HardwareTimer is not destructed when setup() function is finished.
  HardwareTimer *MyTim = new HardwareTimer(Instance);

  // configure pin in output mode
  pinMode(pin, OUTPUT);

  MyTim->setMode(1, TIMER_OUTPUT_COMPARE, NC);
  MyTim->setOverflow(16000, HERTZ_FORMAT);
  MyTim->attachInterrupt(Update_IT_callback);
  MyTim->resume();
}

void loop()
{
  /* Nothing to do all is done by hardware. Even no interrupt required. */
}
Bambo
Posts: 60
Joined: Wed Jan 15, 2020 8:36 pm

Re: Help! TIM3 hardware timer is running 10* faster than configured

Post by Bambo »

mlundin wrote:
Thu Apr 22, 2021 4:07 pm
What processor is this ?
How do you measure the actual timer overflow frequency ?
Whats the value of SystemCoreClock ?
Processor: STM32L452RE
Code to measure frequency:

Code: Select all

static HardwareTimer timer = HardwareTimer(TIM3);
static uint32_t timestamp = 0;

void TimerCallback()
{
    uint32_t elapsed = micros() - timestamp;
    Serial2.println(elapsed);
    timestamp = micros();
}
SystemCoreClock: 80000000

Code: Select all

    uint32_t sysclockfreq_pre = HAL_RCC_GetSysClockFreq();
Bambo
Posts: 60
Joined: Wed Jan 15, 2020 8:36 pm

Re: Help! TIM3 hardware timer is running 10* faster than configured

Post by Bambo »

ABOSTM wrote:
Thu Apr 22, 2021 6:24 pm
Besides mlundin questions, we also miss version of core you used.
Note: there is a new release 2.0 that just came out recently. I suggest you to use it.
m_timer.pause();
It looks like there was some previous configuration of HardwareTimer ...
So you provided some piece of you sketch, but it is much simplifier if you can provide a complet sketch (but minimal, meaning with only the HardwareTimer that reproduce your problem) so that we can try to reproduce easily.

I used the sketch below on a Nucleo_L476RG with your clock config and your 16000 HZ config of Hardwaretimer,
and it works perfectly: led/pin is toggled each 62ms (toggle is performed in callback)

This is a mix of your code and example https://github.com/stm32duino/STM32Exam ... llback.ino

Code: Select all

extern "C" void SystemClock_Config(void) {
    RCC_OscInitTypeDef RCC_OscInitStruct = {};
    RCC_ClkInitTypeDef RCC_ClkInitStruct = {};
    RCC_PeriphCLKInitTypeDef PeriphClkInit = { 0 };

    /* Configure LSE Drive Capability */
    HAL_PWR_EnableBkUpAccess();
    __HAL_RCC_LSEDRIVE_CONFIG(RCC_LSEDRIVE_LOW);
    /* Initializes the CPU, AHB and APB busses clocks */
    RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_LSE | RCC_OSCILLATORTYPE_MSI;
    RCC_OscInitStruct.LSEState = RCC_LSE_ON;
    RCC_OscInitStruct.MSIState = RCC_MSI_ON;
    RCC_OscInitStruct.MSICalibrationValue = 0;
    RCC_OscInitStruct.MSIClockRange = RCC_MSIRANGE_6;
    RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
    RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_MSI;
    RCC_OscInitStruct.PLL.PLLM = 1;
    RCC_OscInitStruct.PLL.PLLN = 40;
    RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV7;
    RCC_OscInitStruct.PLL.PLLQ = RCC_PLLQ_DIV2;
    RCC_OscInitStruct.PLL.PLLR = RCC_PLLR_DIV2;
    if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) {
        Error_Handler();
    }
    /* Initializes the CPU, AHB and APB busses clocks */
    RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_SYSCLK
        | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2;
    RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
    RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
    RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
    RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;

    if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_4) != HAL_OK) {
        Error_Handler();
    }

    PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_SDMMC1 | RCC_PERIPHCLK_SAI1;
    PeriphClkInit.Sdmmc1ClockSelection = RCC_SDMMC1CLKSOURCE_PLLSAI1;
    PeriphClkInit.Sai1ClockSelection = RCC_SAI1CLKSOURCE_PLLSAI1;
    PeriphClkInit.PLLSAI1.PLLSAI1Source = RCC_PLLSOURCE_MSI;
    PeriphClkInit.PLLSAI1.PLLSAI1M = 1;
    PeriphClkInit.PLLSAI1.PLLSAI1N = 16;
    PeriphClkInit.PLLSAI1.PLLSAI1P = RCC_PLLP_DIV17;
    PeriphClkInit.PLLSAI1.PLLSAI1Q = RCC_PLLQ_DIV8;
    PeriphClkInit.PLLSAI1.PLLSAI1R = RCC_PLLR_DIV2;
    PeriphClkInit.PLLSAI1.PLLSAI1ClockOut = RCC_PLLSAI1_SAI1CLK | RCC_PLLSAI1_ADC1CLK| RCC_PLLSAI1_48M2CLK;
    if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK) {
        Error_Handler();
    }


    /* Configure the main internal regulator output voltage */
    if (HAL_PWREx_ControlVoltageScaling(PWR_REGULATOR_VOLTAGE_SCALE1) != HAL_OK) {
        Error_Handler();
    }

    /* Enable MSI Auto calibration */
    HAL_RCCEx_EnableMSIPLLMode();
}


/*
  Timebase callback
  This example shows how to configure HardwareTimer to execute a callback at regular interval.
  Callback toggles pin.
  Once configured, there is only CPU load for callbacks executions.
*/

#if !defined(STM32_CORE_VERSION) || (STM32_CORE_VERSION  < 0x01090000)
#error "Due to API change, this sketch is compatible with STM32_CORE_VERSION  >= 0x01090000"
#endif

#if defined(LED_BUILTIN)
#define pin  LED_BUILTIN
#else
#define pin  D2
#endif

void Update_IT_callback(void)
{ // Toggle pin. 
  digitalWrite(pin, !digitalRead(pin));
}


void setup()
{
  TIM_TypeDef *Instance = TIM3;
  // Instantiate HardwareTimer object. Thanks to 'new' instanciation, HardwareTimer is not destructed when setup() function is finished.
  HardwareTimer *MyTim = new HardwareTimer(Instance);

  // configure pin in output mode
  pinMode(pin, OUTPUT);

  MyTim->setMode(1, TIMER_OUTPUT_COMPARE, NC);
  MyTim->setOverflow(16000, HERTZ_FORMAT);
  MyTim->attachInterrupt(Update_IT_callback);
  MyTim->resume();
}

void loop()
{
  /* Nothing to do all is done by hardware. Even no interrupt required. */
}

Running on STM32L452RE

Testing sketch code along with system clock configuration;

Code: Select all



#include "Sysclock_Config.h"

#include "stm32l4xx.h"
#include "stm32l4xx_hal.h"
#include "stm32l4xx_hal_conf.h"

#include "stm32_def.h"

void assert_failed(uint8_t* inFileName, uint32_t line)
{
    char* fileNameAsString = (char*)inFileName;
    Serial2.println(F("*** [HAL ASSERT FAILED] ***"));
    Serial2.printf("%s\r\n", (char*)inFileName);
    Serial2.printf("%i\r\n", line);
}
void _Error_Handler(const char* file, int line)
{
    Serial2.println(F("*** [ERROR HANDLED] ***"));
    Serial2.printf("%s\r\n", file);
    Serial2.printf("%i\r\n", line);
}

static HardwareTimer timer = HardwareTimer(TIM3);
static uint32_t timestamp = 0;

void TimerCallback()
{
    uint32_t elapsed = micros() - timestamp;
    Serial2.println(elapsed);
    timestamp = micros();
}

// the setup function runs once when you press reset or power the board
void setup() {
    delay(5000);

    Serial2.begin(115200);
    Serial2.println("Started");

    timer.setMode(1, TIMER_OUTPUT_COMPARE, NC); // remove this for new version of STM32Dino, required version 1.8.0.
    timer.setOverflow(16000, HERTZ_FORMAT);
    timer.detachInterrupt();
    timer.attachInterrupt(TimerCallback);
    timer.resume();
}

// the loop function runs over and over again until power down or reset
void loop() {
  
}

Code: Select all

#pragma once

extern "C" void SystemClock_Config(void) {
    RCC_OscInitTypeDef RCC_OscInitStruct = {};
    RCC_ClkInitTypeDef RCC_ClkInitStruct = {};
    RCC_PeriphCLKInitTypeDef PeriphClkInit = { 0 };

    /* Configure LSE Drive Capability */
    HAL_PWR_EnableBkUpAccess();
    __HAL_RCC_LSEDRIVE_CONFIG(RCC_LSEDRIVE_LOW);
    /* Initializes the CPU, AHB and APB busses clocks */
    RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_LSE | RCC_OSCILLATORTYPE_MSI;
    RCC_OscInitStruct.LSEState = RCC_LSE_ON;
    RCC_OscInitStruct.MSIState = RCC_MSI_ON;
    RCC_OscInitStruct.MSICalibrationValue = 0;
    RCC_OscInitStruct.MSIClockRange = RCC_MSIRANGE_6;
    RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
    RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_MSI;
    RCC_OscInitStruct.PLL.PLLM = 1;
    RCC_OscInitStruct.PLL.PLLN = 40;
    RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV7;
    RCC_OscInitStruct.PLL.PLLQ = RCC_PLLQ_DIV2;
    RCC_OscInitStruct.PLL.PLLR = RCC_PLLR_DIV2;
    if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) {
        Error_Handler();
    }
    /* Initializes the CPU, AHB and APB busses clocks */
    RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_SYSCLK
        | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2;
    RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
    RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
    RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
    RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;

    if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_4) != HAL_OK) {
        Error_Handler();
    }

    PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_SDMMC1 | RCC_PERIPHCLK_SAI1;
    PeriphClkInit.Sdmmc1ClockSelection = RCC_SDMMC1CLKSOURCE_PLLSAI1;
    PeriphClkInit.Sai1ClockSelection = RCC_SAI1CLKSOURCE_PLLSAI1;
    PeriphClkInit.PLLSAI1.PLLSAI1Source = RCC_PLLSOURCE_MSI;
    PeriphClkInit.PLLSAI1.PLLSAI1M = 1;
    PeriphClkInit.PLLSAI1.PLLSAI1N = 16;
    PeriphClkInit.PLLSAI1.PLLSAI1P = RCC_PLLP_DIV17;
    PeriphClkInit.PLLSAI1.PLLSAI1Q = RCC_PLLQ_DIV8;
    PeriphClkInit.PLLSAI1.PLLSAI1R = RCC_PLLR_DIV2;
    PeriphClkInit.PLLSAI1.PLLSAI1ClockOut = RCC_PLLSAI1_SAI1CLK | RCC_PLLSAI1_ADC1CLK| RCC_PLLSAI1_48M2CLK;
    if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK) {
        Error_Handler();
    }


    /* Configure the main internal regulator output voltage */
    if (HAL_PWREx_ControlVoltageScaling(PWR_REGULATOR_VOLTAGE_SCALE1) != HAL_OK) {
        Error_Handler();
    }

    /* Enable MSI Auto calibration */
    HAL_RCCEx_EnableMSIPLLMode();


}
The elapsed variable printed is still at around 6us instead of 62us.
Bambo
Posts: 60
Joined: Wed Jan 15, 2020 8:36 pm

Re: Help! TIM3 hardware timer is running 10* faster than configured

Post by Bambo »

If i use this code to timestamp the timer instead. I put a breakpoint at timestamp = timenow and the value of elapsed is closer to 60us, sometimes it is 40us, if i step through it it turns back into 6us. Shouldn't elapsed be a constant 62us?

Code: Select all

static HardwareTimer timer = HardwareTimer(TIM3);
static uint32_t timestamp = 0;

void TimerCallback()
{
    uint32_t timenow = micros();
    uint32_t elapsed = timenow - timestamp;
    timestamp = timenow;
}
ag123
Posts: 731
Joined: Thu Dec 19, 2019 5:30 am
Answers: 3

Re: Help! TIM3 hardware timer is running 10* faster than configured

Post by ag123 »

try to print the values of the timer pre-scalars and ARR auto reload registers, just before you start the timer (i.e. just before timer.resume());
e.g.

Code: Select all

timer.refersh();
Serial.print("pre-scalar:");
Serial.println(timer.getPrescaleFactor());
Serial.print("overflow:");
Serial.println(timer.getOverflow());
...
timer.resume();
overflow is probably the ARR, check in the ref manual and codes.

then check the systemclock speeds and bus speeds take those divide by pre-scalar and ARR to see if you are getting the period you are expecting.
this step would need looking up the reference manuals for the registers and understand the timers itself.

if you have other interrupts or such running, do also check if the other isr or even in loop() if any of those codes disable interrupts etc.
Last edited by ag123 on Fri Apr 23, 2021 10:07 am, edited 3 times in total.
ABOSTM
Posts: 28
Joined: Wed Jan 08, 2020 8:40 am
Answers: 2

Re: Help! TIM3 hardware timer is running 10* faster than configured

Post by ABOSTM »

Have you test my sketch ? is it working ?
void TimerCallback()
{
uint32_t elapsed = micros() - timestamp;
Serial2.println(elapsed);
timestamp = micros();
}
I strongly suggest to not use print function in your interrupt callback, because is a long processing probably larger than the 62microseconds you are expecting. As a general rule, interrupt processing should be as short as possible, like writing some global variable, but not sending data on any bus.

The fact that you add a breakpoint will break the behavior: when processor is stopped (debugger break), some hardware continue to work, this is the case of timer (HardwareTimer) and I guess the same for micros() timer. So In such situation I can not guarantee any constant value.

Use pin toggle like I did and check with oscillo/logical-analyseur and I am convinced it will work.
Also you can store your measured value in callback in a global variable and print that variable regularly in loop() (so out of any interrupt)
Bambo
Posts: 60
Joined: Wed Jan 15, 2020 8:36 pm

Re: Help! TIM3 hardware timer is running 10* faster than configured

Post by Bambo »

ABOSTM wrote:
Fri Apr 23, 2021 9:56 am
Have you test my sketch ? is it working ?
void TimerCallback()
{
uint32_t elapsed = micros() - timestamp;
Serial2.println(elapsed);
timestamp = micros();
}
I strongly suggest to not use print function in your interrupt callback, because is a long processing probably larger than the 62microseconds you are expecting. As a general rule, interrupt processing should be as short as possible, like writing some global variable, but not sending data on any bus.

The fact that you add a breakpoint will break the behavior: when processor is stopped (debugger break), some hardware continue to work, this is the case of timer (HardwareTimer) and I guess the same for micros() timer. So In such situation I can not guarantee any constant value.

Use pin toggle like I did and check with oscillo/logical-analyseur and I am convinced it will work.
Also you can store your measured value in callback in a global variable and print that variable regularly in loop() (so out of any interrupt)
Yes you are correct, the timer is correctly running at 62us measuring using a global variable! :D

Code: Select all



#include "Sysclock_Config.h"

#include "stm32l4xx.h"
#include "stm32l4xx_hal.h"
#include "stm32l4xx_hal_conf.h"

#include "stm32_def.h"

void assert_failed(uint8_t* inFileName, uint32_t line)
{
    char* fileNameAsString = (char*)inFileName;
    Serial2.println(F("*** [HAL ASSERT FAILED] ***"));
    Serial2.printf("%s\r\n", (char*)inFileName);
    Serial2.printf("%i\r\n", line);
}
void _Error_Handler(const char* file, int line)
{
    Serial2.println(F("*** [ERROR HANDLED] ***"));
    Serial2.printf("%s\r\n", file);
    Serial2.printf("%i\r\n", line);
}

static HardwareTimer timer = HardwareTimer(TIM3);
static uint32_t timestamp = 0;
static uint32_t elapsed = 0;

void TimerCallback()
{
    uint32_t timenow = micros();
    elapsed = timenow - timestamp;
    timestamp = timenow;
    delayMicroseconds(30);
}

// the setup function runs once when you press reset or power the board
void setup() {
    delay(5000);

    Serial2.begin(115200);
    Serial2.println("Started");

    timer.setMode(1, TIMER_OUTPUT_COMPARE, NC); // remove this for new version of STM32Dino, required version 1.8.0.
    timer.setOverflow(16000, HERTZ_FORMAT);
    timer.detachInterrupt();
    timer.attachInterrupt(TimerCallback);
    timer.resume();
}

// the loop function runs over and over again until power down or reset
void loop() {
    Serial2.print("Time taken");
    Serial2.println(elapsed);
}

I have added the delayMicroseconds(30) to simulate the real programs isr load, and it still works perfectly, there must be some other issue (like you suggested). :?:
Bambo
Posts: 60
Joined: Wed Jan 15, 2020 8:36 pm

Re: Help! TIM3 hardware timer is running 10* faster than configured

Post by Bambo »

Ok so i found that the issue is if i call

Code: Select all

HAL_StatusTypeDef status = HAL_SAI_Receive(saiHandle,
			dataBuffer,
			2U,
			1);
Inside the ISR loop, the main loop() is stopped being called after a few ticks. I'm going to try to use the SAI interrupts instead of the polling mode to see if that will help?

note: strangely i had the exact same HAL_SAI_Receive() call running inside an 16000hz timer on a previous device and it worked fine, but now it gets stuck inside the ISR.
Post Reply

Return to “General discussion”