use model-dependent GPIO bits
[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 ADC A7 pin
49         SYSCFG2 |= ADCPCTL7;
50
51         // Configure ADC10
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_7;          // A7 ADC input select; Vref=AVCC
56         ADCIE |= ADCIE0;                // Enable ADC conv complete interrupt
57
58         // Configure timer A0 for PWM
59         TA0CCR0 = 10000-1;              // PWM Period
60         TA0CCTL2 = OUTMOD_7;            // CCR2 reset/set
61         TA0CCR2 = 500;                  // CCR2 PWM duty cycle
62         TA0CTL = TASSEL__SMCLK | MC__UP | TACLR;        // SMCLK, up mode, clear TAR
63
64         //Configure timer A1 for counting time
65         TA1CTL |= TASSEL__SMCLK | MC__CONTINUOUS | TACLR | TAIE;        // SMCLK, no divider, continuous mode
66
67         // Disable the GPIO power-on default high-impedance mode to activate
68         // previously configured port settings
69         PM5CTL0 &= ~LOCKLPM5;
70
71         while(1)
72         {
73                 unsigned int events;
74
75                 _disable_interrupts();
76                 events = irq_events;
77                 irq_events = 0;
78                 _enable_interrupts();
79
80                 // Button 2 or PIR events initiate light measurement and tuns on green led
81                 if (events & (1<<ev_btn2|1<<ev_pir1|1<<ev_pir2)) {
82                         if (Duty_Cycle > 1) {
83                                 Time_Left = 15;
84                                 continue;
85                         }
86                         ADCCTL0 |= ADCENC | ADCSC;      // Sampling and conversion start
87                         P1OUT |= BIT1;  // Set P1.1 LED on
88                 }
89
90                 // End of light measurement, set new Duty_Cycle and zero increment and tuns off green led
91                 if (events & 1<<ev_adc) {
92                         P1OUT &= ~BIT1; // Clear P1.1 LED off
93                         if (Time_Left)
94                                 continue;
95                         if (ADC_Result < 200)
96                                 continue;
97                         Time_Left = 15;
98                         Increment = 1;
99                 }
100
101                 // Button 1 sets non-zero increment (and toggles it)
102                 if (events & 1<<ev_btn1) {
103                         if (Duty_Cycle > 5000) {
104                                 Time_Left = 0;
105                                 Increment = -1;
106                         } else {
107                                 Time_Left = 15;
108                                 Increment = 1;
109                         }
110                 }
111
112                 // Timer event (100 ms) changed duty cycle and flashes red led
113                 if (events & 1<<ev_tmr) {
114                         if (Time_Count++ > 10) {
115                                 Time_Count = 0;
116                                 P1OUT ^= BIT0;
117                                 if (Time_Left)
118                                         Time_Left--;
119                                 else if (Duty_Cycle > 1)
120                                         Increment = -1;
121                         }
122                         if (Increment == 0)
123                                 continue;
124                         else if (Increment > 0)
125                                 Duty_Cycle *= 2;
126                         else if (Increment < 0)
127                                 Duty_Cycle /= 2;
128                         if (Duty_Cycle < 1) {
129                                 Duty_Cycle = 1;
130                                 Increment = 0;
131                         }
132                         if (Duty_Cycle > (10000-1)) {
133                                 Duty_Cycle = 10000-1;
134                                 Increment = 0;
135                         }
136                         TA0CCR2 = Duty_Cycle;
137                 }
138                 __bis_SR_register(LPM0_bits | GIE);
139                 __no_operation();
140         }
141         return 0; /* not reached */
142 }
143
144 // TIMER interrupt routine
145 #if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)
146 #pragma vector = TIMER1_A1_VECTOR
147 __interrupt void Timer_A (void)
148 #elif defined(__GNUC__)
149 void __attribute__ ((interrupt(TIMER1_A1_VECTOR))) Timer_A (void)
150 #else
151 #error Compiler not supported!
152 #endif
153 {
154         switch(__even_in_range(TA1IV,TA1IV_TAIFG))
155         {
156                 case TA1IV_NONE:
157                         break;  // No interrupt
158                 case TA1IV_TACCR1:
159                         break;  // CCR1 not used
160                 case TA1IV_TACCR2:
161                         break;  // CCR2 not used
162                 case TA1IV_TAIFG:
163                         irq_events |= 1<<ev_tmr;
164                         __bic_SR_register_on_exit(LPM0_bits);   // Clear CPUOFF bit from LPM0
165                         break;
166                 default:
167                         break;
168         }
169         //if (Time_Count++ > 1000) {
170         //    Time_Count = 0;
171         //    __bic_SR_register_on_exit(LPM0_bits);     // Clear CPUOFF bit from LPM0
172         //}
173 }
174
175 // ADC interrupt service routine
176 #if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)
177 #pragma vector=ADC_VECTOR
178 __interrupt void ADC_ISR(void)
179 #elif defined(__GNUC__)
180 void __attribute__ ((interrupt(ADC_VECTOR))) ADC_ISR (void)
181 #else
182 #error Compiler not supported!
183 #endif
184 {
185         switch(__even_in_range(ADCIV,ADCIV_ADCIFG))
186         {
187                 case ADCIV_NONE:
188                         break;
189                 case ADCIV_ADCOVIFG:
190                         break;
191                 case ADCIV_ADCTOVIFG:
192                         break;
193                 case ADCIV_ADCHIIFG:
194                         break;
195                 case ADCIV_ADCLOIFG:
196                         break;
197                 case ADCIV_ADCINIFG:
198                         break;
199                 case ADCIV_ADCIFG:
200                         ADC_Result = ADCMEM0;
201                         irq_events |= 1<<ev_adc;
202                         __bic_SR_register_on_exit(LPM0_bits);   // Clear CPUOFF bit from LPM0
203                         break;
204                 default:
205                         break;
206         }
207 }
208
209 // GPIO interrupt service routine
210 #if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)
211 #pragma vector=PORT2_VECTOR
212 __interrupt void Port_2(void)
213 #elif defined(__GNUC__)
214 void __attribute__ ((interrupt(PORT2_VECTOR))) Port_2 (void)
215 #else
216 #error Compiler not supported!
217 #endif
218 {
219         if (P2IFG & BIT3) {
220                 irq_events |= 1<<ev_btn1;
221                 P2IFG &= ~BIT3; // Clear P1.3 IFG
222         }
223         if (P2IFG & BIT7) {
224                 irq_events |= 1<<ev_btn2;
225                 P2IFG &= ~BIT7; // Clear P1.3 IFG
226         }
227         if (P2IFG & BIT2) {
228                 irq_events |= 1<<ev_pir1;
229                 P2IFG &= ~BIT2; // Clear P1.4 IFG
230         }
231         if (P2IFG & BIT5) {
232                 irq_events |= 1<<ev_pir2;
233                 P2IFG &= ~BIT5; // Clear P1.7 IFG
234         }
235         __bic_SR_register_on_exit(LPM3_bits);   // Exit LPM3
236 }