Skip to main content
arro239
Associate III
April 15, 2014
Question

faliing to migrate trivial example from TIM6 to TIM5

  • April 15, 2014
  • 8 replies
  • 1058 views
Posted on April 15, 2014 at 15:23

I have a snippet which works, it blinks blue LED on stm32f4discovery:

void TIM6_DAC_IRQHandler() {
if (TIM6->SR)
GPIOD->ODR ^= (1 << 
15
); // Toggle D15
TIM6->SR &= ~1; // Interrupt has been handled
}
int main(void) {
TIM_TypeDef *TIM = TIM6;
RCC->AHB1ENR |= RCC_AHB1ENR_GPIODEN; // Enable GPIOD clock
GPIOD->MODER |= GPIO_MODER_MODER15_0; // Enable output mode for D15
RCC->APB1ENR |= RCC_APB1ENR_TIM6EN; // Enable TIM6 clock
NVIC_EnableIRQ(TIM6_DAC_IRQn); // Enable TIM6 IRQ
TIM->DIER |= TIM_DIER_UIE; // Enable interrupt on update event
TIM->PSC = 41999; // Set prescaler to 41999
TIM->ARR = 999; // Set auto-reload to 999
TIM->CR1 |= TIM_CR1_CEN; // Enable TIM counter
while (1) {
// do nothing
}
}

I am trying to move this logic to TIM5 - I want to use 32 bit counter. Well, it's embarrassing - this snipped does not work. What am I missing?

