| [1455] | 1 | /** |
|---|
| 2 | \brief TelosB-specific definition of the "radiotimer" bsp module. |
|---|
| 3 | |
|---|
| 4 | \author Thomas Watteyne <watteyne@eecs.berkeley.edu>, February 2012. |
|---|
| 5 | */ |
|---|
| 6 | |
|---|
| 7 | #include "msp430f1611.h" |
|---|
| [1457] | 8 | #include "stdio.h" |
|---|
| 9 | #include "string.h" |
|---|
| [1455] | 10 | #include "radiotimer.h" |
|---|
| 11 | |
|---|
| 12 | //=========================== variables ======================================= |
|---|
| 13 | |
|---|
| [1457] | 14 | typedef struct { |
|---|
| [1459] | 15 | radiotimer_compare_cbt overflowCb; |
|---|
| 16 | radiotimer_compare_cbt compareCb; |
|---|
| 17 | radiotimer_capture_cbt startFrameCb; |
|---|
| 18 | radiotimer_capture_cbt endFrameCb; |
|---|
| [1457] | 19 | } radiotimer_vars_t; |
|---|
| 20 | |
|---|
| 21 | radiotimer_vars_t radiotimer_vars; |
|---|
| 22 | |
|---|
| [1455] | 23 | //=========================== prototypes ====================================== |
|---|
| 24 | |
|---|
| 25 | //=========================== public ========================================== |
|---|
| 26 | |
|---|
| [1457] | 27 | void radiotimer_init() { |
|---|
| 28 | // clear local variables |
|---|
| 29 | memset(&radiotimer_vars,0,sizeof(radiotimer_vars_t)); |
|---|
| 30 | } |
|---|
| 31 | |
|---|
| [1459] | 32 | void radiotimer_setOverflowCb(radiotimer_compare_cbt cb) { |
|---|
| 33 | radiotimer_vars.overflowCb = cb; |
|---|
| [1457] | 34 | } |
|---|
| 35 | |
|---|
| [1459] | 36 | void radiotimer_setCompareCb(radiotimer_compare_cbt cb) { |
|---|
| 37 | radiotimer_vars.compareCb = cb; |
|---|
| [1457] | 38 | } |
|---|
| 39 | |
|---|
| [1459] | 40 | void radiotimer_setStartFrameCb(radiotimer_capture_cbt cb) { |
|---|
| 41 | radiotimer_vars.startFrameCb = cb; |
|---|
| [1457] | 42 | } |
|---|
| 43 | |
|---|
| [1459] | 44 | void radiotimer_setEndFrameCb(radiotimer_capture_cbt cb) { |
|---|
| 45 | radiotimer_vars.endFrameCb = cb; |
|---|
| 46 | } |
|---|
| 47 | |
|---|
| [1457] | 48 | void radiotimer_start(uint16_t period) { |
|---|
| 49 | // radio's SFD pin connected to P4.1 |
|---|
| 50 | P4DIR &= ~0x02; // input |
|---|
| 51 | P4SEL |= 0x02; // in CCI1a/B mode |
|---|
| [1455] | 52 | |
|---|
| [1457] | 53 | // CCR0 contains period of counter |
|---|
| 54 | // do not interrupt when counter reaches TBCCR0, but when it resets |
|---|
| 55 | TBCCR0 = period; |
|---|
| [1455] | 56 | |
|---|
| [1457] | 57 | // CCR1 in capture mode |
|---|
| 58 | TBCCTL1 = CM_3+SCS+CAP+CCIE; |
|---|
| 59 | TBCCR1 = 0; |
|---|
| [1455] | 60 | |
|---|
| [1457] | 61 | // CCR2 in compare mode |
|---|
| 62 | TBCCTL2 = 0; |
|---|
| 63 | TBCCR2 = 0; |
|---|
| [1455] | 64 | |
|---|
| 65 | // start counting |
|---|
| [1457] | 66 | TBCTL = TBIE+TBCLR; // interrupt when counter resets |
|---|
| 67 | TBCTL |= MC_1+TBSSEL_1; // up mode, clocked from ACLK |
|---|
| [1455] | 68 | } |
|---|
| 69 | |
|---|
| 70 | void radiotimer_schedule(uint16_t offset) { |
|---|
| 71 | // offset when to fire |
|---|
| [1457] | 72 | TACCR2 = offset; |
|---|
| 73 | |
|---|
| 74 | // enable compare interrupt (this also cancels any pending interrupts) |
|---|
| 75 | TACCTL2 = CCIE; |
|---|
| [1455] | 76 | } |
|---|
| 77 | |
|---|
| 78 | void radiotimer_cancel() { |
|---|
| [1457] | 79 | // reset compare value (also resets interrupt flag) |
|---|
| 80 | TACCR2 = 0; |
|---|
| 81 | |
|---|
| 82 | // disable compare interrupt |
|---|
| 83 | TACCTL2 &= ~CCIE; |
|---|
| [1455] | 84 | } |
|---|
| 85 | |
|---|
| 86 | inline uint16_t radiotimer_getCapturedTime() { |
|---|
| [1457] | 87 | return TACCR1; |
|---|
| [1455] | 88 | } |
|---|
| 89 | |
|---|
| 90 | //=========================== private ========================================= |
|---|
| [1457] | 91 | |
|---|
| 92 | //=========================== interrupt handlers ============================== |
|---|
| 93 | |
|---|
| 94 | /** |
|---|
| 95 | \brief TimerB CCR1-6 interrupt service routine |
|---|
| 96 | */ |
|---|
| 97 | #pragma vector=TIMERB1_VECTOR |
|---|
| 98 | __interrupt void timerb1_ISR (void) { |
|---|
| 99 | uint16_t tbiv_local; |
|---|
| 100 | |
|---|
| 101 | // reading TBIV returns the value of the highest pending interrupt flag |
|---|
| 102 | // and automatically resets that flags. We therefore copy its value to the |
|---|
| 103 | // tbiv_local local variable exactly once. If there is more than one |
|---|
| 104 | // interrupt pending, we will reenter this function after having just left |
|---|
| 105 | // it. |
|---|
| 106 | tbiv_local = TBIV; |
|---|
| 107 | |
|---|
| 108 | switch (tbiv_local) { |
|---|
| 109 | case 0x0002: // CCR1 fires |
|---|
| [1460] | 110 | if (TBCCTL1 & CCI) { |
|---|
| [1457] | 111 | // SFD pin is high: this was the start of a frame |
|---|
| [1459] | 112 | if (radiotimer_vars.startFrameCb!=NULL) { |
|---|
| 113 | radiotimer_vars.startFrameCb(TBCCR1); |
|---|
| [1457] | 114 | } |
|---|
| 115 | } else { |
|---|
| 116 | // SFD pin is low: this was the end of a frame |
|---|
| [1459] | 117 | if (radiotimer_vars.endFrameCb!=NULL) { |
|---|
| 118 | radiotimer_vars.endFrameCb(TBCCR1); |
|---|
| [1457] | 119 | } |
|---|
| 120 | } |
|---|
| 121 | break; |
|---|
| 122 | case 0x0004: // CCR2 fires |
|---|
| [1459] | 123 | if (radiotimer_vars.compareCb!=NULL) { |
|---|
| 124 | radiotimer_vars.compareCb(); |
|---|
| 125 | } |
|---|
| [1457] | 126 | break; |
|---|
| 127 | case 0x0006: // CCR3 fires |
|---|
| 128 | break; |
|---|
| 129 | case 0x0008: // CCR4 fires |
|---|
| 130 | break; |
|---|
| 131 | case 0x000a: // CCR5 fires |
|---|
| 132 | break; |
|---|
| 133 | case 0x000c: // CCR6 fires |
|---|
| 134 | break; |
|---|
| 135 | case 0x000e: // timer overflow |
|---|
| 136 | if (radiotimer_vars.overflowCb!=NULL) { |
|---|
| 137 | radiotimer_vars.overflowCb(); |
|---|
| 138 | } |
|---|
| 139 | break; |
|---|
| 140 | } |
|---|
| [1461] | 141 | |
|---|
| 142 | __bic_SR_register_on_exit(CPUOFF); // restart CPU |
|---|
| [1457] | 143 | } |
|---|
| 144 | |
|---|
| 145 | |
|---|