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