Go to the documentation of this file.00001
00013
00014
00015
00016
00017
00018
00019
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
00031
00032
00033
00034
00035
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
00045
00046
00047
00048
00049
00050 timer_info_t timer_array[TOTAL_NUMBER_OF_TIMERS];
00051
00052
00053 #ifdef NO_32KHZ_CRYSTAL
00054 uint8_t running_timers;
00055 #else
00056 static uint8_t running_timers;
00057 #endif
00058
00059
00060 volatile bool timer_trigger;
00061
00062
00063 static uint_fast8_t running_timer_queue_head;
00064
00065
00066 static uint_fast8_t expired_timer_queue_head;
00067
00068
00069 static uint_fast8_t expired_timer_queue_tail;
00070
00071
00072 static uint32_t timer_last_trigger;
00073 #endif
00074
00075
00076 #ifdef ENABLE_HIGH_PRIO_TMR
00077 static volatile uint8_t high_priority_timer_id;
00078 #endif
00079
00080
00081
00087 #define DELAY_WITHOUT_IRQS_US (100)
00088
00089
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
00098
00099
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
00128 if ((t1 & MASK_LOW27) > (t2 & MASK_LOW27))
00129 {
00130 comparison_status = true;
00131 }
00132 }
00133 return comparison_status;
00134 }
00135 #endif
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
00154
00155
00156
00157 {
00158 timer_expiry_cb_t callback;
00159 void *callback_param;
00160 uint8_t next_expired_timer;
00161
00162
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
00170 callback = (timer_expiry_cb_t)timer_array[expired_timer_queue_head].timer_cb;
00171
00172
00173 callback_param = timer_array[expired_timer_queue_head].param_cb;
00174
00175
00176
00177
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
00185
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
00199 callback(callback_param);
00200 }
00201 }
00202 }
00203 }
00204 #endif
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
00251
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
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
00337
00338
00339
00340 return PAL_TMR_ALREADY_RUNNING;
00341 }
00342
00343
00344
00345
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
00360
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
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
00413 internal_timer_handler();
00414
00415
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
00432
00433
00434
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
00445
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
00465
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
00478
00479
00480 if (expired_timer_queue_head == expired_timer_queue_tail)
00481 {
00482
00483 expired_timer_queue_head = expired_timer_queue_tail =
00484 NO_TIMER;
00485 }
00486 else
00487 {
00488
00489
00490
00491
00492 expired_timer_queue_head =
00493 timer_array[expired_timer_queue_head].next_timer_in_queue;
00494 }
00495 }
00496 else
00497 {
00498
00499
00500
00501
00502 timer_array[prev_index].next_timer_in_queue =
00503 timer_array[timer_id].next_timer_in_queue;
00504
00505
00506
00507
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
00529
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
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
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
00584
00585
00586
00590 void timer_init(void)
00591 {
00592 #if ((TOTAL_NUMBER_OF_TIMERS > 0) || defined(DOXYGEN))
00593
00594
00595
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
00615
00616
00617
00618
00619
00620
00621
00622 #ifndef NO_32KHZ_CRYSTAL
00623 ASSR = _BV(AS2);
00624 #endif
00625
00626
00627
00628
00629
00630 SCCR0 = _BV(SCTSE) | _BV(SCEN) | _BV(SCRES);
00631
00632
00633
00634
00635
00636
00637
00638
00639
00640
00641
00642
00643
00644
00645
00646
00647
00648 SC_WRITE32(SCOCR2, 0x0FFFFFFFul);
00649 SCIRQS = _BV(IRQSCP2);
00650 SCIRQM |= _BV(IRQMCP2);
00651
00652 #ifdef ENABLE_RC_OSC_CALIBRATION
00653
00654
00655
00656
00657
00658
00659
00660 for (uint8_t i = 0; i < 10; i++)
00661 {
00662 pal_timer_delay(50000);
00663 }
00664 #endif
00665 }
00666
00667
00668
00682 void pal_timer_source_select(source_type_t source)
00683 {
00684
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
00737
00738
00739
00740
00741 if (delay < DELAY_WITHOUT_IRQS_US)
00742 {
00743 needs_cli = true;
00744 sreg = SREG;
00745 cli();
00746 }
00747
00748
00749
00750
00751
00752
00753
00754
00755
00756
00757
00758
00759
00760
00761
00762
00763
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
00770
00771
00772
00773 while (delay != 0)
00774 {
00775 uint16_t actval;
00776
00777
00778
00779
00780
00781
00782
00783 if (delay > UINT16_MAX / 2 )
00784 {
00785 actval = UINT16_MAX / 2;
00786 }
00787 else
00788 {
00789 actval = delay;
00790 }
00791 delay -= actval;
00792
00793
00794
00795
00796
00797
00798
00799
00800 #if (F_CPU == 16000000)
00801
00802 actval *= 2 ;
00803 #endif
00804 #if (F_CPU == 4000000)
00805
00806 actval /= 2 ;
00807 #endif
00808 TCNT5 = (uint16_t)(-((int16_t)actval));
00809 TIFR5 = _BV(TOV5);
00810 TCCR5B = _BV(CS51);
00811 while ((TIFR5 & _BV(TOV5)) == 0)
00812 ;
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
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
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
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
00904
00905
00906
00907
00908
00909
00910 while (SC_READ32(SCCNT) != new_ocr)
00911 ;
00912 timer_trigger = true;
00913 }
00914 }
00915 else
00916 {
00917 SCIRQM &= ~_BV(IRQMCP1);
00918 }
00919 }
00920 #endif
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
00938
00939
00940 if (timer_trigger)
00941 {
00942 timer_trigger = false;
00943
00944 if (running_timers > 0)
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
00970
00971
00972
00973 prog_ocr();
00974 }
00975 }
00976
00977 LEAVE_CRITICAL_REGION();
00978 }
00979 #endif
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
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
01029
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
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
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
01068
01069
01070
01071 #if defined(DOXYGEN)
01072
01078 void SCNT_CMP1_vect(void);
01079 #else
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
01090 }
01091 #endif
01092
01093 #if defined(DOXYGEN)
01094
01100 void SCNT_CMP2_vect(void);
01101 #else
01102 ISR(SCNT_CMP2_vect)
01103 {
01104 SC_WRITE32(SCCNT, 0xFFFFFFFF);
01105 }
01106 #endif
01107
01108
01109 #if defined(DOXYGEN)
01110
01116 void SCNT_CMP3_vect(void);
01117 #else
01118 #ifdef ENABLE_HIGH_PRIO_TMR
01119 ISR(SCNT_CMP3_vect)
01120 {
01121
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
01136 callback(param);
01137 }
01138 #endif
01139 #endif
01140
01141
01142
01143