cancel
Showing results for 
Search instead for 
Did you mean: 

TIM4 questions - basic

kamputty
Associate II
Posted on March 23, 2010 at 03:15

TIM4 questions - basic

8 REPLIES 8
Andrew Neil
Evangelist III
Posted on May 17, 2011 at 13:44

By ''callback routine'' do you mean an interrupt handler?

kamputty
Associate II
Posted on May 17, 2011 at 13:44

Hi Neil,

Yes, interrupt handler.

I'm trying to get a real grasp of the timers, so I would like to create ''hello worlds'' showing

#1. using the System Ticker - Done

#2. Setting Timer4 for a one second interrupt (calling a routine just like I did with the System Ticker)

#3. Setting up Timer4 to show PWM

Tomas DRESLER
Senior II
Posted on May 17, 2011 at 13:44

Hi, did you enable the interrupt in the NVIC?

You have to do 4 tasks, if TIM4 shows activity (which I guess does):

1. select the source of interrupt (I guess overflow is OK) and enable the IT generation for it in TIM4

2. configure priority in NVIC for this source and enable it

3. write the interrupt handler body for TIM4_IRQ_Handler (or whatever routine name you will find in interrupt vector table on the TIM4 location)

4. don't forget to clear the TIM4 OVF flag in the IRQ routine

Good luck (or use FW library and some examples ;)
tiago
Associate II
Posted on May 17, 2011 at 13:44

Hi Putty.

I'll try to answer some of your questions...

To understand timer operation you need first to understand basic concepts from CortexM3 buses and clocks. This is not explained by ST datasheets because ARM Cortex M3 manual covers it.

Search for ''ARM Cortex M3 Technical Reference Manual'' on Google and you'll find.

Take a look at STM32 Reference manual page 108 ''Clock Tree'' figure.

First you need to setup your system clock (SYSCLK, in the figure). After that

you must choose AHB and APB1 prescaler. Timer4 is sourced by APB1 bus...

For example, SYSCLK is 40MHz, AHB prescaler = 1 that gives a 40MHz to AHB bus. APB1 prescaler is 4, which gives a clock of 10MHz to the peripherals atached to it. As noted inside the block sourcing timers clock, this 10MHz is multiplied by 2 for timers. Thus, timer clock base will be 20MHz.

Now you can configure your timer. Below is the code I'm using for TIM3 (same parameters for TIM4):

    RCC_APB1ENR->TIM3EN = 1; //enable clock to timer

    TIM3_CR1->CEN = 0; //disable timer to begin configuration

    TIM3_CR1->ARPE = 1; //auto reload counter value

    TIM3_PSC = 1000; //prescaler. Timer clock == 20MHz / 1000 (50 us)

    TIM3_ARR = 70; //auto reload value

    TIM3_CNT = 0; //clear counter value

    TIM3_DIER->UIE = 1; //enable interrupt on overflow

    //NVIC configuration (explanation below)

    setBit(IRQ_CLRPEND0, BIT29); //clear pending interrupt

    setBit(IRQ_SETENA0, BIT29); //enable interrupt    

    TIM3_CR1->CEN = 1;    //enable timer

In this example, timer will count up to 70, which gives an interruption

every 3.5 ms (70 x 50us).

NVIC is the Cortex M3 controller. Almost all interrupts are controlled by NVIC (see Cortex M3 reference manual). Your systick interrupt has worked because it's not controlled by NVIC.

Finaly the interruption routine:

void TIM3_IRQHandler(void)

{

  TIM3_SR->field.UIF = 0;      //clear interrupt flag

  setBit(IRQ_CLRPEND0, BIT29); //clear NVIC pending interrupt

}

This is declared in ''stm32f10x_vector.c'' file from ST Library. Also take look at ''stm32f10x_it.c'' and ''stm32f10x_it.h'' files. Take a look there and see if its clear to you.

A lot information but I think now you have a direction to folow.

Hope this helps.

kamputty
Associate II
Posted on May 17, 2011 at 13:44

Hi Edison and Hagar (and everyone else!)

Well, I can compile (!) but still alittle ''lost''

Here is my program so far...

#include ''stdint.h''

#include ''targets/STM32F10x.h''

// LED1 is on PC12

// The button is on PA0

#define SET_BIT(REG, BIT)     ((REG) |= (BIT))

#define CLEAR_BIT(REG, BIT)   ((REG) &= ~(BIT))

#define READ_BIT(REG, BIT)    ((REG) & (BIT))

#define CLEAR_REG(REG)        ((REG) = (0x0))

#define WRITE_REG(REG, VAL)   ((REG) = (VAL))

#define READ_REG(REG)         ((REG))

#define MODIFY_REG(REG, CLEARMASK, SETMASK)  WRITE_REG((REG), (((READ_REG(REG)) & (~(CLEARMASK))) | (SETMASK)))

volatile uint32_t flag=1;

// init's the LED on RA12

void initLED(void)

{

    // configure LED ports

    RCC_APB2ENR |= RCC_APB2ENR_IOPCEN;

    uint32_t pin = 4;

    uint32_t mode = (uint32_t)0x05 << (pin * 4);

    uint32_t mask = (uint32_t)0x0f << (pin * 4);

    uint32_t temp = GPIOC_CRH & ~mask;

    GPIOC_CRH = temp | mode;

}

// crossworks handler name

void TIM3_IRQHandler(void)

