]> git.karo-electronics.de Git - oswald.git/blobdiff - metawatch/mw_main.c
Add modified LPM3_EXIT_ISR to work around FLL IRQ wake-up problem
[oswald.git] / metawatch / mw_main.c
index 89b014ebe748be909e475509957392796cf23304..07f8ba581a3c1c4493d02caf420ca31ca6eb87e4 100644 (file)
@@ -3,6 +3,9 @@
 #include <stdio.h>
 #include <string.h>
 
+#include "F5xx_F6xx_Core_Lib/HAL_PMM.h"
+#include "F5xx_F6xx_Core_Lib/HAL_UCS.h"
+
 #include "mw_main.h"
 
 #include "mw_uart.h"
@@ -10,6 +13,7 @@
 #include "mw_bt.h"
 #include "mw_adc.h"
 #include "mw_bt.h"
+#include "mw_acc.h"
 #include "bt_hci.h"
 #include "bt_l2cap.h"
 
 
 #include "bluetooth_init_cc256x.h"
 
-unsigned int _event_src = 0;
+uint16_t _event_src = 0;
+
+#define HARDWARE_REVISION_ADDRESS (0x1a07)
 
+uint8_t GetMsp430HardwareRevision(void)
+{
+       uint8_t *pDeviceType = (uint8_t *)(uint8_t *)HARDWARE_REVISION_ADDRESS;
+  
+       return pDeviceType[0]+'1';                         
+}
+
+uint8_t DetermineErrata(void)
+{
+       uint8_t Revision = GetMsp430HardwareRevision();
+  
+       switch (Revision) {
+               case 'F':
+               case 'G':
+               case 'H':
+                       return 0;
+                       break;
+               default:
+                       return 1;
+                       break;
+       }
+}
 
 static void set16mhz(void)
 {
@@ -41,12 +69,41 @@ static void set16mhz(void)
        }
 }
 
