#include /* debug */ #define DEBUG DEBUG_FULL #include "net/ip/uip-debug.h" /* contiki */ #include "sys/process.h" /* mc1322x */ #include "mc1322x.h" #include "contiki-maca.h" #include "config.h" /* Threshold for buck converter; buck will be disabled if vbatt is below this */ #define MC1322X_BUCK_THRES 2425 /* Hysterisis window around buck threshold */ #define MC1322X_BUCK_WINDOW 150 #define MC1322X_BUCK_THRES_H (MC1322X_BUCK_THRES + MC1322X_BUCK_WINDOW/2) #define MC1322X_BUCK_THRES_L (MC1322X_BUCK_THRES - MC1322X_BUCK_WINDOW/2) /* Time between vbatt checks for the buck */ #define MC1322X_BUCK_MONITOR_PERIOD 600 * CLOCK_SECOND /* periodically poll adc_vbatt and manages the buck appropriately */ static struct etimer et_buck; PROCESS(buck_monitor, "buck monitor"); PROCESS_THREAD(buck_monitor, ev, data) { PROCESS_BEGIN(); PRINTF("starting vbatt monitor\n"); etimer_set(&et_buck, MC1322X_BUCK_MONITOR_PERIOD); while (1) { PROCESS_WAIT_EVENT(); if(etimer_expired(&et_buck)) { adc_service(); PRINTF("buck monitor: vbatt: %d mV\n\r", adc_vbatt); if( CRM->VREG_CNTLbits.BUCK_EN == 1 && adc_vbatt < MC1322X_BUCK_THRES_L ) { PRINTF("vbatt low, disabling buck\n\r", adc_vbatt); CRM->SYS_CNTLbits.PWR_SOURCE = 0; CRM->VREG_CNTLbits.BUCK_SYNC_REC_EN = 0; CRM->VREG_CNTLbits.BUCK_BYPASS_EN = 1; CRM->VREG_CNTLbits.BUCK_EN = 0; } else if ( CRM->VREG_CNTLbits.BUCK_EN == 0 && adc_vbatt > MC1322X_BUCK_THRES_H ) { PRINTF("vbatt high, enabling buck\n\r", adc_vbatt); CRM->SYS_CNTLbits.PWR_SOURCE = 1; CRM->VREG_CNTLbits.BUCK_SYNC_REC_EN = 1; CRM->VREG_CNTLbits.BUCK_BYPASS_EN = 0; CRM->VREG_CNTLbits.BUCK_EN = 1; } etimer_set(&et_buck, MC1322X_BUCK_MONITOR_PERIOD); } } PROCESS_END(); } void buck_setup(void) { nvmType_t type; nvmErr_t err; volatile int i; default_vreg_init(); while(CRM->STATUSbits.VREG_1P5V_RDY == 0) { continue; } while(CRM->STATUSbits.VREG_1P8V_RDY == 0) { continue; } /* takes time for the flash supply to fail (if there is no buck) */ /* spin while this happens doing nvm_detects */ /* XXX todo: don't probe buck if Vbatt < 2.5V */ adc_service(); PRINTF("vbatt: %04u mV\n\r", adc_vbatt); type = 1; for(i = 0; i < 128 && type != 0; i++) { err = nvm_detect(gNvmInternalInterface_c, &type); } if (type == gNvmType_NoNvm_c) { PRINTF("NVM failed without buck, trying with buck\n\r"); if (adc_vbatt < MC1322X_BUCK_THRES_L) { PRINTF("Vbatt is low, bypassing buck\n\r"); CRM->SYS_CNTLbits.PWR_SOURCE = 0; CRM->VREG_CNTLbits.BUCK_SYNC_REC_EN = 0; CRM->VREG_CNTLbits.BUCK_BYPASS_EN = 1; CRM->VREG_CNTLbits.BUCK_EN = 0; } else { CRM->SYS_CNTLbits.PWR_SOURCE = 1; CRM->VREG_CNTLbits.BUCK_SYNC_REC_EN = 1; CRM->VREG_CNTLbits.BUCK_BYPASS_EN = 0; CRM->VREG_CNTLbits.BUCK_EN = 1; } while(CRM->STATUSbits.VREG_BUCK_RDY == 0) { continue; } CRM->VREG_CNTLbits.VREG_1P5V_SEL = 3; CRM->VREG_CNTLbits.VREG_1P5V_EN = 3; CRM->VREG_CNTLbits.VREG_1P8V_EN = 1; while(CRM->STATUSbits.VREG_1P5V_RDY == 0) { continue; } while(CRM->STATUSbits.VREG_1P8V_RDY == 0) { continue; } type = 1; for(i = 0; i < 128 && type != 0; i++) { err = nvm_detect(gNvmInternalInterface_c, &type); } if (type != gNvmType_NoNvm_c) { PRINTF("buck ok\n\r"); /* start a process to monitor vbatt and enable/disable the buck as necessary */ process_start(&buck_monitor, NULL); } else { printf("fatal: couldn't detect NVM\n\r"); } } else { PRINTF("NVM ok without buck\n\r"); } } /* setup the RTC */ /* try to start the 32kHz xtal */ void rtc_setup(void) { volatile uint32_t rtc_count; volatile uint32_t i; ring_osc_off(); xtal32_on(); xtal32_exists(); rtc_count = CRM->RTC_COUNT; PRINTF("trying to start 32kHz xtal\n\r"); for(i = 0; i < 150000 && CRM->RTC_COUNT == rtc_count; i++) { continue; } if(CRM->RTC_COUNT == rtc_count) { PRINTF("32xtal failed, using ring osc\n\r"); CRM->SYS_CNTLbits.XTAL32_EXISTS = 0; CRM->XTAL32_CNTLbits.XTAL32_EN = 0; ring_osc_on(); /* Set default tune values from datasheet */ CRM->RINGOSC_CNTLbits.ROSC_CTUNE = 0x6; CRM->RINGOSC_CNTLbits.ROSC_FTUNE = 0x17; /* Trigger calibration */ rtc_calibrate(); PRINTF("RTC calibrated to %d Hz\r\n", rtc_freq); } else { PRINTF("32kHz xtal started\n\r"); rtc_freq = 32768; } } /* call mc1322x_init once to initalize everything with the current config */ void mc1322x_init(void) { /* XXX TODO load config from flash */ /* config should say what uart to use for debug console */ /* config should also set the baud rate */ /* for now, just clean up contiki-conf.h */ /* maybe factor into conf.h -> contiki-conf.h and mc1322x-conf.h platform-conf.h */ /* print out config in debug */ /* initialize the uarts */ uart_init(CONSOLE_UART, CONSOLE_BAUD); PRINTF("mc1322x init\n\r"); adc_init(); ctimer_init(); process_init(); process_start(&etimer_process, NULL); process_start(&contiki_maca_process, NULL); buck_setup(); /* start with a default config */ mc1322x_config_restore(&mc1322x_config); if ( mc1322x_config_valid(&mc1322x_config) != 1 ) { PRINTF("flash invalid\n\r"); /* save the default config to flash */ mc1322x_config_set_default(&mc1322x_config); mc1322x_config_save(&mc1322x_config); } #if DEBUG_FULL mc1322x_config_print(); #endif /* setup the radio */ maca_init(); set_power(mc1322x_config.power); set_channel(mc1322x_config.channel); set_demodulator_type(mc1322x_config.flags.demod); set_prm_mode(mc1322x_config.flags.autoack); /* must be done AFTER maca_init */ /* the radio calibration appears to clobber the RTC trim caps */ rtc_setup(); rtimer_init(); clock_init(); }