{

    if(flag==1)

    {

        GPIOC_BSRR  = (1<<12);   // turn on LED

        flag=0;

    }

    else

    {

        GPIOC_BRR = (1<<12);    // turn off LED

        flag=1;

    }

    CLEAR_BIT(TIM3_SR, TIM3_SR_UIF_MASK);

    SET_BIT(Irq_0_to_31_Clear_Pending, 1 << 29);

}

// I'm running at 72MHz

// I want a one second ''beat''

void initTim3()

{

    SET_BIT(RCC_APB1ENR, RCC_APB1ENR_TIM3EN);

    CLEAR_BIT(TIM3_CR1, TIM3_CR1_CEN_MASK);

    SET_BIT(TIM3_CR1, TIM3_CR1_ARPE);

    WRITE_REG(TIM3_PSC, 1000);

    WRITE_REG(TIM3_ARR, 70);

    WRITE_REG(TIM3_CNT, 0);

    SET_BIT(TIM3_DIER, TIM3_DIER_UIE);

    SET_BIT(Irq_0_to_31_Clear_Pending, 1 << 29);

    SET_BIT(Irq_0_to_31_Set_Enable, 1 << 29);

}

void main(void)

{

    initLED();

    initTim3();

    while(1)

    {

    }

}

When I run it, the LED stay on and that's it! Booooooo....

I know I need to adjust some numbers because I'm running at 72MHz so my PCS and ARR values need adjusting...

Any [more] pointers would be gratly appreciated!

kamputty
Associate II
Posted on May 17, 2011 at 13:44

oops, forgot to enable the timer! DOH! Still does not work...boo...

#include ''stdint.h''

#include ''targets/STM32F10x.h''

// LED1 is on PC12

// The button is on PA0

#define SET_BIT(REG, BIT)     ((REG) |= (BIT))

#define CLEAR_BIT(REG, BIT)   ((REG) &= ~(BIT))

#define READ_BIT(REG, BIT)    ((REG) & (BIT))

#define CLEAR_REG(REG)        ((REG) = (0x0))

#define WRITE_REG(REG, VAL)   ((REG) = (VAL))

#define READ_REG(REG)         ((REG))

#define MODIFY_REG(REG, CLEARMASK, SETMASK)  WRITE_REG((REG), (((READ_REG(REG)) & (~(CLEARMASK))) | (SETMASK)))

volatile uint32_t flag=1;

// init's the LED on RA12

void initLED(void)

{

    // configure LED ports

    RCC_APB2ENR |= RCC_APB2ENR_IOPCEN;

    uint32_t pin = 4;

    uint32_t mode = (uint32_t)0x05 << (pin * 4);

    uint32_t mask = (uint32_t)0x0f << (pin * 4);

    uint32_t temp = GPIOC_CRH & ~mask;

    GPIOC_CRH = temp | mode;

}

// crossworks handler name

void TIM3_IRQHandler(void)

{

    if(flag==1)

    {

        GPIOC_BSRR  = (1<<12);   // turn on LED

        flag=0;

    }

    else

    {

        GPIOC_BRR = (1<<12);    // turn off LED

        flag=1;

    }

    CLEAR_BIT(TIM3_SR, TIM3_SR_UIF_MASK);

    SET_BIT(Irq_0_to_31_Clear_Pending, 1 << 29);

}

// I'm running at 72MHz

// I want a one second ''beat''

void initTim3()

{

    SET_BIT(RCC_APB1ENR, RCC_APB1ENR_TIM3EN);       // enable clock to timer

    CLEAR_BIT(TIM3_CR1, TIM3_CR1_CEN_MASK);         // disable tim3

    SET_BIT(TIM3_CR1, TIM3_CR1_ARPE);               // auto reload counter value

    WRITE_REG(TIM3_PSC, 1000);                      // set PSC

    WRITE_REG(TIM3_ARR, 70);                        // set ARR

    WRITE_REG(TIM3_CNT, 0);                         // clear counter value

    SET_BIT(TIM3_DIER, TIM3_DIER_UIE);              // enable int on overflow

    SET_BIT(Irq_0_to_31_Clear_Pending, 1 << 29);    // clear pending int

    SET_BIT(Irq_0_to_31_Set_Enable, 1 << 29);       // enable int

    SET_BIT(TIM3_CR1, TIM3_CR1_CEN);                // enable tim3

}

void main(void)

{

    initLED();

    initTim3();

    while(1)

    {

    }

}

Tomas DRESLER
Senior II
Posted on May 17, 2011 at 13:44

Well, I don't like your code style, but it's my problem, not yours :)

Basically, if your systems runs at 72 MHz, you get overflow every ~1 ms (not precisely calculated division factors).

Can you see the update flag turned on? If it sets repeatebly, you'll need to check settings of NVIC then. Do you have in your IDE some option to check content of  NVIC and TIM3 registers in a more structured way?
Tomas DRESLER
Senior II
Posted on May 17, 2011 at 13:44

This code works (tested):

void main(void)

{

  RCC->APB1ENR |= RCC_APB1Periph_TIM3;

  TIM3->PSC = 1;

  TIM3->ARR = 0xFFFF;

  // TIM3->EGR = 1;

  TIM3->DIER = 1;

  TIM3->CR1 = 1;

  NVIC->ISER[0] |= (1 << TIM3_IRQChannel);

  ...

}

void TIM3_IRQHandler(void)

{

  TIM3->SR = 0;

}