1
\$\begingroup\$

I am using TIM1 to drive a DMA channel which is sending bytes to GPIOF on an STM32F407. TIM1 is started by an OC channel on a different timer. In the DMA stream interrupt handler, I am attempting to stop TIM1 and also reset the counter by generating an Update event. For troubleshooting purposes I have configured an OC channel on TIM1 so I can confirm it is starting and stopping as expected.

It does appear to start and stop at the correct times when viewing the pin output using a logic analyzer, but when stepping through the interrupt handler in the debugger I see that the CEN bit is still set after clearing it. Also, TIM1->CNT continues to increment as I step through each line.

The interrupt handler is as follows:

void __attribute__((interrupt("IRQ"))) DMA2_Stream5_IRQHandler(void)
{
    // Clear interrupt flags
    do
    {
        DMA2->HIFCR = DMA_HIFCR_CTCIF5 | DMA_HIFCR_CHTIF5;
    }
    while(DMA2->HISR & DMA_HISR_TCIF5);

    // Stop TIM1, TIM5 will re-enable it
    //TIM1->CR1 &= (u16)~TIM_CR1_CEN;
    do
    {
        TIM1->CR1 &= (u16)~TIM_CR1_CEN;
    }
    while(TIM1->CR1 & TIM_CR1_CEN);
    TIM1->EGR = TIM_EventSource_Update;     // Trigger an Update to reset the counter

    // Re-enable DMA for next TIM5 event
    DMA2_Stream5->CR |= DMA_SxCR_EN;
}

The code does exit the loop which clears CEN, but afterwards viewing the TIM1 registers shows CEN is still set. How can I ensure the timer is really stopped and will start counting from 0 next time it is started?

\$\endgroup\$

2 Answers 2

3
\$\begingroup\$

It appears that clearing the enabled flag has no effect when the timer is in slave mode. I have changed my interrupt handler as follows, and now it is working as expected. The timer is stopped and reset, until started again by TIM5.

// Clear interrupt flags
DMA2->HIFCR = DMA_HIFCR_CTCIF5 | DMA_HIFCR_CHTIF5;

// Disable slave move, can't stop the timer unless we do this first
TIM1->SMCR = 0;

// Stop TIM1, TIM5 will re-enable it
TIM1->CR1 = 0;// &= (u16)~TIM_CR1_CEN;
TIM1->EGR = TIM_EventSource_Update;     // Trigger an Update to reset the counter

// Re-enable slave mode
TIM1->SMCR = TIM_SlaveMode_Trigger;
\$\endgroup\$
-2
\$\begingroup\$
  1. it is generally a (very very) bad practice to loop around in an isr.

  2. no point in looping around to clear CEN. if it comes back set, somewhere else your code did it.

  3. flip a pin in the isr to see timing.

\$\endgroup\$
1
  • \$\begingroup\$ Thanks, I am trying to understand why the timer behaves as it does. I would have expected clearing CEN to take effect immediately but it does not. I am not clearing it anywhere else in my code. Also, although the loop does exit (i.e. at some point CEN does clear) it has already been enabled again and the counter is incrementing. Possibly TIM5 has already started it again at this point. Just wondering if there is anything additional that needs to be done apart from clearing CEN to stop the timer. Perhaps setting ARR_Preload causes it to not stop until an update event? Just speculating. \$\endgroup\$
    – Batperson
    Commented Aug 6, 2017 at 23:22

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.