Microcontroller Wireless Solutions


pal_timer.c
Go to the documentation of this file.
00001 
00013 /*
00014  * Copyright (c) 2009, Atmel Corporation All rights reserved.
00015  *
00016  * Licensed under Atmel's Limited License Agreement --> EULA.txt
00017  */
00018 
00019 /* === Includes ============================================================ */
00020 
00021 #include <stdbool.h>
00022 #include <stdint.h>
00023 #include <stddef.h>
00024 #include <stdlib.h>
00025 #include "pal.h"
00026 #include "return_val.h"
00027 #include "pal_timer.h"
00028 #include "app_config.h"
00029 
00030 /* === Globals ============================================================== */
00031 
00032 /*
00033  * Check the number of required timers or change the number of timers that are
00034  * provided by the PAL. This is a kind of error handling to reduce the
00035  * number of used timer and therefore the RAM usage.
00036  */
00037 #if (TOTAL_NUMBER_OF_TIMERS > MAX_NO_OF_TIMERS)
00038 #error "Number of used timers is greater than the number of timer provided by PAL."
00039 #endif
00040 
00041 #if (TOTAL_NUMBER_OF_TIMERS > 0)
00042 
00043 /*
00044  * This is the timer array.
00045  *
00046  * TOTAL_NUMBER_OF_TIMERS is calculated in file app_config.h within the Inc
00047  * directory of each application depending on the number of timers required
00048  * by the stack and the application.
00049  */
00050 timer_info_t timer_array[TOTAL_NUMBER_OF_TIMERS];
00051 
00052 /* This is the counter of all running timers. */
00053 #ifdef NO_32KHZ_CRYSTAL
00054 uint8_t running_timers;
00055 #else
00056 static uint8_t running_timers;
00057 #endif
00058 
00059 /* This flag indicates an expired timer. */
00060 volatile bool timer_trigger;
00061 
00062 /* This is the reference to the head of the running timer queue. */
00063 static uint_fast8_t running_timer_queue_head;
00064 
00065 /* This is the reference to the head of the expired timer queue. */
00066 static uint_fast8_t expired_timer_queue_head;
00067 
00068 /* This is the reference to the tail of the expired timer queue. */
00069 static uint_fast8_t expired_timer_queue_tail;
00070 
00071 /* Time when the SCOCR1 interrupt triggered last time */
00072 static uint32_t timer_last_trigger;
00073 #endif  /* #if (TOTAL_NUMBER_OF_TIMERS > 0) */
00074 
00075 /* This variable holds the id of high priority timer */
00076 #ifdef ENABLE_HIGH_PRIO_TMR
00077 static volatile uint8_t high_priority_timer_id;
00078 #endif
00079 
00080 /* === Macros ============================================================== */
00081 
00087 #define DELAY_WITHOUT_IRQS_US           (100)
00088 
00089 /* === Prototypes =========================================================== */
00090 
00091 #if (TOTAL_NUMBER_OF_TIMERS > 0)
00092 static void prog_ocr(void);
00093 static void start_absolute_timer(uint8_t timer_id,
00094                                  uint32_t point_in_time,
00095                                  FUNC_PTR handler_cb,
00096                                  void *parameter);
00097 #endif  /* #if (TOTAL_NUMBER_OF_TIMERS > 0) */
00098 
00099 /* === Implementation ======================================================= */
00100 
00101 #if ((TOTAL_NUMBER_OF_TIMERS > 0) || defined(DOXYGEN))
00102 
00114 static inline bool compare_time(uint32_t t1, uint32_t t2)
00115 {
00116     bool comparison_status = false;
00117 
00118     if ((t1 & ~MASK_LOW27) == (t2 & ~MASK_LOW27))
00119     {
00120         if (t1 < t2)
00121         {
00122             comparison_status = true;
00123         }
00124     }
00125     else
00126     {
00127         /* This is a timer roll case in which t2 is ahead of t1. */
00128         if ((t1 & MASK_LOW27) > (t2 & MASK_LOW27))
00129         {
00130             comparison_status = true;
00131         }
00132     }
00133     return comparison_status;
00134 }
00135 #endif  /* #if ((TOTAL_NUMBER_OF_TIMERS > 0) || defined(DOXYGEN)) */
00136 
00137 
00138 
00139 #if ((TOTAL_NUMBER_OF_TIMERS > 0) || defined(DOXYGEN))
00140 
00148 void timer_service(void)
00149 {
00150     internal_timer_handler();
00151 
00152     /*
00153      * Process expired timers.
00154      * Call the callback functions of the expired timers in the order of their
00155      * expiry.
00156      */
00157     {
00158         timer_expiry_cb_t callback;
00159         void *callback_param;
00160         uint8_t next_expired_timer;
00161 
00162         /* Expired timer if any will be processed here */
00163         while (NO_TIMER != expired_timer_queue_head)
00164         {
00165             ENTER_CRITICAL_REGION();
00166 
00167             next_expired_timer = timer_array[expired_timer_queue_head].next_timer_in_queue;
00168 
00169             /* Callback is stored */
00170             callback = (timer_expiry_cb_t)timer_array[expired_timer_queue_head].timer_cb;
00171 
00172             /* Callback parameter is stored */
00173             callback_param = timer_array[expired_timer_queue_head].param_cb;
00174 
00175             /*
00176              * The expired timer's structure elements are updated and the timer
00177              * is taken out of expired timer queue
00178              */
00179             timer_array[expired_timer_queue_head].next_timer_in_queue = NO_TIMER;
00180             timer_array[expired_timer_queue_head].timer_cb = NULL;
00181             timer_array[expired_timer_queue_head].param_cb = NULL;
00182 
00183             /*
00184              * The expired timer queue head is updated with the next timer in the
00185              * expired timer queue.
00186              */
00187             expired_timer_queue_head = next_expired_timer;
00188 
00189             if (NO_TIMER == expired_timer_queue_head)
00190             {
00191                 expired_timer_queue_tail = NO_TIMER;
00192             }
00193 
00194             LEAVE_CRITICAL_REGION();
00195 
00196             if (NULL != callback)
00197             {
00198                 /* Callback function is called */
00199                 callback(callback_param);
00200             }
00201         }
00202     }
00203 }
00204 #endif  /* #if ((TOTAL_NUMBER_OF_TIMERS > 0) || defined(DOXYGEN)) */
00205 
00206 
00207 
00208 #if ((TOTAL_NUMBER_OF_TIMERS > 0) || defined(DOXYGEN))
00209 
00229 retval_t pal_timer_start(uint8_t timer_id,
00230                          uint32_t timer_count,
00231                          timeout_type_t timeout_type,
00232                          FUNC_PTR timer_cb,
00233                          void *param_cb)
00234 {
00235     uint32_t point_in_time;
00236 
00237     if (timer_id >= TOTAL_NUMBER_OF_TIMERS)
00238     {
00239         return PAL_TMR_INVALID_ID;
00240     }
00241 
00242     if (NULL == timer_cb)
00243     {
00244         return MAC_INVALID_PARAMETER;
00245     }
00246 
00247     if (NULL != timer_array[timer_id].timer_cb)
00248     {
00249         /*
00250          * Timer is already running if the callback function of the
00251          * corresponding timer index in the timer array is not NULL.
00252          */
00253         return PAL_TMR_ALREADY_RUNNING;
00254     }
00255 
00256     timer_count /= PAL_US_PER_SYMBOLS;
00257 
00258     switch(timeout_type)
00259     {
00260         case TIMEOUT_RELATIVE:
00261         {
00262             if ((timer_count > MAX_TIMEOUT / PAL_US_PER_SYMBOLS) || (timer_count < MIN_TIMEOUT / PAL_US_PER_SYMBOLS))
00263             {
00264                 return PAL_TMR_INVALID_TIMEOUT;
00265             }
00266 
00267             point_in_time = timer_count + SC_READ32(SCCNT);
00268             point_in_time &= MASK_LOW28;
00269         }
00270         break;
00271 
00272         case TIMEOUT_ABSOLUTE:
00273         {
00274             uint32_t timeout;
00275 
00276             timeout = timer_count - SC_READ32(SCCNT);
00277             timeout &= MASK_LOW28;
00278 
00279             if ((timeout > MAX_TIMEOUT / PAL_US_PER_SYMBOLS) || (timeout < MIN_TIMEOUT / PAL_US_PER_SYMBOLS))
00280             {
00281                 return PAL_TMR_INVALID_TIMEOUT;
00282             }
00283             point_in_time = timer_count;
00284         }
00285         break;
00286 
00287         default:
00288             return MAC_INVALID_PARAMETER;
00289     }
00290 
00291     start_absolute_timer(timer_id, point_in_time, timer_cb, param_cb);
00292     return MAC_SUCCESS;
00293 }
00294 #endif  /* #if ((TOTAL_NUMBER_OF_TIMERS > 0) || defined(DOXYGEN)) */
00295 
00296 
00297 
00298 #if ((defined ENABLE_HIGH_PRIO_TMR) || defined(DOXYGEN))
00299 
00315 retval_t pal_start_high_priority_timer(uint8_t timer_id,
00316                                        uint16_t timer_count,
00317                                        FUNC_PTR timer_cb,
00318                                        void *param_cb)
00319 {
00320     timer_expiry_cb_t callback;
00321     uint32_t ocr;
00322 
00323     if (timer_id >= TOTAL_NUMBER_OF_TIMERS)
00324     {
00325         return PAL_TMR_INVALID_ID;
00326     }
00327 
00328     if (NULL == timer_cb)
00329     {
00330         return MAC_INVALID_PARAMETER;
00331     }
00332 
00333     if (NULL != timer_array[timer_id].timer_cb)
00334     {
00335         /*
00336          * Irrespective of the type, the timer is already running if the
00337          * callback function of the corresponding timer index in the timer
00338          * array is not NULL.
00339          */
00340         return PAL_TMR_ALREADY_RUNNING;
00341     }
00342 
00343     /*
00344      * A high priority timer can be started, as currently
00345      * there is no high priority timer running.
00346      */
00347     timer_count /= PAL_US_PER_SYMBOLS;
00348     if (timer_count == 0)
00349     {
00350         callback = (timer_expiry_cb_t)timer_cb;
00351         callback(param_cb);
00352         return MAC_SUCCESS;
00353     }
00354 
00355     ENTER_CRITICAL_REGION();
00356 
00357     high_priority_timer_id = timer_id;
00358     /*
00359      * The corresponding running timer queue's timer index is updated
00360      * with the new values
00361      */
00362     timer_array[timer_id].timer_cb = timer_cb;
00363     timer_array[timer_id].param_cb = param_cb;
00364     timer_array[timer_id].next_timer_in_queue = NO_TIMER;
00365 
00366     ocr = SC_READ32(SCCNT);
00367     ocr += timer_count;
00368     ocr &= MASK_LOW28;
00369 
00370     SCIRQS = _BV(IRQSCP3);
00371     SCIRQM |= _BV(IRQMCP3);
00372 
00373     SC_WRITE32(SCOCR3, ocr);
00374 
00375     timer_array[timer_id].abs_exp_timer = ocr;
00376 
00377     LEAVE_CRITICAL_REGION();
00378 
00379     return MAC_SUCCESS;
00380 }
00381 #endif /* #if ((defined ENABLE_HIGH_PRIO_TMR) || defined(DOXYGEN)) */
00382 
00383 
00384 
00385 #if ((TOTAL_NUMBER_OF_TIMERS > 0) || defined(DOXYGEN))
00386 
00398 retval_t pal_timer_stop(uint8_t timer_id)
00399 {
00400     bool timer_stop_request_status = false;
00401     uint8_t curr_index;
00402     uint8_t prev_index;
00403 
00404 
00405     if (timer_id >= TOTAL_NUMBER_OF_TIMERS)
00406     {
00407         return (PAL_TMR_INVALID_ID);
00408     }
00409 
00410     ENTER_CRITICAL_REGION();
00411 
00412     /* Check if any timer has expired. */
00413     internal_timer_handler();
00414 
00415     /* The requested timer is first searched in the running timer queue */
00416     if (running_timers > 0)
00417     {
00418         uint8_t timer_count = running_timers;
00419         prev_index = curr_index = running_timer_queue_head;
00420         while (timer_count > 0)
00421         {
00422             if (timer_id == curr_index)
00423             {
00424                 timer_stop_request_status = true;
00425 
00426                 if (timer_id == running_timer_queue_head)
00427                 {
00428                     running_timer_queue_head =
00429                         timer_array[timer_id].next_timer_in_queue;
00430                     /*
00431                      * The value in OCR corresponds to the timeout pointed
00432                      * by the 'running_timer_queue_head'. As the head has
00433                      * changed here, OCR needs to be loaded by the new
00434                      * timeout value, if any.
00435                      */
00436                     prog_ocr();
00437                 }
00438                 else
00439                 {
00440                     timer_array[prev_index].next_timer_in_queue =
00441                         timer_array[timer_id].next_timer_in_queue;
00442                 }
00443                 /*
00444                  * The next timer element of the stopped timer is updated
00445                  * to its default value.
00446                  */
00447                 timer_array[timer_id].next_timer_in_queue = NO_TIMER;
00448                 break;
00449             }
00450             else
00451             {
00452                 prev_index = curr_index;
00453                 curr_index = timer_array[curr_index].next_timer_in_queue;
00454             }
00455             timer_count--;
00456         }
00457         if (timer_stop_request_status)
00458         {
00459             running_timers--;
00460         }
00461     }
00462 
00463     /*
00464      * The requested timer is not present in the running timer queue.
00465      * It will be now searched in the expired timer queue
00466      */
00467     if (!timer_stop_request_status)
00468     {
00469         prev_index = curr_index = expired_timer_queue_head;
00470         while (NO_TIMER != curr_index)
00471         {
00472             if (timer_id == curr_index)
00473             {
00474                 if (timer_id == expired_timer_queue_head)
00475                 {
00476                     /*
00477                      * The requested timer is the head of the expired timer
00478                      * queue
00479                      */
00480                     if (expired_timer_queue_head == expired_timer_queue_tail)
00481                     {
00482                         /* Only one timer in expired timer queue */
00483                         expired_timer_queue_head = expired_timer_queue_tail =
00484                             NO_TIMER;
00485                     }
00486                     else
00487                     {
00488                         /*
00489                          * The head of the expired timer queue is moved to next
00490                          * timer in the expired timer queue.
00491                          */
00492                         expired_timer_queue_head =
00493                             timer_array[expired_timer_queue_head].next_timer_in_queue;
00494                     }
00495                 }
00496                 else
00497                 {
00498                     /*
00499                      * The requested timer is present in the middle or at the
00500                      * end of the expired timer queue.
00501                      */
00502                     timer_array[prev_index].next_timer_in_queue =
00503                         timer_array[timer_id].next_timer_in_queue;
00504 
00505                     /*
00506                      * If the stopped timer is the one which is at the tail of
00507                      * the expired timer queue, then the tail is updated.
00508                      */
00509                     if (timer_id == expired_timer_queue_tail)
00510                     {
00511                         expired_timer_queue_tail = prev_index;
00512                     }
00513                 }
00514                 timer_stop_request_status = true;
00515                 break;
00516             }
00517             else
00518             {
00519                prev_index = curr_index;
00520                curr_index = timer_array[curr_index].next_timer_in_queue;
00521             }
00522         }
00523     }
00524 
00525     if (timer_stop_request_status)
00526     {
00527         /*
00528          * The requested timer is stopped, hence the structure elements of the
00529          * timer are updated.
00530          */
00531         timer_array[timer_id].timer_cb = NULL;
00532     }
00533 
00534     LEAVE_CRITICAL_REGION();
00535 
00536     if (timer_stop_request_status)
00537     {
00538         return (MAC_SUCCESS);
00539     }
00540 
00541     return (PAL_TMR_NOT_RUNNING);
00542 }
00543 #endif  /* #if ((TOTAL_NUMBER_OF_TIMERS > 0) || defined(DOXYGEN)) */
00544 
00545 
00546 
00547 #if ((defined ENABLE_HIGH_PRIO_TMR) || defined(DOXYGEN))
00548 
00560 retval_t pal_stop_high_priority_timer(uint8_t timer_id)
00561 {
00562     retval_t timer_stop_status = PAL_TMR_NOT_RUNNING;
00563 
00564     ENTER_CRITICAL_REGION();
00565 
00566     if (timer_id == high_priority_timer_id)
00567     {
00568         /* Turn off timer1 SCOCR3 interrupt */
00569         SCIRQS = _BV(IRQSCP3);
00570         SCIRQM |= _BV(IRQMCP3);
00571 
00572         timer_array[high_priority_timer_id].next_timer_in_queue = NO_TIMER;
00573         timer_array[high_priority_timer_id].timer_cb = NULL;
00574         high_priority_timer_id = NO_TIMER;
00575 
00576         timer_stop_status = MAC_SUCCESS;
00577     }
00578 
00579     LEAVE_CRITICAL_REGION();
00580 
00581     return timer_stop_status;
00582 }
00583 #endif /* #if ((defined ENABLE_HIGH_PRIO_TMR) || defined(DOXYGEN)) */
00584 
00585 
00586 
00590 void timer_init(void)
00591 {
00592 #if ((TOTAL_NUMBER_OF_TIMERS > 0) || defined(DOXYGEN))
00593     /*
00594      * Initialize the timer resources like timer arrays
00595      * queues, timer registers
00596      */
00597     uint8_t index;
00598 
00599     running_timers = 0;
00600     timer_trigger = false;
00601 
00602     running_timer_queue_head = NO_TIMER;
00603     expired_timer_queue_head = NO_TIMER;
00604     expired_timer_queue_tail = NO_TIMER;
00605 #ifdef ENABLE_HIGH_PRIO_TMR
00606     high_priority_timer_id = NO_TIMER;
00607 #endif
00608 
00609     for (index = 0; index < TOTAL_NUMBER_OF_TIMERS; index++)
00610     {
00611         timer_array[index].next_timer_in_queue = NO_TIMER;
00612         timer_array[index].timer_cb = NULL;
00613     }
00614 #endif  /* #if ((TOTAL_NUMBER_OF_TIMERS > 0) || defined(DOXYGEN)) */
00615 
00616     /*
00617      * Enable the 32 kHz crystal oscillator. This is required in
00618      * order to allow for the hardware performing a transparent clock
00619      * switch when the main 16 MHz crystal is turned off (i.e., when
00620      * the transceiver module is put to sleep).
00621      */
00622 #ifndef NO_32KHZ_CRYSTAL
00623     ASSR = _BV(AS2);
00624 #endif
00625 
00626     /*
00627      * Start the MAC symbol counter, resetting the prescaler by the
00628      * same time.  Also enable the rx timestamping feature.
00629      */
00630     SCCR0 = _BV(SCTSE) | _BV(SCEN) | _BV(SCRES);
00631 
00632     /*
00633      * Use SCOCR2 to implement a virtual 28-bit timer. This is needed
00634      * since all layers above PAL operate at a microsecond level, while
00635      * the MAC symbol counter operates at a granularity of MAC symbol
00636      * periods (16 µs).  Due to that, the timer values have to be
00637      * scaled at the PAL API border, and this scaling effectively
00638      * reduces the timer span to 28 bits.
00639      *
00640      * Whenever the timer is about to cross the 28-bit boundary, it is
00641      * advanced (by the ISR for SCOCR2) so the hardware will then
00642      * perform a real rollover at the next timer tick.  That way, the
00643      * worst effect from blocking interrupts for too long is that all
00644      * pending timers at the time of rollover will be delayed a bit.
00645      * If the SCOCR2 interrupt is served within 16 µs, no additional
00646      * delay will happen.
00647      */
00648     SC_WRITE32(SCOCR2, 0x0FFFFFFFul);
00649     SCIRQS = _BV(IRQSCP2);
00650     SCIRQM |= _BV(IRQMCP2);
00651 
00652 #ifdef ENABLE_RC_OSC_CALIBRATION
00653     /*
00654      * In case RC oscillator calibration is enabled for Mega-RF devices,
00655      * the 32kHz oscillator needs to be stable. This takes around half
00656      * a second, before this can be used safely.
00657      * Therefore a blocking delay of 500ms is included, in order to make sure
00658      * a potential RC calibration will work properly.
00659      */
00660     for (uint8_t i = 0; i < 10; i++)
00661     {
00662         pal_timer_delay(50000);
00663     }
00664 #endif  /* ENABLE_RC_OSC_CALIBRATION */
00665 }
00666 
00667 
00668 
00682 void pal_timer_source_select(source_type_t source)
00683 {
00684     /* Keep compiler happy. */
00685     source = source;
00686 }
00687 
00688 
00689 
00697 void pal_get_current_time(uint32_t *current_time)
00698 {
00699     while ((SCSR & _BV(SCBSY)) != 0)
00700     {
00701         ;
00702     }
00703     *current_time = PAL_US_PER_SYMBOLS * SC_READ32(SCCNT);
00704 }
00705 
00706 
00707 
00716 void pal_trx_read_timestamp(uint32_t *timestamp)
00717 {
00718     *timestamp = PAL_US_PER_SYMBOLS * SC_READ32(SCTSR);
00719 }
00720 
00721 
00722 
00730 void  pal_timer_delay(uint16_t delay)
00731 {
00732     bool needs_cli = false;
00733     uint8_t sreg = 0;
00734 
00735     /*
00736      * Any interrupt occurring during the delay calculation will introduce
00737      * additional delay and can also affect the logic of delay calculation.
00738      * Hence the delay implementation is put under critical region as long
00739      * as only a small delay time is requested.
00740      */
00741     if (delay < DELAY_WITHOUT_IRQS_US)
00742     {
00743         needs_cli = true;
00744         sreg = SREG;
00745         cli();
00746     }
00747 
00748     /*
00749      * The logic below depends on the CPU being clocked with 16 MHz,
00750      * and timer 5 being set up for a prescaler of 8, so it will be
00751      * clocked with 2 MHz.  This is the best compromise to achieve the
00752      * 1 µs resolutions callers of pal_timer_delay() are expecting.
00753      *
00754      * In case any other CPU clock frequency should be supported that
00755      * cannot work this way, some of the logic below needs to be
00756      * rewritten.  Normally, there should be no real need for a
00757      * different CPU clock frequency, as the ATmega128RFA1 can operate
00758      * at 16 MHz down to the minimal possible supply voltage.
00759      *
00760      * As a special exception, the CPU frequency 15.3846 MHz will be
00761      * tolerated as it is used in some test setups.  This results in
00762      * delays being approximately 4 % too long which is deemed to be
00763      * acceptable for that particular purpose.
00764      */
00765 #if (F_CPU != 16000000UL) && (F_CPU != 8000000UL) && (F_CPU != 4000000UL) && (F_CPU != 15384600UL)
00766 #  error "pal_timer_delay() is only implemented for F_CPU = 4, 8 and 16 MHz"
00767 #endif
00768     /*
00769      * With a 2 MHz timer clock, it is not possible to span the entire
00770      * delay range of 65 ms using a single timer 5 cycle, so the delay
00771      * is split into multiple smaller delays if required.
00772      */
00773     while (delay != 0)
00774     {
00775         uint16_t actval;
00776 
00777         /*
00778          * Find whether the entire delay time will fit or not.  Note
00779          * that the 2 MHz figure below must *not* be calculated as
00780          * F_CPU / (1000000 * 8) because that will not work as
00781          * expected in the the 15.3 MHz case.
00782          */
00783         if (delay > UINT16_MAX / 2 /* MHz timer clock */)
00784         {
00785             actval = UINT16_MAX / 2;
00786         }
00787         else
00788         {
00789             actval = delay;
00790         }
00791         delay -= actval;        /* remaining delay for next round */
00792 
00793         /*
00794          * Perform the actual delay.  Setup TCNT5 so it will overflow
00795          * after actval cycles.  Then, clear any pending overflow
00796          * interrupt, and start timer 5 with a prescaler of 8.  Poll
00797          * for the overflow interrupt flag, and stop the timer again
00798          * afterwards.
00799          */
00800 #if (F_CPU == 16000000)
00801         /* If the CPU runs at 8MHz, no adjustment is required. */
00802         actval *= 2 /* microseconds to timer 5 clock cycles @ 2 MHz */;
00803 #endif
00804 #if (F_CPU == 4000000)
00805         /* If the CPU runs at 4MHz, adjustment is required. */
00806         actval /= 2 /* microseconds to timer 5 clock cycles @ 500 kHz */;
00807 #endif
00808         TCNT5 = (uint16_t)(-((int16_t)actval));
00809         TIFR5 = _BV(TOV5);
00810         TCCR5B = _BV(CS51);
00811         while ((TIFR5 & _BV(TOV5)) == 0)
00812             /* delay */;
00813         TCCR5B = 0;
00814     }
00815 
00816     if (needs_cli)
00817     {
00818         SREG = sreg;
00819     }
00820 }
00821 
00822 
00823 
00824 #if ((TOTAL_NUMBER_OF_TIMERS > 0) || defined(DOXYGEN))
00825 
00834 bool pal_is_timer_running(uint8_t timer_id)
00835 {
00836     if (NULL == timer_array[timer_id].timer_cb)
00837     {
00838         return false;
00839     }
00840     return true;
00841 }
00842 #endif  /* TOTAL_NUMBER_OF_TIMERS > 0 */
00843 
00844 
00845 
00846 #if (DEBUG > 0)
00847 
00856 bool pal_are_all_timers_stopped(void)
00857 {
00858 #if (TOTAL_NUMBER_OF_TIMERS > 0)
00859     uint8_t timer_id;
00860 
00861     for (timer_id = 0; timer_id < TOTAL_NUMBER_OF_TIMERS; timer_id++)
00862     {
00863         if (NULL != timer_array[timer_id].timer_cb)
00864         {
00865             return false;
00866         }
00867     }
00868 #endif
00869     return true;
00870 }
00871 #endif  /* (DEBUG > 0) */
00872 
00873 
00874 
00875 #if ((TOTAL_NUMBER_OF_TIMERS > 0) || defined(DOXYGEN))
00876 
00882 static void prog_ocr(void)
00883 {
00884     uint32_t new_ocr = timer_array[running_timer_queue_head].abs_exp_timer;
00885 
00886     if (running_timers != 0)
00887     {
00888         SC_WRITE32(SCOCR1, new_ocr);
00889         if ((SCIRQM & _BV(IRQMCP1)) == 0)
00890         {
00891             SCIRQS = _BV(IRQSCP1);
00892             SCIRQM |= _BV(IRQMCP1);
00893         }
00894 
00895         /* Safety check: Trigger timer, if next_trigger is in the past. */
00896         if (compare_time(new_ocr, SC_READ32(SCCNT) + 1))
00897         {
00898             timer_trigger = true;
00899         }
00900         else if ((VERSION_NUM <= 7) && (timer_last_trigger + 1 == new_ocr))
00901         {
00902             /*
00903              * ATmega128RFA1 1.x: new SCOCRx value and value where
00904              * SCOCRx has just triggered an interrupt must differ by
00905              * at least 2.
00906              *
00907              * Just wait a little moment here, and then proceed as if
00908              * the ISR had just triggered.
00909              */
00910             while (SC_READ32(SCCNT) != new_ocr)
00911                 /* wait */;
00912             timer_trigger = true;
00913         }
00914     }
00915     else
00916     {
00917         SCIRQM &= ~_BV(IRQMCP1);
00918     }
00919 }
00920 #endif  /* TOTAL_NUMBER_OF_TIMERS > 0 */
00921 
00922 
00923 
00924 #if ((TOTAL_NUMBER_OF_TIMERS > 0) || defined(DOXYGEN))
00925 
00932 void internal_timer_handler(void)
00933 {
00934     ENTER_CRITICAL_REGION();
00935 
00936     /*
00937      * Flag was set once a timer has expired by the timer ISR or
00938      * by function prog_rc().
00939      */
00940     if (timer_trigger)
00941     {
00942         timer_trigger = false;
00943 
00944         if (running_timers > 0) /* Holds the number of running timers */
00945         {
00946             if ((expired_timer_queue_head == NO_TIMER) &&
00947                 (expired_timer_queue_tail == NO_TIMER))
00948             {
00949                 expired_timer_queue_head = expired_timer_queue_tail =
00950                                                     running_timer_queue_head;
00951             }
00952             else
00953             {
00954                 timer_array[expired_timer_queue_tail].next_timer_in_queue =
00955                                                     running_timer_queue_head;
00956 
00957                 expired_timer_queue_tail = running_timer_queue_head;
00958             }
00959 
00960             running_timer_queue_head =
00961                 timer_array[running_timer_queue_head].next_timer_in_queue;
00962 
00963             timer_array[expired_timer_queue_tail].next_timer_in_queue =
00964                 NO_TIMER;
00965 
00966             running_timers--;
00967 
00968             /*
00969              * As a timer has expired, the SCOCR1 is programmed (if possible)
00970              * with the new timeout value of the timer pointed by running
00971              * timer queue head
00972              */
00973             prog_ocr();
00974         }
00975     }
00976 
00977     LEAVE_CRITICAL_REGION();
00978 }
00979 #endif  /* TOTAL_NUMBER_OF_TIMERS > 0 */
00980 
00981 
00982 
00983 #if ((TOTAL_NUMBER_OF_TIMERS > 0) || defined(DOXYGEN))
00984 
00996 static void start_absolute_timer(uint8_t timer_id,
00997                           uint32_t point_in_time,
00998                           FUNC_PTR handler_cb,
00999                           void *parameter)
01000 {
01001     ENTER_CRITICAL_REGION();
01002 
01003     point_in_time &= MASK_LOW28;
01004 
01005     /* Check is done to see if any timer has expired */
01006     internal_timer_handler();
01007 
01008     if (NO_TIMER == running_timer_queue_head)
01009     {
01010         running_timer_queue_head = timer_id;
01011         timer_array[timer_id].next_timer_in_queue = NO_TIMER;
01012     }
01013     else
01014     {
01015         uint8_t i;
01016         bool timer_inserted = false;
01017         uint8_t curr_index = running_timer_queue_head;
01018         uint8_t prev_index = running_timer_queue_head;
01019 
01020         for (i = 0; i < running_timers; i++)
01021         {
01022             if (NO_TIMER != curr_index)
01023             {
01024                 if (compare_time(timer_array[curr_index].abs_exp_timer,
01025                                      point_in_time))
01026                 {
01027                     /*
01028                      * Requested absolute time value is greater than the time
01029                      * value pointed by the curr_index in the timer array
01030                      */
01031                     prev_index = curr_index;
01032                     curr_index = timer_array[curr_index].next_timer_in_queue;
01033                 }
01034                 else
01035                 {
01036                     timer_array[timer_id].next_timer_in_queue = curr_index;
01037                     if (running_timer_queue_head == curr_index)
01038                     {
01039                         /* Insertion at the head of the timer queue. */
01040                         running_timer_queue_head = timer_id;
01041                     }
01042                     else
01043                     {
01044                         timer_array[prev_index].next_timer_in_queue = timer_id;
01045                     }
01046                     timer_inserted = true;
01047                     break;
01048                 }
01049             }
01050         }
01051         if (!timer_inserted)
01052         {
01053             /* Insertion at the tail of the timer queue. */
01054             timer_array[prev_index].next_timer_in_queue = timer_id;
01055             timer_array[timer_id].next_timer_in_queue = NO_TIMER;
01056         }
01057     }
01058     timer_array[timer_id].abs_exp_timer = point_in_time;
01059     timer_array[timer_id].timer_cb = (FUNC_PTR)handler_cb;
01060     timer_array[timer_id].param_cb = parameter;
01061     running_timers++;
01062 
01063     prog_ocr();
01064 
01065     LEAVE_CRITICAL_REGION();
01066 }
01067 #endif  /* #if ((TOTAL_NUMBER_OF_TIMERS > 0) || defined(DOXYGEN)) */
01068 
01069 
01070 
01071 #if defined(DOXYGEN)
01072 
01078 void SCNT_CMP1_vect(void);
01079 #else  /* !DOXYGEN */
01080 ISR(SCNT_CMP1_vect)
01081 {
01082 #if (TOTAL_NUMBER_OF_TIMERS > 0)
01083     timer_last_trigger = SC_READ32(SCCNT);
01084 
01085     if (running_timers > 0)
01086     {
01087         timer_trigger = true;
01088     }
01089 #endif  /* #if (TOTAL_NUMBER_OF_TIMERS > 0) */
01090 }
01091 #endif /* defined(DOXYGEN) */
01092 
01093 #if defined(DOXYGEN)
01094 
01100 void SCNT_CMP2_vect(void);
01101 #else  /* !DOXYGEN */
01102 ISR(SCNT_CMP2_vect)
01103 {
01104     SC_WRITE32(SCCNT, 0xFFFFFFFF);
01105 }
01106 #endif /* defined(DOXYGEN) */
01107 
01108 
01109 #if defined(DOXYGEN)
01110 
01116 void SCNT_CMP3_vect(void);
01117 #else  /* !DOXYGEN */
01118 #ifdef ENABLE_HIGH_PRIO_TMR
01119 ISR(SCNT_CMP3_vect)
01120 {
01121     /* Turn off SCOCR2 interrupt */
01122     SCIRQM &= ~_BV(IRQMCP3);
01123 
01124     timer_expiry_cb_t callback = (timer_expiry_cb_t)
01125                            (timer_array[high_priority_timer_id].timer_cb);
01126     void *param = timer_array[high_priority_timer_id].param_cb;
01127 
01128     timer_array[high_priority_timer_id].timer_cb = NULL;
01129     timer_array[high_priority_timer_id].next_timer_in_queue = NO_TIMER;
01130 
01131     high_priority_timer_id = NO_TIMER;
01132 
01133     ASSERT(NULL != callback);
01134 
01135     /* The callback function registered for this timer is called */
01136     callback(param);
01137 }
01138 #endif /* ENABLE_HIGH_PRIO_TMR */
01139 #endif /* defined(DOXYGEN) */
01140 
01141 
01142 
01143 /* EOF */