Step timer: reset timer after pauses instead of doing a guess.

We know already wether we start from a pause or not, so let's
take advantage of this knowledge instead of checking for
plausibility of a timer delay at interrupt time.

Costs just 8 bytes binary size:

    SIZES          ARM...     lpc1114
    FLASH  :  7764 bytes          24%
    RAM    :   960 bytes          24%
    EEPROM :     0 bytes           0%

Due to the less code at interrupt time, maximum step rate was
raised from 127.9 kHz to 130.6 kHz.
This commit is contained in:
Markus Hitter 2015-08-03 10:15:59 +02:00
parent f32693bf4e
commit 7afbc70d58
4 changed files with 34 additions and 21 deletions

View File

@ -141,6 +141,7 @@ void enqueue_home(TARGET *t, uint8_t endstop_check, uint8_t endstop_stop_cond) {
ATOMIC_END
if (isdead) {
timer_reset();
next_move();
// Compensate for the cli() in timer_set().
sei();

View File

@ -144,9 +144,7 @@ void TIMER32_0_IRQHandler(void) {
usually wants to handle this case.
Calls from elsewhere should set it to 0. In this case a timer
interrupt is always scheduled. At the risk that if this scheduling
is too short, the timer doesn't delay the requested time, but up to
a full timer counter overflow ( = 2^32 / F_CPU = ~96 seconds).
interrupt is always scheduled.
\return A flag whether the requested time was too short to allow scheduling
an interrupt. This is meaningful for ACCELERATION_TEMPORAL, where
@ -189,20 +187,11 @@ uint8_t timer_set(int32_t delay, uint8_t check_short) {
#endif /* ACCELERATION_TEMPORAL */
/**
Still here? Then we can schedule the next step. Usually off of the previous
step. If we passed this time already, usually because this is the first
move after a pause, we delay off of the current time. Other than on AVR we
can't affort a full round through the timer here, because this round would
be up to 60 seconds.
TODO: this check costs time and is a plausibility check only. It'd be
better to reset the timer from elsewhere when starting a movement
after a pause.
Still here? Then we can schedule the next step. Off of the previous step.
If there is no previous step, TC and MR0 should have been reset to zero
by calling timer_reset() shortly before we arrive here.
*/
if (LPC_TMR32B0->TC - LPC_TMR32B0->MR0 > delay - 100)
LPC_TMR32B0->MR0 = LPC_TMR32B0->TC + delay;
else
LPC_TMR32B0->MR0 += delay;
LPC_TMR32B0->MR0 += delay;
/**
Turn on the stepper interrupt. As this interrupt is the only use of this
@ -213,6 +202,19 @@ uint8_t timer_set(int32_t delay, uint8_t check_short) {
return 0;
}
/** Timer reset.
Reset the timer, so step interrupts scheduled at an arbitrary point in time
don't lead to a full round through the timer counter.
On ARM we actually do something, such a full round through the timer is
2^32 / F_CPU = 44 to 90 seconds.
*/
void timer_reset() {
LPC_TMR32B0->TC = 0;
LPC_TMR32B0->MR0 = 0;
}
/** Stop timers.
This means to be an emergency stop.

View File

@ -134,9 +134,7 @@ void timer_init() {
usually wants to handle this case.
Calls from elsewhere should set it to 0. In this case a timer
interrupt is always scheduled. At the risk that if this scheduling
is too short, the timer doesn't delay the requested time, but up to
a full timer counter overflow ( = 65536 / F_CPU = 3 to 4 milliseconds).
interrupt is always scheduled.
\return A flag whether the requested time was too short to allow scheduling
an interrupt. This is meaningful for ACCELERATION_TEMPORAL, where
@ -149,8 +147,7 @@ void timer_init() {
time of the call, but starting at the time of the previous timer interrupt
fired. This ignores the processing time taken in the step interrupt so far,
offering smooth and even step distribution. Flipside of this coin is,
schedules issued at an arbitrary time can result in drastically wrong delays.
See also discussion of parameter check_short and the return value.
one has to call timer_reset() before scheduling a step at an arbitrary time.
This enables the step interrupt, but also disables interrupts globally.
So, if you use it from inside the step interrupt, make sure to do so
@ -220,6 +217,17 @@ uint8_t timer_set(int32_t delay, uint8_t check_short) {
return 0;
}
/** Timer reset.
Reset the timer, so step interrupts scheduled at an arbitrary point in time
don't lead to a full round through the timer counter.
On AVR we simply do nothing, such a full round through the timer is just
2^16 / F_CPU = 3 to 4 milliseconds.
*/
void timer_reset() {
}
/** Stop timers.
This means to be an emergency stop.

View File

@ -21,6 +21,8 @@ void timer_init(void);
uint8_t timer_set(int32_t delay, uint8_t check_short);
void timer_reset(void);
void timer_stop(void);
#endif /* _TIMER_H */