+static unsigned char PMM15Check(void)
+{
+  // First check if SVSL/SVML is configured for fast wake-up
+  if ((!(SVSMLCTL & SVSLE)) || ((SVSMLCTL & SVSLE) && (SVSMLCTL & SVSLFP)) ||
+      (!(SVSMLCTL & SVMLE)) || ((SVSMLCTL & SVMLE) && (SVSMLCTL & SVMLFP)))
+  { 
+    // Next Check SVSH/SVMH settings to see if settings are affected by PMM15
+    if ((SVSMHCTL & SVSHE) && (!(SVSMHCTL & SVSHFP)))
+    {
+      if ( (!(SVSMHCTL & SVSHMD)) ||
+           ((SVSMHCTL & SVSHMD) && (SVSMHCTL & SVSMHACE)) )
+        return 1; // SVSH affected configurations
+    }
+
+    if ((SVSMHCTL & SVMHE) && (!(SVSMHCTL & SVMHFP)) && (SVSMHCTL & SVSMHACE))
+      return 1; // SVMH affected configurations
+  }
+
+  return 0; // SVS/M settings not affected by PMM15
+}
+
+#define configCPU_CLOCK_HZ ((unsigned long) 16777216) /* 512*32768 */
+#define configTICK_RATE_HZ ((unsigned int)1024)
+#define ACLK_MULTIPLIER    ((unsigned int)512)
+
 static void setup_clocks(void)
 {
        unsigned long i;
 
+       SetVCore(PMMCOREV_2);
+
        /* use external oscillator */
        P7SEL |= BIT0 + BIT1;
+
+#if 1
        if ((UCSCTL6 & XT1DRIVE_3) != XT1DRIVE_3) {
                UCSCTL6_L |= XT1DRIVE1_L + XT1DRIVE0_L;
        }
@@ -60,6 +117,51 @@ static void setup_clocks(void)
        set16mhz();
 
        UCSCTL8 |= SMCLKREQEN;
+#else
+       // Startup LFXT1 32 kHz crystal
+       while (LFXT_Start_Timeout(XT1DRIVE_0, 50000) == UCS_STATUS_ERROR)
+               nop();
+
+       // select the sources for the FLL reference and ACLK
+       SELECT_ACLK(SELA__XT1CLK);
+       SELECT_FLLREF(SELREF__XT1CLK);
+
+       // 512 * 32768 = 16777216 / 1024
+       Init_FLL_Settle(configCPU_CLOCK_HZ/configTICK_RATE_HZ, ACLK_MULTIPLIER);
+  
+       // Disable FLL loop control
+//     __bis_SR_register(SCG0);
+#endif
+       // setup for quick wake up from interrupt and
+       // minimal power consumption in sleep mode
+       DISABLE_SVSL();                         // SVS Low side is turned off
+       DISABLE_SVSL_RESET();
+  
+       DISABLE_SVML();                         // Monitor low side is turned off
+       DISABLE_SVML_INTERRUPT();
+  
+       DISABLE_SVMH();                         // Monitor high side is turned off
+       DISABLE_SVMH_INTERRUPT();
+  
+       ENABLE_SVSH();                          // SVS High side is turned on
+       ENABLE_SVSH_RESET();                    // Enable POR on SVS Event
+
+       SVSH_ENABLED_IN_LPM_FULL_PERF();        // SVS high side Full perf mode,
+                                               // stays on in LPM3,enhanced protect
+       SVSL_ENABLED_IN_LPM_FAST_WAKE();
+
+       // Wait until high side, low side settled
+       while ((PMMIFG & SVSMLDLYIFG) == 0 && (PMMIFG & SVSMHDLYIFG) == 0)
+               nop();
+       CLEAR_PMM_IFGS();
+
+       while (PMM15Check());
+
+       // Errata PMM17
+       if (DetermineErrata()) {
+               *(unsigned int*)(0x0110) = 0x9602;
+               *(unsigned int*)(0x0112) |= 0x0800;
+       }
 
        /* enable oscillator fault NMI IRQ */
 //     SFRIE1 = OFIE;
@@ -111,7 +213,8 @@ static void setup_pins(void)
        DISABLE_LCD_LED();              // frontlight
        CONFIG_DEBUG_PINS();
        CONFIG_ACCELEROMETER_PINS();
-       // DISABLE_ACCELEROMETER_POWER(); // there is no accel. power switching!
+       //DISABLE_ACCELEROMETER_POWER(); // starts from config 5 and later
+       ENABLE_ACCELEROMETER_POWER(); // starts from config 5 and later
 
        HARDWARE_CFG_SENSE_INIT();
 
@@ -119,9 +222,12 @@ static void setup_pins(void)
        APPLE_POWER_DISABLE();
 
        CONFIG_BT_PINS();
-       BT_CLK_REQ_CONFIG_AS_OUTPUT_LOW();
-       BT_IO1_CONFIG_AS_OUTPUT_LOW();
-       BT_IO2_CONFIG_AS_OUTPUT_LOW();
+//     BT_CLK_REQ_CONFIG_AS_OUTPUT_LOW();
+//     BT_IO1_CONFIG_AS_OUTPUT_LOW();
+//     BT_IO2_CONFIG_AS_OUTPUT_LOW();
+       BT_CLK_REQ_CONFIG_AS_INPUT();
+       BT_IO1_CONFIG_AS_INPUT();
+       BT_IO2_CONFIG_AS_INPUT();
        mw_disable_bt();
 
        LIGHT_SENSE_INIT();
@@ -141,6 +247,20 @@ static void setup_pins(void)
 #ifndef MW_DEVBOARD_V2 // but only on real watch
        SFRRPCR &= ~SYSRSTRE;
        SFRRPCR |= SYSNMI;
+#endif
+       /* allow debug UART */
+/*
+       P10SEL &= ~(BIT6 | BIT7);
+       P10DIR |= BIT6 | BIT7;
+       P10OUT &= ~(BIT6 | BIT7);
+*/
+#ifndef MW_DEVBOARD_V2
+       ENABLE_MUX_OUTPUT_CONTROL();
+#ifdef MW_DEBUG_UART
+       MUX_OUTPUT_SELECTS_SERIAL();
+#else
+       MUX_OUTPUT_OFF();
+#endif
 #endif
 }
 
