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"
24 uint16_t _event_src = 0;
26 #define HARDWARE_REVISION_ADDRESS (0x1a07)
28 unsigned char GetMsp430HardwareRevision(void)
30 unsigned char *pDeviceType = (unsigned char *)(unsigned char *)HARDWARE_REVISION_ADDRESS;
32 return pDeviceType[0]+'1';
35 uint8_t DetermineErrata(void)
37 unsigned char Revision = GetMsp430HardwareRevision();
50 static void set16mhz(void)
52 UCSCTL0 = 0x00; // Set lowest possible DCOx, MODx
53 UCSCTL1 = DCORSEL_5; // Select suitable range
54 UCSCTL2 = 488 + FLLD_1; // Set DCO Multiplier
55 UCSCTL4 = SELA__XT1CLK | SELS__DCOCLKDIV | SELM__DCOCLKDIV ;
57 // Worst-case settling time for the DCO when the DCO range bits have been
58 // changed is n x 32 x 32 x f_FLL_reference. See UCS chapter in 5xx UG
60 // 32 x 32 x / f_FLL_reference (32,768 Hz) = .03125 = t_DCO_settle
61 // t_DCO_settle / (1 / 18 MHz) = 562500 = counts_DCO_settle
63 // __delay_cycles(562500);
66 __delay_cycles(56250);
70 static void setup_clocks(void)
76 /* use external oscillator */
78 if ((UCSCTL6 & XT1DRIVE_3) != XT1DRIVE_3) {
79 UCSCTL6_L |= XT1DRIVE1_L + XT1DRIVE0_L;
82 while ((SFRIFG1 & OFIFG) && i--) {
83 UCSCTL7 &= ~(DCOFFG + XT1LFOFFG + XT1HFOFFG + XT2OFFG);
86 UCSCTL6 = (UCSCTL6 & ~(XT1DRIVE_3)) |(XT1DRIVE_0);
90 UCSCTL8 |= SMCLKREQEN;
92 // setup for quick wake up from interrupt and
93 // minimal power consumption in sleep mode
94 DISABLE_SVSL(); // SVS Low side is turned off
97 DISABLE_SVML(); // Monitor low side is turned off
98 DISABLE_SVML_INTERRUPT();
100 DISABLE_SVMH(); // Monitor high side is turned off
101 DISABLE_SVMH_INTERRUPT();
103 ENABLE_SVSH(); // SVS High side is turned on
104 ENABLE_SVSH_RESET(); // Enable POR on SVS Event
106 SVSH_ENABLED_IN_LPM_FULL_PERF(); // SVS high side Full perf mode,
107 // stays on in LPM3,enhanced protect
109 // Wait until high side, low side settled
110 while ((PMMIFG & SVSMLDLYIFG) == 0 && (PMMIFG & SVSMHDLYIFG) == 0)
115 if (DetermineErrata()) {
116 *(unsigned int*)(0x0110) = 0x9602;
117 *(unsigned int*)(0x0112) |= 0x0800;
120 /* enable oscillator fault NMI IRQ */
125 #pragma vector=PWR_PORT_VECTOR
126 __interrupt void PWR_ISR (void)
128 /* clear all possible sources */
129 PWR_PORT_IFG &= ~(BAT_CHARGE_STAT1 | BAT_CHARGE_STAT2 | BAT_CHARGE_PWR_BIT);
130 _event_src |= POWER_SRC_EVENT;
136 static void mw_init_vibrate_pwm(void)
139 // Start with P7.3 as an output
140 P7OUT &= ~BIT3; // Low when a digital output
141 P7SEL &= ~BIT3; // P7 option select = false
142 P7DIR |= BIT3; // P7 outputs
146 // No expansion divide
149 // do a PWM with 64 total steps. This gives a count up of 32 and
150 // a count down of 32
153 // Compare channel 2 is used as output
154 TA1CCTL2 = OUTMOD_6; // PWM output mode: 6 - toggle/set
155 TA1CCR2 = 10; // 10 is a 2/3 duty cycle
160 static void setup_pins(void)
163 CONFIGURE_BUTTON_PINS();
164 #ifdef MW_DEVBOARD_V2
165 CONFIG_LED_PINS(); // debug LEDs on devboard
167 DISABLE_LCD_LED(); // frontlight
169 CONFIG_ACCELEROMETER_PINS();
170 //DISABLE_ACCELEROMETER_POWER(); // starts from config 5 and later
171 ENABLE_ACCELEROMETER_POWER(); // starts from config 5 and later
173 HARDWARE_CFG_SENSE_INIT();
176 APPLE_POWER_DISABLE();
179 BT_CLK_REQ_CONFIG_AS_OUTPUT_LOW();
180 BT_IO1_CONFIG_AS_OUTPUT_LOW();
181 BT_IO2_CONFIG_AS_OUTPUT_LOW();
185 LIGHT_SENSOR_SHUTDOWN();
187 BATTERY_SENSE_INIT();
188 BATTERY_SENSE_DISABLE();
189 BAT_CHARGE_DIR &= ~(BAT_CHARGE_STAT1 | BAT_CHARGE_STAT2 | BAT_CHARGE_PWR_BIT);
190 BAT_CHARGE_OUT |= BAT_CHARGE_PWR_BIT | BAT_CHARGE_STAT1 | BAT_CHARGE_STAT2; // pull-up
191 BAT_CHARGE_REN |= BAT_CHARGE_PWR_BIT; // enable resistors
192 // BAT_CHARGE_IE |= BAT_CHARGE_PWR_BIT;
193 BAT_CHARGE_OUT |= BAT_CHARGE_ENABLE_PIN; // !CE, negative logic
194 BAT_CHARGE_DIR |= BAT_CHARGE_ENABLE_PIN;
196 /* disable reset function, enable NMI, do not enable NMI IRQ */
197 /* to avoid accidential reset on charger clip connect */
198 #ifndef MW_DEVBOARD_V2 // but only on real watch
199 SFRRPCR &= ~SYSRSTRE;
204 #pragma vector=WDT_VECTOR
205 __interrupt void WDT_ISR (void)
207 /* eventually we will do something here, not for now */
208 _event_src |= WATCHDOG_EVENT;
212 static void setup_wdt(void)
215 WDTCTL = WDTPW + WDTHOLD; // disable watchdog
217 WDTCTL = WDT_ADLY_1000; // 1 second timeout
218 SFRIE1 |= WDTIE; // Enable WDT interrupt
223 #pragma vector=UNMI_VECTOR
224 __interrupt void NMI_ISR (void)
226 #if defined MW_DEVBOARD_V2
228 debug_uart_tx_char('n');
230 while ((SFRIFG1 & OFIFG)) {
231 UCSCTL7 &= ~(DCOFFG + XT1LFOFFG + XT1HFOFFG + XT2OFFG);
237 #pragma vector=RTC_VECTOR
238 __interrupt void RTC_ISR (void)
242 debug_uart_tx("RTC none IRQ\n");
244 case RTCIV_RTCRDYIFG:
245 case RTCIV_RTCTEVIFG:
248 debug_uart_tx("RTC misc IRQ\n");
251 RTCPS1CTL &= ~RT1PSIFG;
252 _event_src |= RTC_1HZ_EVENT;
255 #if defined MW_DEVBOARD_V2
270 RTCCTL2 = 0x00 & 0x3f;
273 // Set the counter for RTC mode
276 // set 128 Hz rate for prescale 0 interrupt
277 RTCPS0CTL |= RT0IP_7;
279 // enable 1 pulse per second interrupt using prescale 1
280 RTCPS1CTL |= RT1IP_6 | RT1PSIE;
282 // 1 Hz calibration output
283 RTCCTL23 |= RTCCALF_3;
285 // setting the peripheral selection bit makes the other I/O control a don't care
286 // P2.4 = 1 Hz RTC calibration output
287 // Direction needs to be set as output
288 RTC_1HZ_PORT_SEL |= RTC_1HZ_BIT;
289 RTC_1HZ_PORT_DIR |= RTC_1HZ_BIT;
291 RTCYEAR = (unsigned int) 2013;
292 RTCMON = (unsigned int) 1;
293 RTCDAY = (unsigned int) 1;
294 RTCDOW = (unsigned int) 2;
295 RTCHOUR = (unsigned int) 01;
296 RTCMIN = (unsigned int) 0;
297 RTCSEC = (unsigned int) 0;
300 RTCCTL01 &= ~RTCHOLD;
304 #if defined MW_DEVBOARD_V2
305 static void dbg_out_rtc(void)
308 snprintf(clk_str, 16, "%02d:%02d.%02d %d\n", RTCHOUR, RTCMIN, RTCSEC, RTCDOW);
309 debug_uart_tx(clk_str);
313 static void handle_button_event(void)
315 unsigned char _button_state = 0;
318 snprintf(clk_str, 16, "0x%02x\n", _button_state);
319 debug_uart_tx(clk_str);
321 while (_button_state != (BUTTON_PORT_IN & ALL_BUTTONS)) {
322 __delay_cycles(562500);
323 _button_state = (BUTTON_PORT_IN & ALL_BUTTONS);
324 __delay_cycles(562500);
326 // BUTTON_PORT_IE |= INT_EDGE_SEL_BUTTONS;
328 if (_button_state & SW_A) {
329 debug_uart_tx("switch A\n");
330 oswald_handle_button_press(BUTTON_A);
332 if (_button_state & SW_B) {
333 debug_uart_tx("switch B\n");
334 oswald_handle_button_press(BUTTON_B);
336 if (_button_state & SW_C) {
337 debug_uart_tx("switch C\n");
338 oswald_handle_button_press(BUTTON_C);
340 if (_button_state & SW_D) {
341 debug_uart_tx("switch D\n");
342 oswald_handle_button_press(BUTTON_D);
344 if (_button_state & SW_E) {
345 debug_uart_tx("switch E\n");
346 oswald_handle_button_press(BUTTON_E);
348 if (_button_state & SW_F) {
349 debug_uart_tx("switch F\n");
350 oswald_handle_button_press(BUTTON_F);
354 void check_pwr_state(void)
356 if (BAT_CHARGE_IN & BAT_CHARGE_PWR_BIT) {
357 BAT_CHARGE_OUT |= BAT_CHARGE_ENABLE_PIN;
358 BAT_CHARGE_REN &= ~(BAT_CHARGE_STAT1 | BAT_CHARGE_STAT2); // disable pull-up
360 BAT_CHARGE_OUT &= ~BAT_CHARGE_ENABLE_PIN;
361 BAT_CHARGE_REN |= BAT_CHARGE_STAT1 | BAT_CHARGE_STAT2; // enable pull-up
365 static void handle_bt_uart_rx_event(void)
367 const unsigned char *rx;
368 unsigned char len, *rp, p;
370 rx = mw_bt_get_rx_buf(&rp, &len);
374 p += bt_feed_packet_data(rx[(*rp+p)%BT_RX_MAX_SIZE]);
377 *rp = (*rp + len) % BT_RX_MAX_SIZE;
380 #if defined MW_DEVBOARD_V2
381 static void handle_uart_rx_event(void)
384 #ifndef CC256x_TRANSP
387 if (debug_uart_rx_char(&c)) {
388 debug_uart_tx_char(c);
390 debug_uart_tx("\nenabling ACC\n");
392 } else if (c == 'A') {
393 debug_uart_tx("\ndisabling ACC\n");
395 } else if (c == 'r') {
397 debug_uart_tx("\nread ACC: ");
398 mw_acc_read(&x, &y, &z);
399 snprintf(tstr, 64, "x:%d y:%d z:%d\n", x,y,z);
401 } else if (c =='R') {
403 al = mw_get_amblight_adc_val();
404 snprintf(tstr, 64, "light: %d\n", al);
406 } else if (c == 'b') {
407 debug_uart_tx("\nenabling BT\n");
409 } else if (c == 'B') {
410 debug_uart_tx("\ndisabling BT\n");
412 } else if (c == 'c') {
413 debug_uart_tx("\nCharger status: ");
414 snprintf(tstr, 16, "0x%04x 0x%04x ", BAT_CHARGE_IN, (BAT_CHARGE_IN & BAT_CHARGE_PWR_BIT));
416 if (BAT_CHARGE_IN & BAT_CHARGE_PWR_BIT)
417 debug_uart_tx("no ext pwr, ");
419 debug_uart_tx("ext pwr connected, ");
420 switch (BAT_CHARGE_IN & (BAT_CHARGE_STAT1 | BAT_CHARGE_STAT2)) {
421 case BAT_CHARGE_STAT1:
422 debug_uart_tx("charge done\n");
424 case BAT_CHARGE_STAT2:
425 debug_uart_tx("fast charge\n");
427 case (BAT_CHARGE_STAT1 | BAT_CHARGE_STAT2):
428 debug_uart_tx("suspend, sleep or fault\n");
431 debug_uart_tx("precharge\n");
434 if (BAT_CHARGE_IN & BAT_CHARGE_ENABLE_PIN)
435 debug_uart_tx(" !charge\n");
437 debug_uart_tx(" charge\n");
438 } else if (c == 'd') {
439 debug_uart_tx("charging disabled\n");
440 BAT_CHARGE_OUT |= BAT_CHARGE_ENABLE_PIN;
441 } else if (c == 'e') {
442 debug_uart_tx("charging enabled\n");
443 BAT_CHARGE_OUT &= ~BAT_CHARGE_ENABLE_PIN;
444 } else if (c == 'l') {
445 debug_uart_tx("backlight LED on\n");
446 hal_lcd_set_backlight(TRUE);
447 } else if (c == 'L') {
448 debug_uart_tx("backlight LED off\n");
449 hal_lcd_set_backlight(FALSE);
450 } else if (c == 'u') {
451 mw_lcd_update_screen();
452 } else if (c == '+') {
454 } else if (c == '-') {
456 } else if (c == 'H') {
458 dclass[0] = BT_MW_DEVICE_CLASS & 0xff;
459 dclass[1] = (BT_MW_DEVICE_CLASS & 0xff00) >> 8;
460 dclass[2] = (BT_MW_DEVICE_CLASS & 0xff0000) >> 16;
462 debug_uart_tx("HCI reset\n");
463 bt_hci_cmd(HCI_HC_BB_OGF, HCI_RESET_OCF, 0, NULL);
464 bt_hci_cmd(HCI_HC_BB_OGF, HCI_W_COD_OCF, 3, dclass);
465 } else if (c == 'S') {
466 debug_uart_tx("Scan enable\n");
467 tstr[0] = HCI_BB_SCAN_INQUIRY | HCI_BB_SCAN_PAGE;
468 bt_hci_cmd(HCI_HC_BB_OGF, HCI_W_SCAN_EN_OCF, 1, (uint8_t *)tstr);
469 } else if (c == 'h') {
473 } else if (c == 'm') {
477 } else if (c == 'N') {
478 debug_uart_tx("Set name\n");
486 bt_hci_cmd(HCI_HC_BB_OGF, HCI_W_LOCAL_NAME_OCF, 0x07, (uint8_t *)tstr);
487 } else if (c == 'R') {
488 bt_hci_cmd(HCI_INFO_PARAM_OGF, HCI_R_BD_ADDR_OCF, 0, NULL);
495 void start_timer(int cycles)
498 TA0CTL = TASSEL_1 | TACLR | MC__STOP; // SMCLK, clear TAR
499 TA0CCTL0 = CCIE; // CCR0 interrupt enabled
501 TA0CTL |= MC_1; // Start Timer_A in continuous mode
504 void stop_timer(void)
506 TA0CCTL0 &= ~CCIE; // CCR0 interrupt enabled
507 TA0CTL = MC__STOP; // Start Timer_A in continuous mode
510 // Timer A0 interrupt service routine
511 #pragma vector=TIMER0_A0_VECTOR
512 __interrupt void TIMER0_A0_ISR (void)
515 #if defined xMW_DEVBOARD_V2
518 _event_src |= TIMER_500MS_EVENT | TIMER_100MS_EVENT;
522 uint8_t handle_event(void)
524 #if defined MW_DEVBOARD_V2
530 while (_event_src != 0) {
531 if (_event_src & WATCHDOG_EVENT) {
532 _event_src &= ~WATCHDOG_EVENT;
533 debug_uart_tx_char('w');
534 } else if (_event_src & RTC_1HZ_EVENT) {
535 _event_src &= ~RTC_1HZ_EVENT;
537 oswald_one_second_tick();
538 #if defined MW_DEVBOARD_V2
541 } else if (_event_src & BT_UART_RCV_EVENT) {
542 _event_src &= ~BT_UART_RCV_EVENT;
543 handle_bt_uart_rx_event();
544 } else if (_event_src & BT_UART_WAKEUP_EVENT) {
545 _event_src &= ~BT_UART_WAKEUP_EVENT;
546 bt_hci_ehcill_wake();
547 } else if (_event_src & DBG_UART_RCV_EVENT) {
548 _event_src &= ~DBG_UART_RCV_EVENT;
549 #if defined MW_DEVBOARD_V2
550 handle_uart_rx_event();
552 } else if (_event_src & BUTTON_EVENT) {
553 _event_src &= ~BUTTON_EVENT;
554 handle_button_event();
555 } else if (_event_src & TIMER_500MS_EVENT) {
556 _event_src &= ~TIMER_500MS_EVENT;
557 oswald_halfsecond_tick();
558 } else if (_event_src & TIMER_100MS_EVENT) {
559 _event_src &= ~TIMER_100MS_EVENT;
560 oswald_centisecond_tick();
561 } else if (_event_src & ACCEL_EVENT) {
562 _event_src &= ~ACCEL_EVENT;
565 #if defined MW_DEVBOARD_V2
566 snprintf(tstr, 64, "unhandled event in 0x%04x\n", _event_src);
574 #pragma vector=BUTTON_PORT_VECTOR
575 __interrupt void BUTTON_ISR (void)
578 BUTTON_PORT_IFG &= ~ALL_BUTTONS;
579 // BUTTON_PORT_IE &= ~INT_EDGE_SEL_BUTTONS;
580 _event_src |= BUTTON_EVENT;
581 //_button_state = (BUTTON_PORT_IN & ALL_BUTTONS);
584 #pragma vector=PORT1_VECTOR
585 __interrupt void PORT1_GPIO_ISR (void)
587 if (P1IFG & BT_IO_CTS) {
591 debug_uart_tx("BT CTS irq\n");
592 _event_src |= BT_UART_WAKEUP_EVENT;
593 // bt_hci_ehcill_wake();
594 } else if (P1IFG & ACCELEROMETER_INT_PIN) {
596 P1IFG &= ~ACCELEROMETER_INT_PIN;
597 // debug_uart_tx("ACC irq\n");
598 _event_src |= ACCEL_EVENT;
604 #pragma vector=NOVECTOR
605 __interrupt void UNEXP_ISR (void)
607 debug_uart_tx("unexpected IRQ occured\n");
619 /* enable interrupts, we will need them! */
620 __enable_interrupt();
622 #if defined MW_DEVBOARD_V2
624 debug_uart_tx("\nOswald on MetaWatch\n");
629 mw_lcd_update_screen();
632 mw_init_vibrate_pwm();
634 oswald_set_time(RTCHOUR, RTCMIN, RTCSEC, TRUE);
635 oswald_set_date(RTCDAY, RTCMON, RTCYEAR, TRUE);
639 /* handle pending events */
642 /* enter LPM3 sleep mode waiting for interrupt */
643 /* errata PMM11 + PMM12 - divide MCLK before going to sleep */
644 if (DetermineErrata()) {
650 if (DetermineErrata()) {