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