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