10 years, 11 months ago.

Ticker handlers never called after a while

Hello!

I met an issue with the Ticker class. Please help!

In my program, there are 3 Ticker instance, and they are attached a function to each. (TFunc1, TFunc2, TFunc3) And, a single function is called by InterruptIn. (PFunc1)

If problem occurs, TFunc1, TFunc2, TFunc3 becomes not be executed. But if problem occurs, PFunc1 has been successfully called by pin interrupt.

As a result of looking for the Forum as a similar problem, I found arthur wolf-san's article(http://mbed.org/forum/mbed/topic/3037/)

In this article(if my understanding is correct), the issue is that if LPC_TIM3->MR0's value even match the LPC_TIM3->TC's, the Ticker handler was never called. I confirmed the value of MR0 & TC while running in my program.

The code to confirm LPC_TIM3 s TC, MR0(executed in main() s while(1) loop)

printf(" TIM3 tc(%u) mr0(%u) diff(%d)", 
	LPC_TIM3->TC, 
	LPC_TIM3->MR0, 
	int(LPC_TIM3->MR0) - int(LPC_TIM3->TC) 
);

Output (correct case)

6B->PCE --L--------- f8 f9 f8 02 TIM3 tc(136925302) mr0(136930082) diff(4780)
6B->PCE ------------ 08 09 08 07 TIM3 tc(137007594) mr0(137010082) diff(2489)
6B->PCE ------------ 18 19 18 0c TIM3 tc(137089886) mr0(137090082) diff(197)
6B->PCE ------C----- 29 2a 29 11 TIM3 tc(137171136) mr0(137175082) diff(3947)
6B->PCE ------------ 39 3a 39 16 TIM3 tc(137253428) mr0(137255082) diff(1655)
6B->PCE ------------ 4a 4b 4a 1b TIM3 tc(137335719) mr0(137340082) diff(4363)
6B->PCE ------------ 5a 5b 5a 20 TIM3 tc(137418011) mr0(137420082) diff(2072)
6B->PCE ------------ 6b 6c 6b 25 TIM3 tc(137500302) mr0(137505082) diff(4780)
6B->PCE ------------ 7b 7c 7b 2a TIM3 tc(137582594) mr0(137585082) diff(2488)

In above output,

  • 3rd column(f8) is the counter that increment by TFunc1's execution.
  • 4th column(f9) is the counter that increment by TFunc2's execution.
  • 5th column(f8) is the counter that increment by TFunc3's execution.
  • 6th column(02) is the counter that increment by PFunc1's execution.
  • 8th column is LPC_TIM3->TC.
  • 9th column is LPC_TIM3->MR0.

And found that if problem occurs, MR0 never be incremented, and TC is incremented.

Output (problem occurs)

6B->PCE ------------ 7e 7e 7d 2f TIM3 tc(137664886) mr0(137595157) diff(-69728)
6B->PCE ------------ 7e 7e 7d 34 TIM3 tc(137749261) mr0(137595157) diff(-154103)
6B->PCE ------------ 7e 7e 7d 39 TIM3 tc(137834677) mr0(137595157) diff(-239520)
6B->PCE ------------ 7e 7e 7d 3e TIM3 tc(137920094) mr0(137595157) diff(-324937)

In above output, the counter of TFunc1 to 3 are never incremented. It means that the Ticker handler TFunc1 to 3 are never executed. But, only the PFunc1's counter is incremented by pin interrupt.

"The Ticker handler is executed when MR0 matches the TC", is it correct ? Is there a solution or what? In addition, please let me know if you have any matters to be confirmed.

Thank you very much for your help.

2 Answers

10 years, 11 months ago.

Question: Do you change any interrupt priorities? I looked at the relevant code from the ticker function:

void us_ticker_irq_handler(void) {
    us_ticker_clear_interrupt();
    
    /* Go through all the pending TimerEvents */
    while (1) {
        if (head == NULL) {
            // There are no more TimerEvents left, so disable matches.
            us_ticker_disable_interrupt();
            return;
        }
        
        if ((int)(head->timestamp - us_ticker_read()) <= 0) {
            // This event was in the past:
            //      point to the following one and execute its handler
            ticker_event_t *p = head;
            head = head->next;
            if (event_handler != NULL) {
                event_handler(p->id); // NOTE: the handler can set new events
            }
        } else {
            // This event and the following ones in the list are in the future:
            //      set it as next interrupt and return
            us_ticker_set_interrupt(head->timestamp);
            return;
        }
    }
}

