2 #include <msp430xgeneric.h>
6 #include "F5xx_F6xx_Core_Lib/HAL_PMM.h"
7 #include "F5xx_F6xx_Core_Lib/HAL_UCS.h"
20 #include "oswald_main.h"
21 #include "oswald_hal.h"
23 #include "bluetooth_init_cc256x.h"
25 uint16_t _event_src = 0;
27 #define HARDWARE_REVISION_ADDRESS (0x1a07)
29 uint8_t GetMsp430HardwareRevision(void)
31 uint8_t *pDeviceType = (uint8_t *)(uint8_t *)HARDWARE_REVISION_ADDRESS;
33 return pDeviceType[0]+'1';
36 uint8_t DetermineErrata(void)
38 uint8_t Revision = GetMsp430HardwareRevision();
52 static void set16mhz(void)
54 UCSCTL0 = 0x00; // Set lowest possible DCOx, MODx
55 UCSCTL1 = DCORSEL_5; // Select suitable range
56 UCSCTL2 = 488 + FLLD_1; // Set DCO Multiplier
57 UCSCTL4 = SELA__XT1CLK | SELS__DCOCLKDIV | SELM__DCOCLKDIV ;
59 // Worst-case settling time for the DCO when the DCO range bits have been
60 // changed is n x 32 x 32 x f_FLL_reference. See UCS chapter in 5xx UG
62 // 32 x 32 x / f_FLL_reference (32,768 Hz) = .03125 = t_DCO_settle
63 // t_DCO_settle / (1 / 18 MHz) = 562500 = counts_DCO_settle
65 // __delay_cycles(562500);
68 __delay_cycles(56250);
72 static unsigned char PMM15Check(void)
74 // First check if SVSL/SVML is configured for fast wake-up
75 if ((!(SVSMLCTL & SVSLE)) || ((SVSMLCTL & SVSLE) && (SVSMLCTL & SVSLFP)) ||
76 (!(SVSMLCTL & SVMLE)) || ((SVSMLCTL & SVMLE) && (SVSMLCTL & SVMLFP)))
78 // Next Check SVSH/SVMH settings to see if settings are affected by PMM15
79 if ((SVSMHCTL & SVSHE) && (!(SVSMHCTL & SVSHFP)))
81 if ( (!(SVSMHCTL & SVSHMD)) ||
82 ((SVSMHCTL & SVSHMD) && (SVSMHCTL & SVSMHACE)) )
83 return 1; // SVSH affected configurations
86 if ((SVSMHCTL & SVMHE) && (!(SVSMHCTL & SVMHFP)) && (SVSMHCTL & SVSMHACE))
87 return 1; // SVMH affected configurations
90 return 0; // SVS/M settings not affected by PMM15
93 #define configCPU_CLOCK_HZ ((unsigned long) 16777216) /* 512*32768 */
94 #define configTICK_RATE_HZ ((unsigned int)1024)
95 #define ACLK_MULTIPLIER ((unsigned int)512)
97 static void setup_clocks(void)
101 SetVCore(PMMCOREV_2);
103 /* use external oscillator */
104 P7SEL |= BIT0 + BIT1;
107 if ((UCSCTL6 & XT1DRIVE_3) != XT1DRIVE_3) {
108 UCSCTL6_L |= XT1DRIVE1_L + XT1DRIVE0_L;
111 while ((SFRIFG1 & OFIFG) && i--) {
112 UCSCTL7 &= ~(DCOFFG + XT1LFOFFG + XT1HFOFFG + XT2OFFG);
115 UCSCTL6 = (UCSCTL6 & ~(XT1DRIVE_3)) |(XT1DRIVE_0);
119 UCSCTL8 |= SMCLKREQEN;
121 // Startup LFXT1 32 kHz crystal
122 while (LFXT_Start_Timeout(XT1DRIVE_0, 50000) == UCS_STATUS_ERROR)
125 // select the sources for the FLL reference and ACLK
126 SELECT_ACLK(SELA__XT1CLK);
127 SELECT_FLLREF(SELREF__XT1CLK);
129 // 512 * 32768 = 16777216 / 1024
130 Init_FLL_Settle(configCPU_CLOCK_HZ/configTICK_RATE_HZ, ACLK_MULTIPLIER);
132 // Disable FLL loop control
133 // __bis_SR_register(SCG0);
135 // setup for quick wake up from interrupt and
136 // minimal power consumption in sleep mode
137 DISABLE_SVSL(); // SVS Low side is turned off
138 DISABLE_SVSL_RESET();
140 DISABLE_SVML(); // Monitor low side is turned off
141 DISABLE_SVML_INTERRUPT();
143 DISABLE_SVMH(); // Monitor high side is turned off
144 DISABLE_SVMH_INTERRUPT();
146 ENABLE_SVSH(); // SVS High side is turned on
147 ENABLE_SVSH_RESET(); // Enable POR on SVS Event
149 SVSH_ENABLED_IN_LPM_FULL_PERF(); // SVS high side Full perf mode,
150 // stays on in LPM3,enhanced protect
151 SVSL_ENABLED_IN_LPM_FAST_WAKE();
153 // Wait until high side, low side settled
154 while ((PMMIFG & SVSMLDLYIFG) == 0 && (PMMIFG & SVSMHDLYIFG) == 0)
158 while (PMM15Check());
161 if (DetermineErrata()) {
162 *(unsigned int*)(0x0110) = 0x9602;
163 *(unsigned int*)(0x0112) |= 0x0800;
166 /* enable oscillator fault NMI IRQ */
171 #pragma vector=PWR_PORT_VECTOR
172 __interrupt void PWR_ISR (void)
174 /* clear all possible sources */
175 PWR_PORT_IFG &= ~(BAT_CHARGE_STAT1 | BAT_CHARGE_STAT2 | BAT_CHARGE_PWR_BIT);
176 _event_src |= POWER_SRC_EVENT;
182 static void mw_init_vibrate_pwm(void)
185 // Start with P7.3 as an output
186 P7OUT &= ~BIT3; // Low when a digital output
187 P7SEL &= ~BIT3; // P7 option select = false
188 P7DIR |= BIT3; // P7 outputs
192 // No expansion divide
195 // do a PWM with 64 total steps. This gives a count up of 32 and
196 // a count down of 32
199 // Compare channel 2 is used as output
200 TA1CCTL2 = OUTMOD_6; // PWM output mode: 6 - toggle/set
201 TA1CCR2 = 10; // 10 is a 2/3 duty cycle
206 static void setup_pins(void)
209 CONFIGURE_BUTTON_PINS();
210 #ifdef MW_DEVBOARD_V2
211 CONFIG_LED_PINS(); // debug LEDs on devboard
213 DISABLE_LCD_LED(); // frontlight
215 CONFIG_ACCELEROMETER_PINS();
216 //DISABLE_ACCELEROMETER_POWER(); // starts from config 5 and later
217 ENABLE_ACCELEROMETER_POWER(); // starts from config 5 and later
219 HARDWARE_CFG_SENSE_INIT();
222 APPLE_POWER_DISABLE();
225 // BT_CLK_REQ_CONFIG_AS_OUTPUT_LOW();
226 // BT_IO1_CONFIG_AS_OUTPUT_LOW();
227 // BT_IO2_CONFIG_AS_OUTPUT_LOW();
228 BT_CLK_REQ_CONFIG_AS_INPUT();
229 BT_IO1_CONFIG_AS_INPUT();
230 BT_IO2_CONFIG_AS_INPUT();
234 LIGHT_SENSOR_SHUTDOWN();
236 BATTERY_SENSE_INIT();
237 BATTERY_SENSE_DISABLE();
238 BAT_CHARGE_DIR &= ~(BAT_CHARGE_STAT1 | BAT_CHARGE_STAT2 | BAT_CHARGE_PWR_BIT);
239 BAT_CHARGE_OUT |= BAT_CHARGE_PWR_BIT | BAT_CHARGE_STAT1 | BAT_CHARGE_STAT2; // pull-up
240 BAT_CHARGE_REN |= BAT_CHARGE_PWR_BIT; // enable resistors
241 // BAT_CHARGE_IE |= BAT_CHARGE_PWR_BIT;
242 BAT_CHARGE_OUT |= BAT_CHARGE_ENABLE_PIN; // !CE, negative logic
243 BAT_CHARGE_DIR |= BAT_CHARGE_ENABLE_PIN;
245 /* disable reset function, enable NMI, do not enable NMI IRQ */
246 /* to avoid accidential reset on charger clip connect */
247 #ifndef MW_DEVBOARD_V2 // but only on real watch
248 SFRRPCR &= ~SYSRSTRE;
251 /* allow debug UART */
253 P10SEL &= ~(BIT6 | BIT7);
254 P10DIR |= BIT6 | BIT7;
255 P10OUT &= ~(BIT6 | BIT7);
257 #ifndef MW_DEVBOARD_V2
258 ENABLE_MUX_OUTPUT_CONTROL();
260 MUX_OUTPUT_SELECTS_SERIAL();
267 #pragma vector=WDT_VECTOR
268 __interrupt void WDT_ISR (void)
270 /* eventually we will do something here, not for now */
271 _event_src |= WATCHDOG_EVENT;
275 static void setup_wdt(void)
278 WDTCTL = WDTPW + WDTHOLD; // disable watchdog
280 WDTCTL = WDT_ADLY_1000; // 1 second timeout
281 SFRIE1 |= WDTIE; // Enable WDT interrupt
286 #pragma vector=UNMI_VECTOR
287 __interrupt void NMI_ISR (void)
289 #if defined MW_DEVBOARD_V2
291 debug_uart_tx_char('n');
293 while ((SFRIFG1 & OFIFG)) {
294 UCSCTL7 &= ~(DCOFFG + XT1LFOFFG + XT1HFOFFG + XT2OFFG);
300 #pragma vector=RTC_VECTOR
301 __interrupt void RTC_ISR (void)
305 debug_uart_tx("RTC none IRQ\n");
307 case RTCIV_RTCRDYIFG:
308 case RTCIV_RTCTEVIFG:
311 debug_uart_tx("RTC misc IRQ\n");
314 RTCPS1CTL &= ~RT1PSIFG;
315 _event_src |= RTC_1HZ_EVENT;
318 #if defined MW_DEVBOARD_V2
333 RTCCTL2 = 0x00 & 0x3f;
336 // Set the counter for RTC mode
339 // set 128 Hz rate for prescale 0 interrupt
340 RTCPS0CTL |= RT0IP_7;
342 // enable 1 pulse per second interrupt using prescale 1
343 RTCPS1CTL |= RT1IP_6 | RT1PSIE;
345 // 1 Hz calibration output
346 RTCCTL23 |= RTCCALF_3;
348 // setting the peripheral selection bit makes the other I/O control a don't care
349 // P2.4 = 1 Hz RTC calibration output
350 // Direction needs to be set as output
351 RTC_1HZ_PORT_SEL |= RTC_1HZ_BIT;
352 RTC_1HZ_PORT_DIR |= RTC_1HZ_BIT;
354 RTCYEAR = (unsigned int) 2013;
355 RTCMON = (unsigned int) 1;
356 RTCDAY = (unsigned int) 1;
357 RTCDOW = (unsigned int) 2;
358 RTCHOUR = (unsigned int) 01;
359 RTCMIN = (unsigned int) 0;
360 RTCSEC = (unsigned int) 0;
363 RTCCTL01 &= ~RTCHOLD;
367 #if defined MW_DEVBOARD_V2 || MW_DEBUG_UART
368 static void dbg_out_rtc(void)
371 snprintf(clk_str, 16, "%02d:%02d.%02d %d\n", RTCHOUR, RTCMIN, RTCSEC, RTCDOW);
372 debug_uart_tx(clk_str);
376 static void handle_button_event(void)
378 unsigned char _button_state = 0;
381 snprintf(clk_str, 16, "0x%02x\n", _button_state);
382 debug_uart_tx(clk_str);
384 while (_button_state != (BUTTON_PORT_IN & ALL_BUTTONS)) {
385 __delay_cycles(562500);
386 _button_state = (BUTTON_PORT_IN & ALL_BUTTONS);
387 __delay_cycles(562500);
389 // BUTTON_PORT_IE |= INT_EDGE_SEL_BUTTONS;
391 if (_button_state & SW_A) {
392 debug_uart_tx("switch A\n");
393 oswald_handle_button_press(BUTTON_A);
395 if (_button_state & SW_B) {
396 debug_uart_tx("switch B\n");
397 oswald_handle_button_press(BUTTON_B);
399 if (_button_state & SW_C) {
400 debug_uart_tx("switch C\n");
401 oswald_handle_button_press(BUTTON_C);
403 if (_button_state & SW_D) {
404 debug_uart_tx("switch D\n");
405 oswald_handle_button_press(BUTTON_D);
407 if (_button_state & SW_E) {
408 debug_uart_tx("switch E\n");
409 oswald_handle_button_press(BUTTON_E);
411 if (_button_state & SW_F) {
412 debug_uart_tx("switch F\n");
413 oswald_handle_button_press(BUTTON_F);
417 void check_pwr_state(void)
419 if (BAT_CHARGE_IN & BAT_CHARGE_PWR_BIT) {
420 BAT_CHARGE_OUT |= BAT_CHARGE_ENABLE_PIN;
421 BAT_CHARGE_REN &= ~(BAT_CHARGE_STAT1 | BAT_CHARGE_STAT2); // disable pull-up
423 BAT_CHARGE_OUT &= ~BAT_CHARGE_ENABLE_PIN;
424 BAT_CHARGE_REN |= BAT_CHARGE_STAT1 | BAT_CHARGE_STAT2; // enable pull-up
428 static void handle_bt_uart_rx_event(void)
430 const unsigned char *rx;
431 unsigned char len, *rp, p;
433 rx = mw_bt_get_rx_buf(&rp, &len);
437 p += bt_feed_packet_data(rx[(*rp+p)%BT_RX_MAX_SIZE]);
440 *rp = (*rp + len) % BT_RX_MAX_SIZE;
443 #if defined MW_DEVBOARD_V2 || MW_DEBUG_UART
444 static void handle_uart_rx_event(void)
447 #ifndef CC256x_TRANSP
450 if (debug_uart_rx_char(&c)) {
451 debug_uart_tx_char(c);
453 debug_uart_tx("\nenabling ACC\n");
455 } else if (c == 'A') {
456 debug_uart_tx("\ndisabling ACC\n");
458 } else if (c == 'r') {
460 debug_uart_tx("\nread ACC: ");
461 mw_acc_read(&x, &y, &z);
462 snprintf(tstr, 64, "x:%d y:%d z:%d\n", x,y,z);
464 } else if (c =='R') {
466 al = mw_get_amblight_adc_val();
467 snprintf(tstr, 64, "light: %d\n", al);
469 } else if (c == 'b') {
470 debug_uart_tx("\nenabling BT\n");
472 } else if (c == 'B') {
473 debug_uart_tx("\ndisabling BT\n");
475 } else if (c == 'c') {
476 debug_uart_tx("\nCharger status: ");
477 snprintf(tstr, 16, "0x%04x 0x%04x ", BAT_CHARGE_IN, (BAT_CHARGE_IN & BAT_CHARGE_PWR_BIT));
479 if (BAT_CHARGE_IN & BAT_CHARGE_PWR_BIT)
480 debug_uart_tx("no ext pwr, ");
482 debug_uart_tx("ext pwr connected, ");
483 switch (BAT_CHARGE_IN & (BAT_CHARGE_STAT1 | BAT_CHARGE_STAT2)) {
484 case BAT_CHARGE_STAT1:
485 debug_uart_tx("charge done\n");
487 case BAT_CHARGE_STAT2:
488 debug_uart_tx("fast charge\n");
490 case (BAT_CHARGE_STAT1 | BAT_CHARGE_STAT2):
491 debug_uart_tx("suspend, sleep or fault\n");
494 debug_uart_tx("precharge\n");
497 if (BAT_CHARGE_IN & BAT_CHARGE_ENABLE_PIN)
498 debug_uart_tx(" !charge\n");
500 debug_uart_tx(" charge\n");
501 } else if (c == 'd') {
502 debug_uart_tx("charging disabled\n");
503 BAT_CHARGE_OUT |= BAT_CHARGE_ENABLE_PIN;
504 } else if (c == 'e') {
505 debug_uart_tx("charging enabled\n");
506 BAT_CHARGE_OUT &= ~BAT_CHARGE_ENABLE_PIN;
507 } else if (c == 'l') {
508 debug_uart_tx("backlight LED on\n");
509 hal_lcd_set_backlight(TRUE);
510 } else if (c == 'L') {
511 debug_uart_tx("backlight LED off\n");
512 hal_lcd_set_backlight(FALSE);
513 } else if (c == 'u') {
514 mw_lcd_update_screen();
515 } else if (c == '+') {
517 } else if (c == '-') {
519 } else if (c == 'H') {
521 dclass[0] = BT_MW_DEVICE_CLASS & 0xff;
522 dclass[1] = (BT_MW_DEVICE_CLASS & 0xff00) >> 8;
523 dclass[2] = (BT_MW_DEVICE_CLASS & 0xff0000) >> 16;
525 debug_uart_tx("HCI reset\n");
526 bt_hci_cmd(HCI_HC_BB_OGF, HCI_RESET_OCF, 0, NULL);
527 bt_hci_cmd(HCI_HC_BB_OGF, HCI_W_COD_OCF, 3, dclass);
528 } else if (c == 'i') {
529 debug_uart_tx("Information:\n");
530 debug_uart_tx("Oswald ");
531 debug_uart_tx(MW_MAIN_VERSION);
533 debug_uart_tx("Build #");
534 debug_uart_tx(BUILDNO);
536 debug_uart_tx("BT V ");
537 debug_uart_tx(cc256x_version);
539 debug_uart_tx("MCU Rev ");
540 debug_uart_tx_char(GetMsp430HardwareRevision());
542 } else if (c == 'S') {
543 debug_uart_tx("Scan enable\n");
544 tstr[0] = HCI_BB_SCAN_INQUIRY | HCI_BB_SCAN_PAGE;
545 bt_hci_cmd(HCI_HC_BB_OGF, HCI_W_SCAN_EN_OCF, 1, (uint8_t *)tstr);
546 } else if (c == 'h') {
550 } else if (c == 'm') {
554 } else if (c == 'N') {
555 debug_uart_tx("Set name\n");
563 bt_hci_cmd(HCI_HC_BB_OGF, HCI_W_LOCAL_NAME_OCF, 0x07, (uint8_t *)tstr);
564 } else if (c == 'R') {
565 bt_hci_cmd(HCI_INFO_PARAM_OGF, HCI_R_BD_ADDR_OCF, 0, NULL);
572 void start_timer(int cycles)
575 TA0CTL = TASSEL_1 | TACLR | MC__STOP; // SMCLK, clear TAR
576 TA0CCTL0 = CCIE; // CCR0 interrupt enabled
578 TA0CTL |= MC_1; // Start Timer_A in continuous mode
581 void stop_timer(void)
583 TA0CCTL0 &= ~CCIE; // CCR0 interrupt enabled
584 TA0CTL = MC__STOP; // Start Timer_A in continuous mode
587 // Timer A0 interrupt service routine
588 #pragma vector=TIMER0_A0_VECTOR
589 __interrupt void TIMER0_A0_ISR (void)
592 #if defined xMW_DEVBOARD_V2
595 _event_src |= TIMER_500MS_EVENT | TIMER_100MS_EVENT;
600 uint8_t handle_event(void)
602 #if defined MW_DEVBOARD_V2 || MW_DEBUG_UART
608 while (_event_src != 0) {
609 if (_event_src & WATCHDOG_EVENT) {
610 _event_src &= ~WATCHDOG_EVENT;
611 debug_uart_tx_char('w');
612 } else if (_event_src & RTC_1HZ_EVENT) {
613 _event_src &= ~RTC_1HZ_EVENT;
615 oswald_one_second_tick();
616 #if defined MW_DEVBOARD_V2 || MW_DEBUG_UART
619 } else if (_event_src & BT_UART_RCV_EVENT) {
620 _event_src &= ~BT_UART_RCV_EVENT;
621 handle_bt_uart_rx_event();
622 } else if (_event_src & BT_UART_WAKEUP_EVENT) {
623 _event_src &= ~BT_UART_WAKEUP_EVENT;
624 bt_hci_ehcill_wake();
625 } else if (_event_src & DBG_UART_RCV_EVENT) {
626 _event_src &= ~DBG_UART_RCV_EVENT;
627 #if defined MW_DEVBOARD_V2 || MW_DEBUG_UART
628 handle_uart_rx_event();
630 } else if (_event_src & BUTTON_EVENT) {
631 _event_src &= ~BUTTON_EVENT;
632 handle_button_event();
633 } else if (_event_src & TIMER_500MS_EVENT) {
634 _event_src &= ~TIMER_500MS_EVENT;
635 oswald_halfsecond_tick();
636 } else if (_event_src & TIMER_100MS_EVENT) {
637 _event_src &= ~TIMER_100MS_EVENT;
638 oswald_centisecond_tick();
639 } else if (_event_src & ACCEL_EVENT) {
640 _event_src &= ~ACCEL_EVENT;
643 #if defined MW_DEVBOARD_V2 || MW_DEBUG_UART
644 snprintf(tstr, 64, "unhandled event in 0x%04x\n", _event_src);
652 #pragma vector=BUTTON_PORT_VECTOR
653 __interrupt void BUTTON_ISR (void)
657 BUTTON_PORT_IFG &= ~ALL_BUTTONS;
658 // BUTTON_PORT_IE &= ~INT_EDGE_SEL_BUTTONS;
659 _event_src |= BUTTON_EVENT;
660 //_button_state = (BUTTON_PORT_IN & ALL_BUTTONS);
663 #pragma vector=PORT1_VECTOR
664 __interrupt void PORT1_GPIO_ISR (void)
666 if (P1IFG & BT_IO_CTS) {
671 debug_uart_tx("BT CTS irq\n");
672 _event_src |= BT_UART_WAKEUP_EVENT;
673 // bt_hci_ehcill_wake();
674 } else if (P1IFG & ACCELEROMETER_INT_PIN) {
677 P1IFG &= ~ACCELEROMETER_INT_PIN;
678 // debug_uart_tx("ACC irq\n");
679 _event_src |= ACCEL_EVENT;
685 #pragma vector=NOVECTOR
686 __interrupt void UNEXP_ISR (void)
688 debug_uart_tx("unexpected IRQ occured\n");
700 /* enable interrupts, we will need them! */
701 __enable_interrupt();
703 #if defined MW_DEVBOARD_V2 || MW_DEBUG_UART
705 debug_uart_tx("\nOswald on MetaWatch\n");
710 mw_lcd_update_screen();
713 mw_init_vibrate_pwm();
715 oswald_set_time(RTCHOUR, RTCMIN, RTCSEC, TRUE);
716 oswald_set_date(RTCDAY, RTCMON, RTCYEAR, TRUE);
720 /* handle pending events */
723 /* enter LPM3 sleep mode waiting for interrupt */
724 /* errata PMM11 + PMM12 - divide MCLK before going to sleep */
725 if (DetermineErrata()) {
731 if (DetermineErrata()) {