From 81da03661f51061203889cb115142217230d6a76 Mon Sep 17 00:00:00 2001 From: Nils Faerber Date: Sat, 6 Jul 2013 23:19:55 +0200 Subject: [PATCH] Add modified LPM3_EXIT_ISR to work around FLL IRQ wake-up problem --- metawatch/mw_bt.c | 85 +++++++++++++++++++++++-------- metawatch/mw_bt.h | 9 ++-- metawatch/mw_main.c | 119 +++++++++++++++++++++++++++++++++++++------- metawatch/mw_main.h | 1 + 4 files changed, 169 insertions(+), 45 deletions(-) diff --git a/metawatch/mw_bt.c b/metawatch/mw_bt.c index d5c7d26..ace18e9 100644 --- a/metawatch/mw_bt.c +++ b/metawatch/mw_bt.c @@ -58,15 +58,17 @@ __interrupt void UCA1_ISR (void) if (UCA1STAT & UCRXERR) { debug_uart_tx("BT UART RXERR: "); if (UCA1STAT & UCOE) - debug_uart_tx("overrun\n"); + debug_uart_tx("overrun "); if (UCA1STAT & UCPE) - debug_uart_tx("parity err\n"); + debug_uart_tx("parity err "); if (UCA1STAT & UCFE) - debug_uart_tx("frm-err\n"); + debug_uart_tx("frm-err "); + debug_uart_tx("\n"); } bt_rx_buf[bt_rx_buf_wpos++] = UCA1RXBUF; bt_rx_buf_wpos %= BT_RX_MAX_SIZE; - LPM3_EXIT; + // LPM3_EXIT; + LPM3_EXIT_ISR(); _event_src |= BT_UART_RCV_EVENT; break; case 4: // TXIFG @@ -96,9 +98,10 @@ void mw_init_bt_uart(const bt_uart_baud_t baud) //UCA1CTL0 |= UCRXEIE; UCA1CTL1 &= ~UCSWRST; + /* clear interrup flags */ - UCA1IE = UCRXIE; UCA1IFG = 0; + UCA1IE = UCRXIE; } #if 0 // Does never finish, presumably trigger does not trigger, unknown :( @@ -121,17 +124,23 @@ void mw_bt_uart_tx(const void *buf, const unsigned int len) nop(); } #else -void mw_bt_uart_tx(const void *buf, const unsigned int len) +int mw_bt_uart_tx(const void *buf, const unsigned int len) { - unsigned int pos; + unsigned int pos, i; // char txstr[8]; pos = 0; // debug_uart_tx("BT tx: "); while (pos < len) { - // wait for CTS to go low - while ((BT_IO_PIN & BT_IO_CTS)) - nop(); + // watch for CTS to be low + i = 0; + while ((BT_IO_PIN & BT_IO_CTS) && (i < 1000)) { + __delay_cycles(16000); + i++; + if (i >= 1000) + return -1; + // nop(); + } // do not start a transfer if UART is busy, e.g. rx-ing while (UCA1STAT & UCBUSY) @@ -147,25 +156,31 @@ void mw_bt_uart_tx(const void *buf, const unsigned int len) } while (UCA1STAT & UCBUSY) nop(); + + return len; } #endif -static void load_cc256x_init_script(void) +static int load_cc256x_init_script(void) { uint32_t pos; unsigned char *tptr; + int tlen; pos = 0; while (pos < cc256x_init_script_size) { if (_event_src != 0) handle_event(); tptr = (unsigned char *)(cc256x_init_script + pos); - mw_bt_uart_tx(tptr, 4 + tptr[3]); - pos += 4 + tptr[3]; + tlen = mw_bt_uart_tx(tptr, 4 + tptr[3]); + if (tlen < 0) + return -1; + pos += tlen /*4 + tptr[3]*/; // each init script part is one HCI command so wait for reply if (_event_src != 0) handle_event(); } + return 0; } void mw_enable_bt(void) @@ -174,6 +189,7 @@ void mw_enable_bt(void) /* make sure it resets */ BT_SHUTDOWN(); + __delay_cycles(16000); /* enable 32kHz ACLK output to BT module */ P11DIR |= BIT0; @@ -182,11 +198,19 @@ void mw_enable_bt(void) // wait for clock to stabilize __delay_cycles(16000); + // disable the IRQ on CTS, later used to get a wakeup IRQ from eHCILL + // will be enabled when going to sleep + P1IE &= ~BT_IO_CTS; + P1IES &= ~BT_IO_CTS; + BT_IO_PDIR &= ~(BT_IO_CTS | BT_IO_PIN1 | BT_IO_PIN2 | BT_IO_CLKREQ); BT_IO_PDIR |= BT_IO_RTS; + BT_IO_POUT &= ~(BT_IO_CTS | BT_IO_PIN1 | BT_IO_PIN2 | BT_IO_CLKREQ); BT_IO_POUT &= ~BT_IO_RTS; // low == ready, high == !ready + BT_IO_REN |= BT_IO_CTS; // enable pull-down on CTS, POUT-CTS is 0 already + /* setup UART pins */ BT_UART_PSEL |= BT_UART_TX_PIN | BT_UART_RX_PIN; // P5OUT |= BT_UART_TX_PIN | BT_UART_RX_PIN; @@ -207,28 +231,45 @@ void mw_enable_bt(void) } if (i>=1000) { debug_uart_tx("Timeout waiting for CC256x to lower CTS\n"); + mw_bt_enabled = 0; } else { debug_uart_tx("CC256x CTS low - uploading init\n"); - for (i=0; i<100; i++) { - __delay_cycles(16000); // give it some more before anyone sends data + + // the init script consists of HCI cmds so HCI must be setup before + bt_hci_init(); + + // give it some more time before anyone sends data + for (i=0; i<10; i++) { + __delay_cycles(16000); + } + if (load_cc256x_init_script() < 0) { + debug_uart_tx("init upload failed!\n"); + return; } - load_cc256x_init_script(); + + __delay_cycles(32000); + debug_uart_tx("init uploaded\n"); - } - P1IE &= ~BT_IO_CTS; - P1IES &= ~BT_IO_CTS; + init_l2cap(); - bt_hci_init(); - init_l2cap(); + if (_event_src != 0) + handle_event(); - mw_bt_enabled = 1; + mw_bt_enabled = 1; + } } void mw_disable_bt(void) { mw_bt_enabled = 0; + // disable the IRQ on CTS + P1IE &= ~BT_IO_CTS; + P1IES &= ~BT_IO_CTS; + // BT_IO_REN &= ~BT_IO_CTS; // disable pull-down on CTS + P1IFG &= ~BT_IO_CTS; + /* disable UART RX interrupt */ UCA1IE &= ~UCRXIE; diff --git a/metawatch/mw_bt.h b/metawatch/mw_bt.h index 1569ae4..913a9ef 100644 --- a/metawatch/mw_bt.h +++ b/metawatch/mw_bt.h @@ -12,17 +12,18 @@ #define BT_IO_POUT P1OUT #define BT_IO_PIN P1IN #define BT_IO_PDIR P1DIR +#define BT_IO_REN P1REN #define BT_IO_PIN1 BIT5 #define BT_IO_PIN2 BIT6 -#define BT_IO_CLKREQ BIT4 +#define BT_IO_CLKREQ BIT4 #define BT_SHUTDOWN() { BT_RST_POUT &= ~BT_RST_PIN; } -#define BT_ENABLE() { BT_RST_POUT |= BT_RST_PIN; } +#define BT_ENABLE() { BT_RST_POUT |= BT_RST_PIN; } #define BT_UART_PSEL P5SEL #define BT_UART_PDIR P5DIR -#define BT_UART_REN P5REN +#define BT_UART_REN P5REN #define BT_UART_POUT P5OUT #define BT_UART_TX_PIN BIT6 #define BT_UART_RX_PIN BIT7 @@ -56,7 +57,7 @@ typedef enum { void mw_init_bt_uart(const bt_uart_baud_t baud); -void mw_bt_uart_tx(const void *buf, const unsigned int len); +int mw_bt_uart_tx(const void *buf, const unsigned int len); // extern char BT_UART_RX_CHAR; int mw_bt_get_rxbuf_len(void); diff --git a/metawatch/mw_main.c b/metawatch/mw_main.c index 4ba6c54..07f8ba5 100644 --- a/metawatch/mw_main.c +++ b/metawatch/mw_main.c @@ -20,24 +20,26 @@ #include "oswald_main.h" #include "oswald_hal.h" +#include "bluetooth_init_cc256x.h" uint16_t _event_src = 0; #define HARDWARE_REVISION_ADDRESS (0x1a07) -unsigned char GetMsp430HardwareRevision(void) +uint8_t GetMsp430HardwareRevision(void) { - unsigned char *pDeviceType = (unsigned char *)(unsigned char *)HARDWARE_REVISION_ADDRESS; + uint8_t *pDeviceType = (uint8_t *)(uint8_t *)HARDWARE_REVISION_ADDRESS; return pDeviceType[0]+'1'; } uint8_t DetermineErrata(void) { - unsigned char Revision = GetMsp430HardwareRevision(); + uint8_t Revision = GetMsp430HardwareRevision(); switch (Revision) { case 'F': + case 'G': case 'H': return 0; break; @@ -67,6 +69,31 @@ 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; @@ -75,6 +102,8 @@ static void setup_clocks(void) /* use external oscillator */ P7SEL |= BIT0 + BIT1; + +#if 1 if ((UCSCTL6 & XT1DRIVE_3) != XT1DRIVE_3) { UCSCTL6_L |= XT1DRIVE1_L + XT1DRIVE0_L; } @@ -88,7 +117,21 @@ 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 @@ -105,12 +148,15 @@ static void setup_clocks(void) 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; @@ -176,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(); @@ -198,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 } @@ -250,8 +313,8 @@ __interrupt void RTC_ISR (void) case RTCIV_RT1PSIFG: RTCPS1CTL &= ~RT1PSIFG; _event_src |= RTC_1HZ_EVENT; - LPM3_EXIT; - nop(); + // LPM3_EXIT; + LPM3_EXIT_ISR(); #if defined MW_DEVBOARD_V2 LED7_TOGGLE(); #endif @@ -301,7 +364,7 @@ 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]; @@ -377,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; @@ -462,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; @@ -516,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) @@ -535,7 +613,7 @@ 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(); #endif } else if (_event_src & BT_UART_RCV_EVENT) { @@ -546,7 +624,7 @@ uint8_t handle_event(void) 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) { @@ -562,7 +640,7 @@ uint8_t handle_event(void) _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 @@ -574,7 +652,8 @@ uint8_t handle_event(void) #pragma vector=BUTTON_PORT_VECTOR __interrupt void BUTTON_ISR (void) { - LPM3_EXIT; + // LPM3_EXIT; + LPM3_EXIT_ISR(); BUTTON_PORT_IFG &= ~ALL_BUTTONS; // BUTTON_PORT_IE &= ~INT_EDGE_SEL_BUTTONS; _event_src |= BUTTON_EVENT; @@ -585,14 +664,16 @@ __interrupt void BUTTON_ISR (void) __interrupt void PORT1_GPIO_ISR (void) { if (P1IFG & BT_IO_CTS) { - LPM3_EXIT; + //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; + LPM3_EXIT_ISR(); P1IFG &= ~ACCELEROMETER_INT_PIN; // debug_uart_tx("ACC irq\n"); _event_src |= ACCEL_EVENT; @@ -619,7 +700,7 @@ int main(void) /* enable interrupts, we will need them! */ __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 diff --git a/metawatch/mw_main.h b/metawatch/mw_main.h index f3e5db9..8d02f7d 100644 --- a/metawatch/mw_main.h +++ b/metawatch/mw_main.h @@ -12,6 +12,7 @@ #endif #include "hal_io_macros.h" +#define LPM3_EXIT_ISR() { _BIC_SR_IRQ(SCG1+OSCOFF+CPUOFF); nop(); } #define WATCHDOG_EVENT 1 << 0 #define RTC_1HZ_EVENT 1 << 1 -- 2.39.2