void TIM5_IRQHandler() {
if (TIM5->SR)
GPIOD->ODR ^= (1 << 
15
); // Toggle D15
TIM5->SR &= ~1; // Interrupt has been handled
}
int main(void) {
TIM_TypeDef *TIM = TIM5;
RCC->AHB1ENR |= RCC_AHB1ENR_GPIODEN; // Enable GPIOD clock
GPIOD->MODER |= GPIO_MODER_MODER15_0; // Enable output mode for D15
RCC->APB1ENR |= RCC_APB1ENR_TIM5EN; // Enable TIM5 clock
NVIC_EnableIRQ(TIM5_IRQn); // Enable TIM5 IRQ
TIM->DIER |= TIM_DIER_UIE; // Enable interrupt on update event
TIM->PSC = 41999; // Set prescaler to 41999
TIM->ARR = 999; // Set auto-reload to 999
TIM->CR1 |= TIM_CR1_CEN; // Enable TIM counter
while (1) {
// do nothing
}
}

    This topic has been closed for replies.

    8 replies

    chen
    Associate II
    April 15, 2014
    Posted on April 15, 2014 at 15:35

    Hi

    A quick check of the data sheet for STM32F4 shows that gpio D15 is not accessible for Tim5

    To use Tim5 - you will have to move IO pin

    arro239
    arro239Author
    Associate III
    April 15, 2014
    Posted on April 15, 2014 at 16:01

    Wait a second, what do you mean not accessible? I am not using D15 as one of timer channels - I am controlling it manually from the callback. I was under an impression that I can do whatever I want to do and there is no connection between the TIM and GPIO in this snipped.

    Do I miss something?
    chen
    Associate II
    April 15, 2014
    Posted on April 15, 2014 at 17:14

    Hi

    ''Do I miss something?''

    No, I did. I did not check your code.

    Not sure what you are missing. Will have o look at the reference manual.

    Tesla DeLorean
    Guru
    April 15, 2014
    Posted on April 15, 2014 at 17:54

    TIM6->SR &= ~1; // Interrupt has been handled

    This is NOT how to clear a timer interrupt, just write the mask! Also be aware there is a race condition on the NVIC. I would clear it before toggling the LED
    Tips, Buy me a coffee, or three.. PayPal Venmo (See Profile) Up vote any posts that you find helpful, it shows what's working..
    arro239
    arro239Author
    Associate III
    April 15, 2014
    Posted on April 15, 2014 at 20:24

    void TIM5_IRQHandler() {
    if (TIM->SR) {
    TIM->SR = ~1; // Interrupt has been handled
    schedulerCallback();
    }
    }

    Would this be a proper way to clear the flag? If not, what would be the best way to do that? With this change, the code now works on TIM5 - thank you clive1!
    frankmeyer9
    Associate III
    April 15, 2014
    Posted on April 15, 2014 at 20:36

    Would this be a proper way to clear the flag?

    When in doubt, just copy the method of the peripheral library (stm32f4xx_tim.c):

    void TIM_ClearITPendingBit(TIM_TypeDef* TIMx, uint16_t TIM_IT)
    {
    /* Check the parameters */
    assert_param(IS_TIM_ALL_PERIPH(TIMx));
    /* Clear the IT pending Bit */
    TIMx->SR = (uint16_t)~TIM_IT;
    }

    arro239
    arro239Author
    Associate III
    April 15, 2014
    Posted on April 15, 2014 at 20:39

    Episode #2, now I am trying one pulse mode and variable ARR

    This code works with TIM6 - the LED blinks three times:

    int globalCounter = 0;
    static TIM_TypeDef *TIM = TIM6;
    static void setTimer(int arr) {
    TIM->ARR = arr;
    TIM->EGR |= TIM_EGR_UG; // generate an update event to reload timer's counter value
    TIM->CR1 |= TIM_CR1_CEN; // restart timer
    }
    void TIM6_DAC_IRQHandler() {
    if (TIM->SR) {
    GPIOD->ODR ^= (1 << 
    14
    ); // Toggle D14
    globalCounter++;
    if (globalCounter < 6) {
    setTimer(499 * globalCounter);
    }
    TIM->SR = ~1; // Interrupt has been handled
    }
    }
    int main(void) {
    RCC->AHB1ENR |= RCC_AHB1ENR_GPIODEN; // Enable GPIOD clock
    GPIOD->MODER |= GPIO_MODER_MODER14_0; // Enable output mode for D14
    RCC->APB1ENR |= RCC_APB1ENR_TIM6EN; // Enable TIM6 clock
    NVIC_EnableIRQ(TIM6_DAC_IRQn); // Enable TIM6 IRQ
    TIM->DIER |= TIM_DIER_UIE; // Enable interrupt on update event
    TIM->CR1 |= TIM_CR1_OPM; // one pulse mode: count down ARR and stop
    TIM->CR1 &= ~TIM_CR1_ARPE; /* ARR register is NOT buffered, allows to update timer's period on-fly. */
    TIM->PSC = 41999; // Set prescaler to 41999
    setTimer(999);
    // TIM->ARR = darr; // Set auto-reload to 999
    // TIM->CR1 |= TIM_CR1_CEN; // Enable TIM counter
    while (1) {
    // do nothing
    }
    }

    but it would not work if I move the flag reset:

    void TIM6_DAC_IRQHandler() {
    if (TIM->SR) {
    TIM->SR = ~1; // Interrupt has been handled
    GPIOD->ODR ^= (1 << 14); // Toggle D14
    globalCounter++;
    if (globalCounter < 6) {
    setTimer(499 * globalCounter);
    }
    }
    }

    and probably because of that this would not work on TIM5. Please advise.
    arro239
    arro239Author
    Associate III
    April 15, 2014
    Posted on April 15, 2014 at 20:49

    I guess the condition check was also wrong, here is the code which seems to be doing what I wanted:

    int globalCounter = 0;
    static TIM_TypeDef *TIM = TIM5;
    static void setTimer(int arr) {
    TIM->ARR = arr;
    TIM->EGR |= TIM_EGR_UG; // generate an update event to reload timer's counter value
    TIM->CR1 |= TIM_CR1_CEN; // restart timer
    }
    static void callback(void) {
    GPIOD->ODR ^= (1 << 
    15
    ); // Toggle D15
    globalCounter++;
    if (globalCounter < 6) {
    setTimer(499 * globalCounter);
    }
    }
    void TIM5_IRQHandler() {
    if ((TIM->SR & 0x0001 != 0) && (TIM->DIER & 0x0001 != 0)) {
    callback();
    }
    TIM->SR = ~TIM_IT_Update; // Interrupt has been handled
    }
    int main(void) {
    RCC->AHB1ENR |= RCC_AHB1ENR_GPIODEN; // Enable GPIOD clock
    GPIOD->MODER |= GPIO_MODER_MODER15_0; // Enable output mode for D15
    RCC->APB1ENR |= RCC_APB1ENR_TIM5EN; // Enable TIM6 clock
    NVIC_EnableIRQ(TIM5_IRQn); // Enable TIM6 IRQ
    TIM->DIER |= TIM_DIER_UIE; // Enable interrupt on update event
    TIM->CR1 |= TIM_CR1_OPM; // one pulse mode: count down ARR and stop
    TIM->CR1 &= ~TIM_CR1_ARPE; /* ARR register is NOT buffered, allows to update timer's period on-fly. */
    TIM->PSC = 41999; // Set prescaler to 41999
    setTimer(999);
    while (1) {
    }
    }