From 4d737b1f6318db3014731fc2a2648997c2dfc03e Mon Sep 17 00:00:00 2001 From: Nicolas Schodet Date: Fri, 3 Jun 2011 10:07:33 +0200 Subject: digital/ai/src/utils: use interrupt for timer Use interrupt to avoid loosing any single timer tick. --- digital/ai/src/fsm/init.c | 2 +- digital/ai/src/utils/chrono.c | 94 +++++++++--------------------- digital/ai/src/utils/chrono.h | 56 ++---------------- digital/ai/src/utils/timer.avr.c | 33 ++++++++--- digital/ai/src/utils/timer.h | 18 +++--- digital/io-hub/src/guybrush/simu.host.c | 6 ++ digital/io-hub/src/robospierre/simu.host.c | 6 ++ digital/io/src/simu.host.c | 6 ++ 8 files changed, 84 insertions(+), 137 deletions(-) diff --git a/digital/ai/src/fsm/init.c b/digital/ai/src/fsm/init.c index 97fdea12..60e6b088 100644 --- a/digital/ai/src/fsm/init.c +++ b/digital/ai/src/fsm/init.c @@ -181,7 +181,7 @@ FSM_TRANS (INIT_GOING_TO_START_POSITION, robot_move_success, FSM_TRANS (INIT_WAITING_SECOND_JACK_OUT, jack_removed, INIT_FINISHED) { - chrono_init (); + chrono_start (); fsm_queue_post_event (FSM_EVENT (AI, init_start_round)); return FSM_NEXT (INIT_WAITING_SECOND_JACK_OUT, jack_removed); } diff --git a/digital/ai/src/utils/chrono.c b/digital/ai/src/utils/chrono.c index 85851547..83447c8d 100644 --- a/digital/ai/src/utils/chrono.c +++ b/digital/ai/src/utils/chrono.c @@ -33,105 +33,69 @@ #include "chrono.h" -/** - * Implementation notes. - * This module compute the number of tic of the main loop it should count - * before the match is over (chrono_init). Every tic of the main loop, it - * decrements the counter (chrono_update). When the counter is zero, the - * match is over (chrono_is_match_over, chrono_end_match). - */ - -/** Number of overflows of the timer to wait before the match is over. */ -#define CHRONO_MATCH_OVERFLOW_COUNT \ +/** Number of timer tick to wait before the match is over. */ +#define CHRONO_MATCH_TICK_COUNT \ (CHRONO_MATCH_DURATION_MS / TIMER_PERIOD_MS) -/** - * Duration of a loop to emulate from the original behaviour, in ms. - */ -#define CHRONO_LOOP_DURATION_MS 4 - -/** - * Time to wait before resetting slaves board, in ms. - */ +/** Time to wait before resetting slaves board, in ms. */ #define CHRONO_WAIT_BEFORE_RESET_MS 1000 -/** - * Number of time to overflow before the end of the match. - */ -static uint32_t chrono_ov_count_; +/** Number of timer tick left before the match ends. */ +static uint32_t chrono_tick_left_; -/** - * Status of the chrono module. - * Set to 0 if the module is disabled, otherwise set to a non 0 value. - */ -static uint8_t chrono_enabled_ = 0; +/** Last timer tick value. */ +static uint8_t chrono_last_tick_; +/** Is chrono started? */ +static uint8_t chrono_started_; void -chrono_init (void) +chrono_start (void) { - /* Enable chrono. */ - chrono_enable (); - /* Set the overflow counter to the maximum of overflow before the end of - * the match. */ - chrono_ov_count_ = CHRONO_MATCH_OVERFLOW_COUNT; + chrono_started_ = 1; + chrono_tick_left_ = CHRONO_MATCH_TICK_COUNT; + chrono_last_tick_ = timer_get_tick (); } void chrono_update (void) { - /* Decrement overflow counter if it is possible. */ - if (chrono_enabled_ && chrono_ov_count_) - chrono_ov_count_--; + if (chrono_started_) + { + uint8_t new_tick = timer_get_tick (); + uint8_t diff = new_tick - chrono_last_tick_; + chrono_last_tick_ = new_tick; + if (diff > chrono_tick_left_) + chrono_tick_left_ = 0; + else + chrono_tick_left_ -= diff; + } } uint8_t chrono_is_match_over (void) { - if (!chrono_enabled_ || chrono_ov_count_) + if (!chrono_started_ || chrono_tick_left_) return 0; else return 1; } -void -chrono_enable (void) -{ - chrono_enabled_ = 1; -} - -void -chrono_disable (void) -{ - chrono_enabled_ = 0; -} - -uint8_t -chrono_enabled (void) -{ - return chrono_enabled_; -} - uint32_t chrono_remaining_time (void) { - return chrono_ov_count_ * TIMER_PERIOD_MS; + return chrono_tick_left_ * TIMER_PERIOD_MS; } void chrono_end_match (uint8_t block) { - /* Make sure previous command has been acknowledged. If not, retransmit - * until acknowledged */ - while (!twi_master_sync ()) - utils_delay_ms (CHRONO_LOOP_DURATION_MS); - /* Make the bot stop moving */ asserv_stop_motor (); /* Wait until complete */ while (!twi_master_sync ()) - utils_delay_ms (CHRONO_LOOP_DURATION_MS); + timer_wait (); /* Wait CHRONO_WAIT_BEFORE_RESET ms before reseting */ utils_delay_ms (CHRONO_WAIT_BEFORE_RESET_MS); @@ -149,9 +113,3 @@ chrono_end_match (uint8_t block) #endif } -void -chrono_set_timer (uint32_t elapsed_time) -{ - if (chrono_enabled_) - chrono_ov_count_ = elapsed_time / TIMER_PERIOD_MS; -} diff --git a/digital/ai/src/utils/chrono.h b/digital/ai/src/utils/chrono.h index 580529cf..085b1a5e 100644 --- a/digital/ai/src/utils/chrono.h +++ b/digital/ai/src/utils/chrono.h @@ -26,57 +26,21 @@ * }}} */ /** - * @file Module to manage the chrono responsible to stop the bot after 90s. - * - * It is based on the main timer to know when to stop the bot. - * - * The main loop should never last more than the 4.44ms defined, otherwise, - * this module will not be precise at all! + * Module to manage the chrono responsible to stop the robot after 90s. */ /** Duration of a match in milliseconds, with margin. */ -#define CHRONO_MATCH_DURATION_MS (90000 - 2500) +#define CHRONO_MATCH_DURATION_MS (90000 - 1500) -/** - * Initialize the chrono module. - * It setups it for a duration of CHRONO_MATCH_DURATION_MS. - */ +/** Start chrono count down. */ void -chrono_init (void); +chrono_start (void); -/** - * Update chrono module. - * You must call this function every overflow of the main timer. - */ +/** Update chrono module. */ void chrono_update (void); -/** - * Enable chrono module. - * You should call this function when a match start. - */ -void -chrono_enable (void); - -/** - * Disable chrono module. - */ -void -chrono_disable (void); - -/** - * Is chrono module enabled? - * @return 0 if not enabled, other values otherwise. - */ -uint8_t -chrono_enabled (void); - -/** - * Match over? - * @return - * - 0 if the match is not finished yet. - * - 1 if the match is over. - */ +/** Match over? Return 0 if you still have chance to make points! */ uint8_t chrono_is_match_over (void); @@ -96,12 +60,4 @@ chrono_remaining_time (void); void chrono_end_match (uint8_t block); -/** - * Set timer at desired value. - * This function should be used for tests purpose only. - * @param elapsed_time elapsed time since beginning. - */ -void -chrono_set_timer (uint32_t elapsed_time); - #endif /* chrono_h */ diff --git a/digital/ai/src/utils/timer.avr.c b/digital/ai/src/utils/timer.avr.c index 63aa7bdc..7045b9c8 100644 --- a/digital/ai/src/utils/timer.avr.c +++ b/digital/ai/src/utils/timer.avr.c @@ -29,6 +29,18 @@ #include "modules/utils/utils.h" #include "io.h" +/** Set to 1 when timer overflowed, reset in timer_wait. */ +static volatile uint8_t timer_overflow; + +/** Incremented when timer overflowed. */ +static volatile uint8_t timer_tick; + +ISR (TIMER0_OVF_vect) +{ + timer_overflow = 1; + timer_tick++; +} + void timer_init (void) { @@ -50,19 +62,22 @@ timer_init (void) TCCR0B = regv (FOC0A, FOC0B, 5, 4, WGM02, CS02, CS01, CS00, 0, 0, 0, 0, 0, 1, 0, 0); #endif + TIMSK0 = _BV (TOIE0); } uint8_t timer_wait (void) { - /* Let's pretend we have reached overflow before calling this function. */ - uint8_t count_before_ov = 1; - /* Loop until an overflow of the timer occurs. */ - while (!(TIFR_reg & _BV (TOV0))) - /* We have not reached overflow. */ - count_before_ov = 0; - /* Write 1 to clear overflow. */ - TIFR_reg = _BV (TOV0); - return count_before_ov; + uint8_t late = 1; + while (!timer_overflow) + late = 0; + timer_overflow = 0; + return late; +} + +uint8_t +timer_get_tick (void) +{ + return timer_tick; } diff --git a/digital/ai/src/utils/timer.h b/digital/ai/src/utils/timer.h index e085b86e..dd71681f 100644 --- a/digital/ai/src/utils/timer.h +++ b/digital/ai/src/utils/timer.h @@ -52,17 +52,17 @@ void timer_init (void); /** - * Wait until the timer overflows. - * @return - * - 0 if we are on time (we have not reached overflow before calling this - * function). - * - 1 if we have already reached overflow. - * @warning if this function return 1, it means we are late and the main loop - * is lasting more than the time configured. Consequence, some important - * functions (like the chronometer for match duration) will not work - * correctly! + * Wait until next tick. Return non zero if we are late. + * + * Warning: if this function return non zero, it means we are late and the + * main loop is lasting more than the time configured. Consequence: some + * important functions will not work correctly! */ uint8_t timer_wait (void); +/** Get a tick value, incremented at each tick, never reset. */ +uint8_t +timer_get_tick (void); + #endif /* timer_h */ diff --git a/digital/io-hub/src/guybrush/simu.host.c b/digital/io-hub/src/guybrush/simu.host.c index e4cd61f0..567070d3 100644 --- a/digital/io-hub/src/guybrush/simu.host.c +++ b/digital/io-hub/src/guybrush/simu.host.c @@ -89,6 +89,12 @@ timer_wait (void) return 0; } +uint8_t +timer_get_tick (void) +{ + return mex_node_date () / 4; +} + /** Send computed path. */ void simu_send_path (vect_t *points, uint8_t len, diff --git a/digital/io-hub/src/robospierre/simu.host.c b/digital/io-hub/src/robospierre/simu.host.c index 70055d7d..745cdbc8 100644 --- a/digital/io-hub/src/robospierre/simu.host.c +++ b/digital/io-hub/src/robospierre/simu.host.c @@ -81,6 +81,12 @@ timer_wait (void) return 0; } +uint8_t +timer_get_tick (void) +{ + return mex_node_date () / 4; +} + /** Send computed path. */ void simu_send_path (vect_t *points, uint8_t len, diff --git a/digital/io/src/simu.host.c b/digital/io/src/simu.host.c index a35b9d12..d6c6ef54 100644 --- a/digital/io/src/simu.host.c +++ b/digital/io/src/simu.host.c @@ -227,6 +227,12 @@ timer_wait (void) return 0; } +uint8_t +timer_get_tick (void) +{ + return mex_node_date () / 4; +} + void eeprom_load_param (void) { -- cgit v1.2.3