parametrize button interrupts per model
[sensor-light.git] / msp430 / main.c
1 #include <msp430.h> 
2
3 static volatile unsigned int ADC_Result;
4 static volatile unsigned int irq_events = 0;
5 enum {ev_btn1 = 0, ev_btn2, ev_pir1, ev_pir2, ev_tmr, ev_adc, ev_MAX};
6
7 #ifdef ADCSC /* Let us hope that this is a "new" model */
8 # define BIT_RL BIT0
9 # define BIT_GL BIT1
10 # define PBTN(x) P2##x
11 # define BIT_BTN BIT3
12 # define HAVE_BTN2
13 # define BIT_BTN2 BIT7
14 #else
15 # define BIT_RL BIT0
16 # define BIT_GL BIT6
17 # define PBTN(x) P1##x
18 # define BIT_BTN BIT3
19 # define BIT_BTN2 0
20 #endif
21
22 int main(void)
23 {
24         int Duty_Cycle = 1;
25         int Increment = 1;
26         unsigned int Time_Count = 0;
27         unsigned int Time_Left = 5;
28
29         WDTCTL = WDTPW | WDTHOLD;       // stop watchdog timer
30         // Configure GPIO Out
31         P1DIR |= BIT_RL|BIT_GL|BIT7;    // Set LEDs & PWM to output direction
32         P1OUT &= ~(BIT_RL|BIT_GL);      // LEDs off
33         P1SEL1 |= BIT7;                 // PWM out
34
35         // Configure GPIO In
36         PBTN(DIR) &= ~(BIT_BTN|BIT_BTN2);       // Buttons
37         PBTN(OUT) |= BIT_BTN|BIT_BTN2;          // Pull up
38         PBTN(REN) |= BIT_BTN|BIT_BTN2;          // Enable pull-up
39         PBTN(IES) |= BIT_BTN|BIT_BTN2;          // INT on Hi->Lo edge
40         PBTN(IE)  |= BIT_BTN|BIT_BTN2;          // INT enable
41
42         P2DIR &= ~(BIT4|BIT5);          // PIR Sensors
43         P2OUT &= ~(BIT4|BIT5);          // Pull down
44         P2REN |= BIT4|BIT5;             // Enable pull-down
45         P2IES &= ~(BIT4|BIT5);          // INT on Lo->Hi edge
46         P2IE  |= BIT4|BIT5;             // INT enable
47
48         // Configure ADC10
49
50 #ifdef ADCPCTL4 /* Newer model */
51         SYSCFG2 |= ADCPCTL4|ADCPCTL5;   // disconnect pin 4 and 5 from GPIO
52         ADCCTL0 |= ADCSHT_2 | ADCON;    // ADCON, S&H=16 ADC clks
53         ADCCTL1 |= ADCSHP;              // ADCCLK = MODOSC; sampling timer
54         ADCCTL2 |= ADCRES;              // 10-bit conversion results
55         ADCMCTL0 |= ADCINCH_4;          // A4 ADC input select; Vref=AVCC
56         ADCIE |= ADCIE0;                // Enable ADC conv complete interrupt
57         // channel 5 is unused, reserved for measuring current
58 #else
59 # error older mode ADC unimplemented
60         // channel 5 is unused, reserved for measuring current
61 #endif
62
63         // Configure timer A0 for PWM
64         TA0CCR0 = 10000-1;              // PWM Period
65         TA0CCTL2 = OUTMOD_7;            // CCR2 reset/set
66         TA0CCR2 = 500;                  // CCR2 PWM duty cycle
67         TA0CTL = TASSEL__SMCLK | MC__UP | TACLR;        // SMCLK, up mode, clear TAR
68
69         //Configure timer A1 for counting time
70         TA1CTL |= TASSEL__SMCLK | MC__CONTINUOUS | TACLR | TAIE;        // SMCLK, no divider, continuous mode
71
72         // Disable the GPIO power-on default high-impedance mode to activate
73         // previously configured port settings
74         PM5CTL0 &= ~LOCKLPM5;
75
76         while(1)
77         {
78                 unsigned int events;
79
80                 _disable_interrupts();
81                 events = irq_events;
82                 irq_events = 0;
83                 _enable_interrupts();
84
85                 // Button 2 or PIR events initiate light measurement and tuns on green led
86                 if (events & (1<<ev_btn2|1<<ev_pir1|1<<ev_pir2)) {
87                         if (Duty_Cycle > 1) {
88                                 Time_Left = 15;
89                                 continue;
90                         }
91                         ADCCTL0 |= ADCENC | ADCSC;      // Sampling and conversion start
92                         // ADC10CTL0 |= ENC + ADC10SC;  // Sampling and conversion start
93                         P1OUT |= BIT_GL;        // Set green LED on
94                 }
95
96                 // End of light measurement,
97                 // set new Duty_Cycle and zero increment and turn off green led
98                 if (events & 1<<ev_adc) {
99                         P1OUT &= ~BIT_GL;       // Clear green LED off
100                         if (Time_Left)
101                                 continue;
102                         if (ADC_Result < 200)
103                                 continue;
104                         Time_Left = 15;
105                         Increment = 1;
106                 }
107
108                 // Button 1 sets non-zero increment (and toggles it)
109                 if (events & 1<<ev_btn1) {
110                         if (Duty_Cycle > 5000) {
111                                 Time_Left = 0;
112                                 Increment = -1;
113                         } else {
114                                 Time_Left = 15;
115                                 Increment = 1;
116                         }
117                 }
118
119                 // Timer event (100 ms) changed duty cycle and flashes red led
120                 if (events & 1<<ev_tmr) {
121                         if (Time_Count++ > 10) {
122                                 Time_Count = 0;
123                                 P1OUT ^= BIT_RL; // blink
124                                 if (Time_Left)
125                                         Time_Left--;
126                                 else if (Duty_Cycle > 1)
127                                         Increment = -1;
128                         }
129                         if (Increment == 0)
130                                 continue;
131                         else if (Increment > 0)
132                                 Duty_Cycle *= 2;
133                         else if (Increment < 0)
134                                 Duty_Cycle /= 2;
135                         if (Duty_Cycle < 1) {
136                                 Duty_Cycle = 1;
137                                 Increment = 0;
138                         }
139                         if (Duty_Cycle > (10000-1)) {
140                                 Duty_Cycle = 10000-1;
141                                 Increment = 0;
142                         }
143                         TA0CCR2 = Duty_Cycle;
144                 }
145                 __bis_SR_register(LPM0_bits | GIE);
146                 __no_operation();
147         }
148         return 0; /* not reached */
149 }
150
151 // TIMER interrupt routine
152 #if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)
153 #pragma vector = TIMER1_A1_VECTOR
154 __interrupt void Timer_A (void)
155 #elif defined(__GNUC__)
156 void __attribute__ ((interrupt(TIMER1_A1_VECTOR))) Timer_A (void)
157 #else
158 #error Compiler not supported!
159 #endif
160 {
161         switch(__even_in_range(TA1IV,TA1IV_TAIFG))
162         {
163                 case TA1IV_NONE:
164                         break;  // No interrupt
165                 case TA1IV_TACCR1:
166                         break;  // CCR1 not used
167                 case TA1IV_TACCR2:
168                         break;  // CCR2 not used
169                 case TA1IV_TAIFG:
170                         irq_events |= 1<<ev_tmr;
171                         __bic_SR_register_on_exit(LPM0_bits);   // Wake up
172                         break;
173                 default:
174                         break;
175         }
176 }
177
178 // ADC interrupt service routine
179 #if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)
180 #pragma vector=ADC_VECTOR
181 __interrupt void ADC_ISR(void)
182 #elif defined(__GNUC__)
183 void __attribute__ ((interrupt(ADC_VECTOR))) ADC_ISR (void)
184 #else
185 #error Compiler not supported!
186 #endif
187 {
188         switch(__even_in_range(ADCIV,ADCIV_ADCIFG))
189         {
190                 case ADCIV_NONE:
191                         break;
192                 case ADCIV_ADCOVIFG:
193                         break;
194                 case ADCIV_ADCTOVIFG:
195                         break;
196                 case ADCIV_ADCHIIFG:
197                         break;
198                 case ADCIV_ADCLOIFG:
199                         break;
200                 case ADCIV_ADCINIFG:
201                         break;
202                 case ADCIV_ADCIFG:
203                         ADC_Result = ADCMEM0;
204                         irq_events |= 1<<ev_adc;
205                         __bic_SR_register_on_exit(LPM0_bits);   // Wake up
206                         break;
207                 default:
208                         break;
209         }
210 }
211
212 // GPIO interrupt service routine
213 #if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)
214 #pragma vector=PORT2_VECTOR
215 __interrupt void Port_2(void)
216 #elif defined(__GNUC__)
217 void __attribute__ ((interrupt(PORT2_VECTOR))) Port_2 (void)
218 #else
219 #error Compiler not supported!
220 #endif
221 {
222         if (PBTN(IFG) & BIT_BTN) {
223                 irq_events |= 1<<ev_btn1;
224                 PBTN(IFG) &= ~BIT_BTN;  // Clear button IFG
225         }
226 #ifdef HAVE_BTN2
227         if (PBTN(IFG) & BIT_BTN2) {
228                 irq_events |= 1<<ev_btn2;
229                 PBTN(IFG) &= ~BIT_BTN2; // Clear button 2 IFG
230         }
231 #endif
232         if (P2IFG & BIT4) {
233                 irq_events |= 1<<ev_pir1;
234                 P2IFG &= ~BIT4; // Clear P2.4 IFG
235         }
236         if (P2IFG & BIT5) {
237                 irq_events |= 1<<ev_pir2;
238                 P2IFG &= ~BIT5; // Clear P2.5 IFG
239         }
240         __bic_SR_register_on_exit(LPM0_bits);   // Wake up
241 }