@@ -182,16 +302,22 @@ __interrupt void RTC_ISR (void)
 {
        switch (RTCIV) {
                case RTCIV_NONE:
+                       debug_uart_tx("RTC none IRQ\n");
                        break;
                case RTCIV_RTCRDYIFG:
                case RTCIV_RTCTEVIFG:
                case RTCIV_RTCAIFG:
                case RTCIV_RT0PSIFG:
+                       debug_uart_tx("RTC misc IRQ\n");
                        break;
                case RTCIV_RT1PSIFG:
                        RTCPS1CTL &= ~RT1PSIFG;
                        _event_src |= RTC_1HZ_EVENT;
-                       LPM3_EXIT;
+                       // LPM3_EXIT;
+                       LPM3_EXIT_ISR();
+#if defined MW_DEVBOARD_V2
+                       LED7_TOGGLE();
+#endif
                        break;
                default:
                        break;
@@ -238,13 +364,12 @@ void setup_rtc(void)
        nop();
 }
 
-#if defined MW_DEVBOARD_V2
+#if defined MW_DEVBOARD_V2 || MW_DEBUG_UART
 static void dbg_out_rtc(void)
 {
        char clk_str[16];
        snprintf(clk_str, 16, "%02d:%02d.%02d %d\n", RTCHOUR, RTCMIN, RTCSEC, RTCDOW);
        debug_uart_tx(clk_str);
-       // bt_l2cap_send_channel(0x40, clk_str, strlen(clk_str));
 }
 #endif
 
@@ -315,7 +440,7 @@ static void handle_bt_uart_rx_event(void)
        *rp = (*rp + len) % BT_RX_MAX_SIZE;
 }
 
