Replace final picture
[sensor-light.git] / msp430 / main.c
index 7de46c33bb0835c18fcce8c47781ec06491ccf4c..53ee457adf1da057d276a1f2bf221a9700be1a14 100644 (file)
@@ -4,55 +4,106 @@ static volatile unsigned int ADC_Result;
 static volatile unsigned int irq_events = 0;
 enum {ev_btn1 = 0, ev_btn2, ev_pir1, ev_pir2, ev_tmr, ev_adc, ev_MAX};
 
+#define PWM_ORDER 10
+#define PWM_HALF 5
+#define LIGHT_THRESHOLD 900
+#define TIME_ON 320
+       
+#ifdef ADCSC /* Let us hope that this is a "new" model */
+# define BIT_RL BIT0
+# define BIT_GL BIT1
+# define PBTN(x) P2##x
+# define BIT_BTN BIT3
+# define HAVE_BTN2
+# define BIT_BTN2 BIT7
+#else
+# define BIT_RL BIT0
+# define BIT_GL BIT6
+# define PBTN(x) P1##x
+# define BIT_BTN BIT3
+# define BIT_BTN2 0
+#endif
+
+static int expon2(int duty)
+{
+       int shift = duty>>1;
+       int comp = 1<<shift;
+       int extra = (duty & 1) ? comp>>1 : 0;
+       return (duty ? comp|extra : 0);
+}
+
 int main(void)
 {
-       int Duty_Cycle = 1;
+       int Duty_Cycle = 0;
        int Increment = 1;
-       unsigned int Time_Count = 0;
-       unsigned int Time_Left = 5;
+       unsigned int Time_Left = 50;
+       unsigned int Time_Indicate = 2;
 
        WDTCTL = WDTPW | WDTHOLD;       // stop watchdog timer
        // Configure GPIO Out
-       P1DIR |= BIT0|BIT1|BIT2;     // Set P1.0&1&2/LEDs to output direction
-       P1OUT &= ~(BIT0|BIT1);       // P1.0&1 LEDs off
-       P1SEL1 |= BIT2;              // P1.2 PWM out
+       P1DIR |= BIT_RL|BIT_GL|BIT2;    // Set LEDs & PWM to output direction
+       P1OUT &= ~(BIT_RL|BIT_GL);      // LEDs off
+#ifdef P1SEL1
+       P1SEL1 |= BIT2;                 // PWM out
+#else
+       P1SEL |= BIT2;                  // PWM out
+#endif
 
        // Configure GPIO In
-       P2DIR &= ~(BIT3|BIT7);       // Buttons
-       P2OUT |= BIT3|BIT7;          // Pull up
-       P2REN |= BIT3|BIT7;          // Enable pull-up
-       P2IES |= BIT3|BIT7;          // INT on Hi->Lo edge
-       P2IE  |= BIT3|BIT7;          // INT enable
-
-       P2DIR &= ~(BIT2|BIT5);       // PIR Sensors
-       P2OUT &= ~(BIT2|BIT5);       // Pull down
-       P2REN |= BIT2|BIT5;          // Enable pull-down
-       P2IES &= ~(BIT2|BIT5);       // INT on Lo->Hi edge
-       P2IE  |= BIT2|BIT5;          // INT enable
-       P2IFG = 0;                   // ??? Needed?
-
-       // Configure ADC A7 pin
-       SYSCFG2 |= ADCPCTL7;
+       PBTN(DIR) &= ~(BIT_BTN|BIT_BTN2);       // Buttons
+       PBTN(OUT) |= BIT_BTN|BIT_BTN2;          // Pull up
+       PBTN(REN) |= BIT_BTN|BIT_BTN2;          // Enable pull-up
+       PBTN(IES) |= BIT_BTN|BIT_BTN2;          // INT on Hi->Lo edge
+       PBTN(IE)  |= BIT_BTN|BIT_BTN2;          // INT enable
+
+       P2DIR &= ~(BIT4|BIT5);          // PIR Sensors
+       P2OUT &= ~(BIT4|BIT5);          // Pull down
+       P2REN &= ~(BIT4|BIT5);          // Disable pull
+       P2IES &= ~(BIT4|BIT5);          // INT on Lo->Hi edge
+       P2IE  |= BIT4|BIT5;             // INT enable
 
        // Configure ADC10
-       ADCCTL0 |= ADCSHT_2 | ADCON;        // ADCON, S&H=16 ADC clks
-       ADCCTL1 |= ADCSHP;                  // ADCCLK = MODOSC; sampling timer
-       ADCCTL2 |= ADCRES;                  // 10-bit conversion results
-       ADCMCTL0 |= ADCINCH_7;              // A7 ADC input select; Vref=AVCC
-       ADCIE |= ADCIE0;                    // Enable ADC conv complete interrupt
+
+#ifdef ADCPCTL4 /* Newer model */
+       SYSCFG2 |= ADCPCTL4|ADCPCTL5;   // disconnect pin 4 and 5 from GPIO
+       ADCCTL0 |= ADCSHT_2 | ADCON;    // ADCON, S&H=16 ADC clks
+       ADCCTL1 |= ADCSHP;              // ADCCLK = MODOSC; sampling timer
+       ADCCTL2 |= ADCRES;              // 10-bit conversion results
+       ADCMCTL0 |= ADCINCH_4;          // A4 ADC input select; Vref=AVCC
+       ADCIE |= ADCIE0;                // Enable ADC conv complete interrupt
+       // channel 5 is unused, reserved for measuring current
+#else
+       ADC10CTL0 = ADC10SHT_2 + ADC10ON + ADC10IE; // ADCON, S&H=16 ADC clks
+       ADC10CTL1 = INCH_4;             // A4 ADC input select
+       // channel 5 is unused, reserved for measuring current
+#endif
+
+       // Timer and PWM
+
+#ifndef TASSEL__SMCLK
+# define TASSEL__SMCLK TASSEL_2
+# define MC__UP MC_1
+# define MC__CONTINUOUS MC_2
+# define TA0CCR2 TA0CCR1
+# define TA0CCTL2 TA0CCTL1
+#endif
 
        // Configure timer A0 for PWM
-       TA0CCR0 = 10000-1;                         // PWM Period
-       TA0CCTL2 = OUTMOD_7;                      // CCR2 reset/set
-       TA0CCR2 = 500;                     // CCR2 PWM duty cycle
-       TA0CTL = TASSEL__SMCLK | MC__UP | TACLR;  // SMCLK, up mode, clear TAR
+       TA0CCR0 = 1 << PWM_ORDER;       // PWM Period 2^10 ca. 1 kHz
+       TA0CCR2 = 0;                    // CCR1 PWM duty cycle
+       TA0CCTL2 = OUTMOD_7;            // CCR1 reset/set
+       TA0CTL = TASSEL__SMCLK | MC__UP | TACLR;// SMCLK, up mode
+               // SMCLK, no divider, up mode, no interrupt, clear TAR
 
        //Configure timer A1 for counting time
-       TA1CTL |= TASSEL__SMCLK | MC__CONTINUOUS | TACLR | TAIE;     // SMCLK, no divider, continuous mode
+       TA1CTL |= TASSEL__SMCLK | MC__CONTINUOUS | TACLR | TAIE;
+               // SMCLK, no divider, continuous mode, interrupt enable
 
+#ifdef LOCKLPM5
        // Disable the GPIO power-on default high-impedance mode to activate
        // previously configured port settings
        PM5CTL0 &= ~LOCKLPM5;
+#endif
 
        while(1)
        {
@@ -63,63 +114,72 @@ int main(void)
                irq_events = 0;
                _enable_interrupts();
 
-               // Button 2 or PIR events initiate light measurement and tuns on green led
+               // Button 2 or PIR events initiate light measurement
+               // and tuns on green or red led
                if (events & (1<<ev_btn2|1<<ev_pir1|1<<ev_pir2)) {
-                       if (Duty_Cycle > 1) {
-                               Time_Left = 15;
-                               continue;
-                       }
-                       ADCCTL0 |= ADCENC | ADCSC;                       // Sampling and conversion start
-                       P1OUT |= BIT1;                                   // Set P1.1 LED on
+                       if (events & 1<<ev_pir1)
+                               P1OUT |= BIT_GL;        // Set green LED on
+                       if (events & 1<<ev_pir2)
+                               P1OUT |= BIT_RL;        // Set red LED on
+                       // Sampling and conversion start
+#ifdef ADCENC
+                       ADCCTL0 |= ADCENC | ADCSC;
+#else
+                       ADC10CTL0 |= ENC + ADC10SC;
+#endif
                }
 
-               // End of light measurement, set new Duty_Cycle and zero increment and tuns off green led
+               // End of light measurement. Set new Duty_Cycle,
+               // zero increment and turn off green led
                if (events & 1<<ev_adc) {
-                       P1OUT &= ~BIT1;                                  // Clear P1.1 LED off
-                       if (Time_Left)
-                               continue;
-                       if (ADC_Result < 200)
+                       P1OUT ^= (BIT_GL|BIT_RL); // Flip green and red LEDs
+                       Time_Indicate = 5;
+                       if (ADC_Result < LIGHT_THRESHOLD)
                                continue;
-                       Time_Left = 15;
+                       Time_Left = TIME_ON;
                        Increment = 1;
                }
 
                // Button 1 sets non-zero increment (and toggles it)
                if (events & 1<<ev_btn1) {
-                       if (Duty_Cycle > 5000) {
+                       P1OUT |= (BIT_GL|BIT_RL); // Set green and red LEDs on
+                       Time_Indicate = 5;
+                       if (Duty_Cycle > PWM_HALF) {
                                Time_Left = 0;
                                Increment = -1;
                        } else {
-                               Time_Left = 15;
+                               Time_Left = TIME_ON;
                                Increment = 1;
                        }
                }
 
                // Timer event (100 ms) changed duty cycle and flashes red led
                if (events & 1<<ev_tmr) {
-                       if (Time_Count++ > 10) {
-                               Time_Count = 0;
-                               P1OUT ^= BIT0;
-                               if (Time_Left)
-                                       Time_Left--;
-                               else if (Duty_Cycle > 1)
-                                       Increment = -1;
-                       }
-                       if (Increment == 0)
-                               continue;
-                       else if (Increment > 0)
-                               Duty_Cycle *= 2;
-                       else if (Increment < 0)
-                               Duty_Cycle /= 2;
-                       if (Duty_Cycle < 1) {
-                               Duty_Cycle = 1;
-                               Increment = 0;
+                       if (Time_Indicate) {
+                               Time_Indicate--;
+                               if (!Time_Indicate)
+                                       P1OUT &= ~(BIT_RL|BIT_GL); // LEDs off
                        }
-                       if (Duty_Cycle > (10000-1)) {
-                               Duty_Cycle = 10000-1;
-                               Increment = 0;
+                       if (Time_Left) {
+                               Time_Left--;
+                               if (!Time_Left)
+                                       if (Duty_Cycle)
+                                               Increment = -1;
                        }
-                       TA0CCR2 = Duty_Cycle;
+                       if (Increment > 0) {
+                               if (++Duty_Cycle >= (PWM_ORDER<<1)) {
+                                       Duty_Cycle = PWM_ORDER<<1;
+                                       Increment = 0;
+                               }
+                       } else if (Increment < 0) {
+                               if (--Duty_Cycle < 1) {
+                                       Duty_Cycle = 0;
+                                       Increment = 0;
+                               }
+                       } else // Increment _was_ zero - no change!
+                               continue;
+
+                       TA0CCR2 = expon2(Duty_Cycle);
                }
                __bis_SR_register(LPM0_bits | GIE);
                __no_operation();
@@ -140,24 +200,25 @@ void __attribute__ ((interrupt(TIMER1_A1_VECTOR))) Timer_A (void)
        switch(__even_in_range(TA1IV,TA1IV_TAIFG))
        {
                case TA1IV_NONE:
-                       break;                               // No interrupt
+                       break;  // No interrupt
                case TA1IV_TACCR1:
-                       break;                               // CCR1 not used
+                       break;  // CCR1 not used
                case TA1IV_TACCR2:
-                       break;                               // CCR2 not used
+                       break;  // CCR2 not used
                case TA1IV_TAIFG:
                        irq_events |= 1<<ev_tmr;
-                       __bic_SR_register_on_exit(LPM0_bits);            // Clear CPUOFF bit from LPM0
+                       __bic_SR_register_on_exit(LPM0_bits);   // Wake up
                        break;
                default:
                        break;
        }
-       //if (Time_Count++ > 1000) {
-       //    Time_Count = 0;
-       //    __bic_SR_register_on_exit(LPM0_bits);            // Clear CPUOFF bit from LPM0
-       //}
 }
 
+#ifndef ADC_VECTOR
+# define ADCMEM0 ADC10MEM
+# define ADC_VECTOR ADC10_VECTOR
+#endif
+
 // ADC interrupt service routine
 #if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)
 #pragma vector=ADC_VECTOR
@@ -168,6 +229,7 @@ void __attribute__ ((interrupt(ADC_VECTOR))) ADC_ISR (void)
 #error Compiler not supported!
 #endif
 {
+#ifdef ADCIV_NONE
        switch(__even_in_range(ADCIV,ADCIV_ADCIFG))
        {
                case ADCIV_NONE:
@@ -183,13 +245,16 @@ void __attribute__ ((interrupt(ADC_VECTOR))) ADC_ISR (void)
                case ADCIV_ADCINIFG:
                        break;
                case ADCIV_ADCIFG:
+#endif
                        ADC_Result = ADCMEM0;
                        irq_events |= 1<<ev_adc;
-                       __bic_SR_register_on_exit(LPM0_bits);            // Clear CPUOFF bit from LPM0
+                       __bic_SR_register_on_exit(LPM0_bits);   // Wake up
+#ifdef ADCIV_NONE
                        break;
                default:
                        break;
        }
+#endif
 }
 
 // GPIO interrupt service routine
@@ -202,21 +267,37 @@ void __attribute__ ((interrupt(PORT2_VECTOR))) Port_2 (void)
 #error Compiler not supported!
 #endif
 {
-       if (P2IFG & BIT3) {
-               irq_events |= 1<<ev_btn1;
-               P2IFG &= ~BIT3;                      // Clear P1.3 IFG
-       }
-       if (P2IFG & BIT7) {
-               irq_events |= 1<<ev_btn2;
-               P2IFG &= ~BIT7;                      // Clear P1.3 IFG
-       }
-       if (P2IFG & BIT2) {
+       if (P2IFG & BIT4) {
                irq_events |= 1<<ev_pir1;
-               P2IFG &= ~BIT2;                      // Clear P1.4 IFG
+               P2IFG &= ~BIT4; // Clear P2.4 IFG
        }
        if (P2IFG & BIT5) {
                irq_events |= 1<<ev_pir2;
-               P2IFG &= ~BIT5;                      // Clear P1.7 IFG
+               P2IFG &= ~BIT5; // Clear P2.5 IFG
        }
-       __bic_SR_register_on_exit(LPM3_bits);   // Exit LPM3
+#if (PBTN() == P1)
+       __bic_SR_register_on_exit(LPM0_bits);   // Wake up
+}
+// GPIO interrupt service routine
+#if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)
+#pragma vector=PORT1_VECTOR
+__interrupt void Port_1(void)
+#elif defined(__GNUC__)
+void __attribute__ ((interrupt(PORT1_VECTOR))) Port_1 (void)
+#else
+#error Compiler not supported!
+#endif
+{
+#endif /* (PBTN() == P1) */
+       if (PBTN(IFG) & BIT_BTN) {
+               irq_events |= 1<<ev_btn1;
+               PBTN(IFG) &= ~BIT_BTN;  // Clear button IFG
+       }
+#ifdef HAVE_BTN2
+       if (PBTN(IFG) & BIT_BTN2) {
+               irq_events |= 1<<ev_btn2;
+               PBTN(IFG) &= ~BIT_BTN2; // Clear button 2 IFG
+       }
+#endif
+       __bic_SR_register_on_exit(LPM0_bits);   // Wake up
 }