TIcker / Timer3 problem

01 Jan 2012

Hi !

Context/Plug : I program Smoothie ( http://smoothieware.org/ ), a CNC controller for LPC17xx ( incl. mbed ) boards that can control CNC mills, lasercutters, and 3D printers. The project is based on gcc4mbed ( https://github.com/adamgreen/gcc4mbed ), and makes heavy use of the mBed libraries.

I've spent 4 days trying to debug a problem I'm having with Ticker and I think it's time to call for help :)

Basically the problem is that from time to time, Ticker will stop calling the handlers.

A bit info about the setup : I have 3 Tickers configured, two at 400hz and one at 5hz. Also, I use Timer1 and Timer0. ( Timer1 is disabled when the bug occurs ). Priorities are set like this :

    NVIC_SetPriority(TIMER3_IRQn, 4); 
    NVIC_SetPriority(TIMER0_IRQn, 2); 
    NVIC_SetPriority(TIMER1_IRQn, 3); 

So Timer0 moves the motors ( sends step signals ), and Timer3 updates the speed at which it does that ( acceleration/deceleration ). ( Timer1 steps the extruder motor, but the bug occurs even when it's disabled ). When the bug occurs, the speed stops being updated ( the Ticker handler stops being called ), and Timer0 continues stepping at a constant speed. After a while ( may be quite long depending on the speed ), it goes back to normal.

So I've started debugging the values of LPC_TIM3->MR0 and TC from the Timer0 handler. The way I understand how it works ( what I observe when the bug does not occur ) is : TC increments continuously ( no reset ), when it matches MR0 the interrupt is called, MR0 is incremented by 2500, handlers are called if needed, then we wait for the next match.

Now I think the bug is occuring when the Timer3 handler is interrupted by Timer0, thus taking too much time, and thus having TC > MR0 + 2500 after the end of the handler. But that does not cause the bug every time.

I've put a bit of code, executed inside Timer0, to see what Timer3 does :

printf("tc(%u) mr0(%u) diff(%d) pending:%u \r\n", LPC_TIM3->TC, LPC_TIM3->MR0, int(LPC_TIM3->MR0) - int(LPC_TIM3->TC), ( NVIC->ISPR[0] & ( 1<<4 ) ) );

This outputs ( bug not occuring ):

tc(396225035) mr0(396225000) -35    pending:16
tc(396282688) mr0(396285000)  2312  pending:0
tc(396296647) mr0(396296459) -189   pending:0
tc(396446673) mr0(396445000) -1674  pending:16
tc(396468532) mr0(396445000) -23533 pending:16
tc(396474138) mr0(396450000) -24139 pending:0
tc(396479083) mr0(396455000) -24084 pending:0
tc(396484028) mr0(396460000) -24029 pending:0
tc(396488959) mr0(396482500) -6460  pending:0
tc(396493804) mr0(396495000)  1195  pending:0
tc(396498563) mr0(396497500) -1064  pending:0

Now what happens ( mostly, I'm not sure why it's not always that way, maybe the printfs are messing with it ), is that when TC > MR0, the interrupt is made pending, and called. MR0 is incremented, and everybody is happy. Now from time to time, Timer0 takes longer than usual ( longer than 2500 ), and interrupts Timer3 when doing so, and so Timer3 takes longer than 2500 ( here 25000 ). But in this example, it does not disrupt the process, MR0 keeps on being incremented.

When the bug occurs, on the other hand, M0 stops being incremented, and I think that's what's causing the problem :

tc(401787404) mr0(401787500)  96     pending:0
tc(402016942) mr0(402017500)  557    pending:0
tc(402296701) mr0(402284451) -12251  pending:0
tc(402446942) mr0(402284451) -162492 pending:0
tc(402469066) mr0(402284451) -184616 pending:0
tc(402504306) mr0(402284451) -219856 pending:0
tc(402561230) mr0(402284451) -276780 pending:0
tc(402618154) mr0(402284451) -333704 pending:0
tc(402675063) mr0(402284451) -390613 pending:0
tc(402731987) mr0(402284451) -447537 pending:0
tc(402788911) mr0(402284451) -504460 pending:0

So the same thing happens ( I'm guessing that Timer3 takes too long to execute, possibly because it's interrupted by a long Timer0 interrupt ), but now MR0 steps being incremented ! So Timer3 stops calling the handler, and the program stops working correctly.

Anyone has some idea of how to fix this ? ( I can't have Timer0 not last more than 2500, it has to do so from time to time, that's from design ).

Thank you very much in advance for your help. And a happy new year :)

03 Jan 2012

Did you make a design? Do you know how things work or do you just code by trial and error? Why does Timer0 take longer than usual?

I really wonder about code like this:

    // Clear dir pins
    this->dir_gpio_port->FIOSET = this->dir_invert_mask & this->dir_mask;
    this->dir_gpio_port->FIOCLR = ~ this->dir_invert_mask & this->dir_mask;
    // Set dir pins
    this->dir_gpio_port->FIOSET = ( this->out_bits ^ this->dir_invert_mask ) & this->dir_mask;
    this->dir_gpio_port->FIOCLR = ( ~ ( this->out_bits ^ this->dir_invert_mask ) ) & this->dir_mask; 

If your functionality depends on 1 base tick, why do you use independent timers?

04 Jan 2012

Rene Greiner wrote:

Did you make a design? Do you know how things work or do you just code by trial and error?

It works ( mostly, it's changed a very small bit ) like this : http://smoothieware.org/howitworks :)

Rene Greiner wrote:

Why does Timer0 take longer than usual?

Movements are in the code represented as blocks. A block is executed, steps are outputed to stepper drivers, and when all the steps have been executed, we indicate to the system the block is finished, and the Player module fetches a new one, and indicates that new block to the system ( which starts the stepping of the new block ). This takes longer than the "usual" Timer0 interrupt, but that's ok since we are between blocks so interrupting anything else in the code won't cause trouble at that moment. Or at least that's what I thought, obviously the Ticker does not like it.

Rene Greiner wrote:

I really wonder about code like this:

    // Clear dir pins
    this->dir_gpio_port->FIOSET = this->dir_invert_mask & this->dir_mask;
    this->dir_gpio_port->FIOCLR = ~ this->dir_invert_mask & this->dir_mask;
    // Set dir pins
    this->dir_gpio_port->FIOSET = ( this->out_bits ^ this->dir_invert_mask ) & this->dir_mask;
    this->dir_gpio_port->FIOCLR = ( ~ ( this->out_bits ^ this->dir_invert_mask ) ) & this->dir_mask; 

What do you wonder about it ?

Rene Greiner wrote:

If your functionality depends on 1 base tick, why do you use independent timers?

The system is intended to be modular, and while right now I could get away with doing everything in Timer0 ( I originally ported grbl and that's what it did ), it's designed so that you can do any number of things in the acceleartion loop without causing trouble to the stepping loop.