Other ticker functions disable interrupts while running. Now I understand they don't want to do it too much, but I guess if other interrupts have higher priority there is a chance it goes wrong. Lets say next event is 1us in the future. Line 12 will then be false, since 1 is not smaller or equal than zero. Now an interrupt happens that takes a few microseconds to handle. Interrupt is handled, and line 23 sets the interrupt for the 'next' value, which is now in the past, so it is never called. If I am correct interrupts should be disabled there for a bit (I would guess before line 12 disabling interrupt, @line 13 and 24 they could then be enabled again).

But this all is only possible if you did lower the timer interrupt priority. Normally it runs at maximum priority so it can't be interrupted. In the post you linked the interrupt prioritity was lowered, so it could in principle happen there.

Accepted Answer
Sankichi
poster
10 years, 11 months ago.

Erik-san,

Thank you for your quick response.

Quote:

Question: Do you change any interrupt priorities?

Yes. I changed priority of interrupts to InterruptIn has higher priority than Ticker. Below is a part of my code.

Priority setting part

void OutputClass::InitInterruptPriority(void)
{
    NVIC_SetPriority(NonMaskableInt_IRQn, 100 ); 
    NVIC_SetPriority(MemoryManagement_IRQn, 100);
    
    NVIC_SetPriority(BusFault_IRQn, 100);
    NVIC_SetPriority(UsageFault_IRQn, 100);
    NVIC_SetPriority(SVCall_IRQn, 100);
    NVIC_SetPriority(DebugMonitor_IRQn, 100);
    NVIC_SetPriority(PendSV_IRQn, 100);
    NVIC_SetPriority(SysTick_IRQn, 50);
    NVIC_SetPriority(WDT_IRQn, 100);
    NVIC_SetPriority(TIMER0_IRQn, 85);
    NVIC_SetPriority(TIMER1_IRQn, 85);
    NVIC_SetPriority(TIMER2_IRQn, 85);
    NVIC_SetPriority(TIMER3_IRQn, 85);	// <--- Timer 3 priority: 85
    NVIC_SetPriority(UART0_IRQn, 75);
    NVIC_SetPriority(UART1_IRQn, 100);
    NVIC_SetPriority(UART2_IRQn, 100);
    NVIC_SetPriority(UART3_IRQn, 100);
    
    NVIC_SetPriority(PWM1_IRQn, 100);
    NVIC_SetPriority(I2C0_IRQn, 100);
    NVIC_SetPriority(I2C1_IRQn, 100);
    NVIC_SetPriority(I2C2_IRQn, 100);
    NVIC_SetPriority(SPI_IRQn, 100);
    NVIC_SetPriority(SSP0_IRQn, 100);
    NVIC_SetPriority(SSP1_IRQn, 100);
    NVIC_SetPriority(PLL0_IRQn, 100);
    NVIC_SetPriority(RTC_IRQn, 100);
    NVIC_SetPriority(EINT0_IRQn, 100);
    NVIC_SetPriority(EINT1_IRQn, 100);
    
    NVIC_SetPriority(EINT2_IRQn, 100);
    NVIC_SetPriority(EINT3_IRQn, 0);	// <--- InterruptIn priority?: 0 (Changed to max)
    NVIC_SetPriority(ADC_IRQn, 100);
    NVIC_SetPriority(BOD_IRQn, 100);
    NVIC_SetPriority(USB_IRQn, 100);
    NVIC_SetPriority(CAN_IRQn, 100);
    NVIC_SetPriority(DMA_IRQn, 100);
    
    NVIC_SetPriority(I2S_IRQn, 100);
    NVIC_SetPriority(ENET_IRQn, 100);
    NVIC_SetPriority(RIT_IRQn, 100);
    NVIC_SetPriority(MCPWM_IRQn, 100);
    NVIC_SetPriority(QEI_IRQn, 100);
    NVIC_SetPriority(PLL1_IRQn, 100);
    
}

As a tentative fix for this probrem, if the value of MR0 falls below the TC, reset MR0 to a value greater than TC.

Fix code to reset LPC_TIM3 s MR0(executed in main() s while(1) loop)

if( (int(LPC_TIM3->MR0) - int(LPC_TIM3->TC)) <0 )
{
	printf("=================================================\r\n");
	printf("                   Resetting MR0 !!!!            \r\n");
	printf("=================================================\r\n");
	LPC_TIM3->MR0 = LPC_TIM3->TC + 200;
}

It will be dirty fix, but for now, it seems to work almost normally. (By abobe resetting, TFunc1 to 3 works again)

If you have an other solutions/ideas, please post. Thanks!

Make a post in the bug report forum, I think best solution is if they disable other interrupts for a short while. (And re-enable them before the attached user functions are called, so then they are only for a few clock cycles disabled). But then it can be fixed in the mbed library itself.

posted by Erik - 04 May 2013