Configuring the rate of Timer interrupts for the STM32F4xx Discovery Board

armfrequencyinterruptsstm32f4timer

I'm working on a project with the STM32F407 board and Keil, and as part of a larger project I'm working on I need to configure a timer interrupt. Eventually it will run at around 46 kHz, but for now I'm just trying to control the rate at which it interrupts.

In it's current state I have the timer and interrupt working so that when TIM3 finishes counting up it's period, it throws an interrupt which I have a handler written for. I can then blink an LED or do whatever I need to in this handler. My problem is that no matter how I seem to configure it I can't adjust the rate at which it interrupts. I've put a counter that increments every time the interrupt is thrown. I've used this to time it and found that it seems to run at a rate of about 245 kHz (+/- maybe 5 kHz).

I've used the excel spreadsheet that generates the system_stm32f4xx file to configure for a clock of 168 MHz. I configure the TIM3 clock using the following function:

void InitializeTimer() {
    TIM_TimeBaseInitTypeDef SetupTimer;
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);

    SetupTimer.TIM_Prescaler = 167-1;
    SetupTimer.TIM_Period = 1000-1;
    SetupTimer.TIM_CounterMode = TIM_CounterMode_Up;
    SetupTimer.TIM_ClockDivision = TIM_CKD_DIV1;

    TIM_TimeBaseInit(TIM3, &SetupTimer);
    TIM_Cmd(TIM3, ENABLE); 
    TIM_ITConfig(TIM3, TIM_IT_Update, ENABLE);
}

I configure the interrupt with the following function:

void EnableTimerInterrupt()
{
    NVIC_InitTypeDef nvicStructure;
    nvicStructure.NVIC_IRQChannel = TIM3_IRQn;
    nvicStructure.NVIC_IRQChannelPreemptionPriority = 0;
    nvicStructure.NVIC_IRQChannelSubPriority = 1;
    nvicStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&nvicStructure);
}

Both are called from main in this order. Based on this post I found the above prescalar and period values to get an interrupt of 1 kHz. However this is not the case. In no particular order a list of things I've tried includes:

  • Numerous different combinations of prescalar/period values
  • Changing the the HSE_VALUE in stm32f4xx.h from 25 MHz to 8 MHz (everything I've seen says the external oscillator runs at 8 MHz, not 25; but the that's what the excel file configured it to
  • adding the following to my Timer initialization function:

    uint16_t prescalar_val = (uint16_t) ((SystemCoreClock / 2) / 6000000) - 1; //6 MHz
    ...
    TIM_PrescalerConfig(TIM3, prescalar_val, TIM_PSCReloadMode_Immediate);
    

    Which is a code snippet I found that said it configures the timer to run at 6 MHz

I'm pretty much stumped at this point. I've read this document's section on general purpose timers (ch 18), and based on that and other examples I've found online I'm doing everything right. Maybe there's something I'm missing, which wouldn't be very surprising – I'm pretty new at this. In a worst case scenario I just use the interrupt as is, and use a counter to divide the frequency, but that seems like a pretty silly solution.

Any help anyone could give me would be greatly appreciated. If someone wants to look at any other file or function in particular I can post it.

Best Answer

So after much frustration I figured out how to scale my timer/interrupt. I was trying to do it all at once instead of develop it incrementally.

In case anyone finds this question I found this article and followed its step by step instructions - configuring the timer, then the interrupt, then the interrupt handler. I think my issue was that I was not clearing the Pending Bit after each interrupt, as they do in step 9:

TIM_ClearITPendingBit(TIM2, TIM_IT_Update);

Adding that to the end of my interrupt handlers seemed to do the trick. I can scale timing as I would expect to by providing variable arguments to the prescalar and period.