Periodic Timer on other Interrupts ( via HAL )?

19 Sep 2016

i have just returned from an odyssey into timers on STM32. my goal was to write a sketch that uses a periodic interrupt to drive a DAC at an audio rate ( 20KHz – 48KHz ). i want to share some of my findings and also ask a question.

first i did the obvious and used the mbed Ticker class to configure a callback at 40 μsec. the following snippet illustrates what i want to achieve ( i replaced the DAC with an LED and reduced the update rate for illustration purposes ):

mbed_ticker_approach

#include "mbed.h"

DigitalOut            myled(LED2);
Ticker mTicker;

void ticker_callback() {
  myled = !myled;
}

int main() {
  mTicker.attach(ticker_callback, 0.5f);
  while(1) {}
}

it worked ok-ish but i experienced some weird timing inconsistencies as soon as computations became more demanding. i found out that mbed uses just a single interrupt to drive all kinds of timing tasks. based on this understanding, i decided to investigate if a dedicated interrupt might work more reliably. after a lot of research i found an STM32-specfic solution that makes use of the underlying HAL:

nvic_and_HAL_approach

#include "mbed.h"

#define TIM_USR      TIM3
#define TIM_USR_IRQ  TIM3_IRQn

DigitalOut myled(LED2);
TIM_HandleTypeDef mTimUserHandle;

extern "C"
void M_TIM_USR_Handler(void) {
  if (__HAL_TIM_GET_FLAG(&mTimUserHandle, TIM_FLAG_UPDATE) == SET) {
    __HAL_TIM_CLEAR_FLAG(&mTimUserHandle, TIM_FLAG_UPDATE);
    myled = !myled;
  }
}

int main() {
  __HAL_RCC_TIM3_CLK_ENABLE();

  mTimUserHandle.Instance               = TIM_USR;
  mTimUserHandle.Init.Prescaler         = 47999;
  mTimUserHandle.Init.CounterMode       = TIM_COUNTERMODE_UP;
  mTimUserHandle.Init.Period            = 500; // 0.5 sec interval at 48 MHz MCU speed
  mTimUserHandle.Init.ClockDivision     = TIM_CLOCKDIVISION_DIV1;
  HAL_TIM_Base_Init(&mTimUserHandle);
  HAL_TIM_Base_Start_IT(&mTimUserHandle);

  NVIC_SetVector(TIM_USR_IRQ, (uint32_t)M_TIM_USR_Handler);
  NVIC_EnableIRQ(TIM_USR_IRQ);

  while(1) {}
}

// see also this thread: https://developer.mbed.org/users/AjK/notebook/getting-closer-to-the-hardware/
// and this thread: https://developer.mbed.org/forum/mbed/topic/16541/

the code above works fine for my setup. however, when i choose a different timer than timer 3 ( TIM3 ), the callback never happens ( although the application runs ). on my nucleo_f072rb board mbed is using timer 2 for its timing task but the others ( e.g TIM6, TIM7, or TIM15 ) should be available according to what i found out about mbed.

i am puzzled to what causes this behavior: is there something i am missing about the internals of mbed or am i just doing something plain wrong in my code?

on a side note: i get the timers to work when i do it in plain HAL with STM32CubeMX + SW4STM32, though using a different callback mechanic ( via HAL_TIM_PeriodElapsedCallback ).

21 Sep 2016

grmpf, i found the problem __HAL_RCC_TIM3_CLK_ENABLE(); needs to be adjusted to different timers of course.