-#if defined MW_DEVBOARD_V2
+#if defined MW_DEVBOARD_V2 || MW_DEBUG_UART
 static void handle_uart_rx_event(void)
 {
        char c;
@@ -324,7 +449,24 @@ static void handle_uart_rx_event(void)
 
        if (debug_uart_rx_char(&c)) {
                debug_uart_tx_char(c);
-               if (c == 'b') {
+               if (c == 'a') {
+                       debug_uart_tx("\nenabling ACC\n");
+                       mw_acc_enable();
+               } else if (c == 'A') {
+                       debug_uart_tx("\ndisabling ACC\n");
+                       mw_acc_disable();
+               } else if (c == 'r') {
+                       int16_t x,y,z;
+                       debug_uart_tx("\nread ACC: ");
+                       mw_acc_read(&x, &y, &z);
+                       snprintf(tstr, 64, "x:%d y:%d z:%d\n", x,y,z);
+                       debug_uart_tx(tstr);
+               } else if (c =='R') {
+                       int16_t al;
+                       al = mw_get_amblight_adc_val();
+                       snprintf(tstr, 64, "light: %d\n", al);
+                       debug_uart_tx(tstr);
+               } else if (c == 'b') {
                        debug_uart_tx("\nenabling BT\n");
                        mw_enable_bt();
                } else if (c == 'B') {
@@ -374,13 +516,6 @@ static void handle_uart_rx_event(void)
                        nop();
                } else if (c == '-') {
                        nop();
-               } else if (c == 't') {
-                       int i;
-                       debug_uart_tx("cc256x ini content:\n");
-                       for (i=0; i<16; i++) {
-                               snprintf(tstr, 16, "0x%04x 0x%02x\n", i, cc256x_init_script[i]);
-                               debug_uart_tx(tstr);
-                       }
                } else if (c == 'H') {
                        uint8_t dclass[3];
                        dclass[0] = BT_MW_DEVICE_CLASS & 0xff;
@@ -390,6 +525,20 @@ static void handle_uart_rx_event(void)
                        debug_uart_tx("HCI reset\n");
                        bt_hci_cmd(HCI_HC_BB_OGF, HCI_RESET_OCF, 0, NULL);
                        bt_hci_cmd(HCI_HC_BB_OGF, HCI_W_COD_OCF, 3, dclass);
+               } else if (c == 'i') {
+                       debug_uart_tx("Information:\n");
+                       debug_uart_tx("Oswald ");
+                       debug_uart_tx(MW_MAIN_VERSION);
+                       debug_uart_tx("\n");
+                       debug_uart_tx("Build #");
+                       debug_uart_tx(BUILDNO);
+                       debug_uart_tx("\n");
+                       debug_uart_tx("BT V ");
+                       debug_uart_tx(cc256x_version);
+                       debug_uart_tx("\n");
+                       debug_uart_tx("MCU Rev ");
+                       debug_uart_tx_char(GetMsp430HardwareRevision());
+                       debug_uart_tx("\n");
                } else if (c == 'S') {
                        debug_uart_tx("Scan enable\n");
                        tstr[0] = HCI_BB_SCAN_INQUIRY | HCI_BB_SCAN_PAGE;
@@ -423,16 +572,16 @@ static void handle_uart_rx_event(void)
 void start_timer(int cycles)
 {
        TA0EX0 = TAIDEX_0;
-       TA0CTL = TASSEL_1 | TACLR | MC__STOP;              // SMCLK, clear TAR
-       TA0CCTL0 = CCIE;                         // CCR0 interrupt enabled
+       TA0CTL = TASSEL_1 | TACLR | MC__STOP;   // SMCLK, clear TAR
+       TA0CCTL0 = CCIE;                        // CCR0 interrupt enabled
        TA0CCR0 = cycles;
-       TA0CTL |= MC_1;                         // Start Timer_A in continuous mode
+       TA0CTL |= MC_1;                         // Start Timer_A in continuous mode
 }
 
 void stop_timer(void)
 {
-       TA0CCTL0 &= ~CCIE;                         // CCR0 interrupt enabled
-       TA0CTL = MC__STOP;                         // Start Timer_A in continuous mode
+       TA0CCTL0 &= ~CCIE;                      // CCR0 interrupt enabled
+       TA0CTL = MC__STOP;                      // Start Timer_A in continuous mode
 }
  
 // Timer A0 interrupt service routine
@@ -444,12 +593,13 @@ __interrupt void TIMER0_A0_ISR (void)
        LED6_TOGGLE();
 #endif
        _event_src |= TIMER_500MS_EVENT | TIMER_100MS_EVENT;
-       LPM3_EXIT;
+       // LPM3_EXIT;
+       LPM3_EXIT_ISR();
 }
 
 uint8_t handle_event(void)
 {
-#if defined MW_DEVBOARD_V2
+#if defined MW_DEVBOARD_V2 || MW_DEBUG_UART
        char tstr[64];
 #endif
        if (_event_src == 0)
@@ -463,16 +613,18 @@ uint8_t handle_event(void)
                        _event_src &= ~RTC_1HZ_EVENT;
                        check_pwr_state();
                        oswald_one_second_tick();
-#if defined MW_DEVBOARD_V2
+#if defined MW_DEVBOARD_V2 || MW_DEBUG_UART
                        dbg_out_rtc();
-                       LED7_TOGGLE();
 #endif
                } else if (_event_src & BT_UART_RCV_EVENT) {
                        _event_src &= ~BT_UART_RCV_EVENT;
                        handle_bt_uart_rx_event();
+               } else if (_event_src & BT_UART_WAKEUP_EVENT) {
+                       _event_src &= ~BT_UART_WAKEUP_EVENT;
+                       bt_hci_ehcill_wake();
                } else if (_event_src & DBG_UART_RCV_EVENT) {
                        _event_src &= ~DBG_UART_RCV_EVENT;
-#if defined MW_DEVBOARD_V2
+#if defined MW_DEVBOARD_V2 || MW_DEBUG_UART
                        handle_uart_rx_event();
 #endif
                } else if (_event_src & BUTTON_EVENT) {
@@ -484,8 +636,11 @@ uint8_t handle_event(void)
                } else if (_event_src & TIMER_100MS_EVENT) {
                        _event_src &= ~TIMER_100MS_EVENT;
                        oswald_centisecond_tick();
+               } else if (_event_src & ACCEL_EVENT) {
+                       _event_src &= ~ACCEL_EVENT;
+                       mw_acc_handle_irq();
                } else {
-#if defined MW_DEVBOARD_V2
+#if defined MW_DEVBOARD_V2 || MW_DEBUG_UART
                        snprintf(tstr, 64, "unhandled event in 0x%04x\n", _event_src);
                        debug_uart_tx(tstr);
 #endif
@@ -497,13 +652,35 @@ uint8_t handle_event(void)
 #pragma vector=BUTTON_PORT_VECTOR
 __interrupt void BUTTON_ISR (void)
 {
+       // LPM3_EXIT;
+       LPM3_EXIT_ISR();
        BUTTON_PORT_IFG &= ~ALL_BUTTONS;
        // BUTTON_PORT_IE  &= ~INT_EDGE_SEL_BUTTONS;
        _event_src |= BUTTON_EVENT;
        //_button_state = (BUTTON_PORT_IN & ALL_BUTTONS);
-       LPM3_EXIT;
 }
 
+#pragma vector=PORT1_VECTOR
+__interrupt void PORT1_GPIO_ISR (void)
+{
+       if (P1IFG & BT_IO_CTS) {
+               //LPM3_EXIT;
+               LPM3_EXIT_ISR();
+               P1IE &= ~BT_IO_CTS;
+               P1IFG &= ~BT_IO_CTS;
+               debug_uart_tx("BT CTS irq\n");
+               _event_src |= BT_UART_WAKEUP_EVENT;
+               // bt_hci_ehcill_wake();
+       } else if (P1IFG & ACCELEROMETER_INT_PIN) {
+               //LPM3_EXIT;
+               LPM3_EXIT_ISR();
+               P1IFG &= ~ACCELEROMETER_INT_PIN;
+               // debug_uart_tx("ACC irq\n");
+               _event_src |= ACCEL_EVENT;
+       }
+}
+
+
 #if 0
 #pragma vector=NOVECTOR
 __interrupt void UNEXP_ISR (void)
@@ -515,17 +692,15 @@ __interrupt void UNEXP_ISR (void)
 
 int main(void)
 {
-       int idle = 0;
-
        setup_wdt();
        setup_pins();
        setup_clocks();
        setup_rtc();
 
        /* enable interrupts, we will need them! */
-       __eint();
+       __enable_interrupt();
 
-#if defined MW_DEVBOARD_V2
+#if defined MW_DEVBOARD_V2 || MW_DEBUG_UART
        init_debug_uart();
        debug_uart_tx("\nOswald on MetaWatch\n");
 #endif
@@ -537,32 +712,25 @@ int main(void)
        mw_init_adc();
        mw_init_vibrate_pwm();
 
-#if 0
-       RTCYEAR = (unsigned int) 2013;
-       RTCMON = (unsigned int) 1;
-       RTCDAY = (unsigned int) 1;
-       RTCDOW = (unsigned int) 2;
-       RTCHOUR = (unsigned int) 01;
-       RTCMIN = (unsigned int) 0;
-       RTCSEC = (unsigned int) 0;
-#endif
-
        oswald_set_time(RTCHOUR, RTCMIN, RTCSEC, TRUE);
        oswald_set_date(RTCDAY, RTCMON, RTCYEAR, TRUE);
        oswald_init();
 
        while (1) {
                /* handle pending events */
-               if (handle_event())
-                       idle++;
-               else
-                       idle = 0;
+               handle_event();
 
                /* enter LPM3 sleep mode waiting for interrupt */
-               if (idle > 100) {
-                       idle = 0;
-                       // debug_uart_tx("z");
-                       LPM3;
+               /* errata PMM11 + PMM12 - divide MCLK before going to sleep */
+               if (DetermineErrata()) {
+                       MCLK_DIV(2);
+                       nop();
+               }
+               LPM3;
+               nop();
+               if (DetermineErrata()) {
+                       __delay_cycles(100);
+                       MCLK_DIV(1);
                }
        };