/*---------------------------------------------------------------------------*/ void rf_core_setup_interrupts() { bool interrupts_disabled; /* We are already turned on by the caller, so this should not happen */ if(!rf_core_is_accessible()) { PRINTF("setup_interrupts: No access\n"); return; } /* Disable interrupts */ interrupts_disabled = ti_lib_int_master_disable(); /* Set all interrupt channels to CPE0 channel, error to CPE1 */ HWREG(RFC_DBELL_NONBUF_BASE + RFC_DBELL_O_RFCPEISL) = ERROR_IRQ; /* Acknowledge configured interrupts */ HWREG(RFC_DBELL_NONBUF_BASE + RFC_DBELL_O_RFCPEIEN) = ENABLED_IRQS; /* Clear interrupt flags, active low clear(?) */ HWREG(RFC_DBELL_NONBUF_BASE + RFC_DBELL_O_RFCPEIFG) = 0x0; ti_lib_int_pend_clear(INT_RF_CPE0); ti_lib_int_pend_clear(INT_RF_CPE1); ti_lib_int_enable(INT_RF_CPE0); ti_lib_int_enable(INT_RF_CPE1); if(!interrupts_disabled) { ti_lib_int_master_enable(); } }
/*---------------------------------------------------------------------------*/ void cc26xx_rf_cpe0_isr(void) { ENERGEST_ON(ENERGEST_TYPE_IRQ); if(!rf_core_is_accessible()) { printf("RF ISR called but RF not ready... PANIC!!\n"); if(rf_core_power_up() != RF_CORE_CMD_OK) { PRINTF("rf_core_power_up() failed\n"); return; } } ti_lib_int_master_disable(); if(HWREG(RFC_DBELL_NONBUF_BASE + RFC_DBELL_O_RFCPEIFG) & RX_FRAME_IRQ) { process_poll(&rf_core_process); } if(RF_CORE_DEBUG_CRC) { if(HWREG(RFC_DBELL_NONBUF_BASE + RFC_DBELL_O_RFCPEIFG) & RX_NOK_IRQ) { rx_nok_isr(); } } /* Clear interrupt flags */ HWREG(RFC_DBELL_NONBUF_BASE + RFC_DBELL_O_RFCPEIFG) = 0x0; ti_lib_int_master_enable(); ENERGEST_OFF(ENERGEST_TYPE_IRQ); }
/*---------------------------------------------------------------------------*/ void board_init() { uint8_t int_disabled = ti_lib_int_master_disable(); /* Turn on relevant PDs */ wakeup_handler(); /* Enable GPIO peripheral */ ti_lib_prcm_peripheral_run_enable(PRCM_PERIPH_GPIO); /* Apply settings and wait for them to take effect */ ti_lib_prcm_load_set(); while (!ti_lib_prcm_load_get()) ; lpm_register_module(&srf_module); /* Re-enable interrupt if initially enabled. */ if (!int_disabled) { ti_lib_int_master_enable(); } /* Init of PWM */ pwm_init(); }
/*---------------------------------------------------------------------------*/ void rf_core_power_down() { bool interrupts_disabled = ti_lib_int_master_disable(); ti_lib_int_disable(INT_RF_CPE0); ti_lib_int_disable(INT_RF_CPE1); if(rf_core_is_accessible()) { HWREG(RFC_DBELL_NONBUF_BASE + RFC_DBELL_O_RFCPEIFG) = 0x0; HWREG(RFC_DBELL_NONBUF_BASE + RFC_DBELL_O_RFCPEIEN) = 0x0; /* need to send FS_POWERDOWN or analog components will use power */ fs_powerdown(); } /* Shut down the RFCORE clock domain in the MCU VD */ ti_lib_prcm_domain_disable(PRCM_DOMAIN_RFCORE); ti_lib_prcm_load_set(); while(!ti_lib_prcm_load_get()); /* Turn off RFCORE PD */ ti_lib_prcm_power_domain_off(PRCM_DOMAIN_RFCORE); while(ti_lib_prcm_power_domain_status(PRCM_DOMAIN_RFCORE) != PRCM_DOMAIN_POWER_OFF); ti_lib_int_pend_clear(INT_RF_CPE0); ti_lib_int_pend_clear(INT_RF_CPE1); ti_lib_int_enable(INT_RF_CPE0); ti_lib_int_enable(INT_RF_CPE1); if(!interrupts_disabled) { ti_lib_int_master_enable(); } }
/*---------------------------------------------------------------------------*/ void cc26xx_uart_init() { bool interrupts_disabled; /* Return early if disabled by user conf or if ports are misconfigured */ if(usable() == false) { return; } /* Disable Interrupts */ interrupts_disabled = ti_lib_int_master_disable(); /* Register ourselves with the LPM module */ lpm_register_module(&uart_module); /* Only TX and EN to start with. RX will be enabled only if needed */ input_handler = NULL; /* * init() won't actually fire up the UART. We turn it on only when (and if) * it gets requested, either to enable input or to send out a character * * Thus, we simply re-enable processor interrupts here */ if(!interrupts_disabled) { ti_lib_int_master_enable(); } }
/*---------------------------------------------------------------------------*/ void board_init() { /* Disable global interrupts */ bool int_disabled = ti_lib_int_master_disable(); /* Turn on relevant PDs */ wakeup_handler(); /* Enable GPIO peripheral */ ti_lib_prcm_peripheral_run_enable(PRCM_PERIPH_GPIO); /* Apply settings and wait for them to take effect */ ti_lib_prcm_load_set(); while(!ti_lib_prcm_load_get()); /* Make sure the external flash is in the lower power mode */ ext_flash_init(); lpm_register_module(&launchpad_module); /* For unsupported peripherals, select a default pin configuration */ configure_unused_pins(); /* Re-enable interrupt if initially enabled. */ if(!int_disabled) { ti_lib_int_master_enable(); } }
/*---------------------------------------------------------------------------*/ void board_init() { /* Disable global interrupts */ uint8_t int_disabled = ti_lib_int_master_disable(); power_domains_on(); /* Configure all clock domains to run at full speed */ ti_lib_prcm_clock_configure_set(PRCM_DOMAIN_SYSBUS, PRCM_CLOCK_DIV_1); ti_lib_prcm_clock_configure_set(PRCM_DOMAIN_CPU, PRCM_CLOCK_DIV_1); ti_lib_prcm_clock_configure_set(PRCM_DOMAIN_TIMER, PRCM_CLOCK_DIV_1); ti_lib_prcm_clock_configure_set(PRCM_DOMAIN_SERIAL, PRCM_CLOCK_DIV_1); ti_lib_prcm_clock_configure_set(PRCM_DOMAIN_PERIPH, PRCM_CLOCK_DIV_1); /* Enable GPIO peripheral */ ti_lib_prcm_peripheral_run_enable(PRCM_PERIPH_GPIO); /* Apply settings and wait for them to take effect */ ti_lib_prcm_load_set(); while(!ti_lib_prcm_load_get()); /* Enable GPT0 module - Wait for the clock to be enabled */ ti_lib_prcm_peripheral_run_enable(PRCM_PERIPH_TIMER0); ti_lib_prcm_load_set(); while(!ti_lib_prcm_load_get()); /* Keys (input pullup) */ ti_lib_rom_ioc_pin_type_gpio_input(BOARD_IOID_KEY_LEFT); ti_lib_rom_ioc_pin_type_gpio_input(BOARD_IOID_KEY_RIGHT); ti_lib_ioc_io_port_pull_set(BOARD_IOID_KEY_LEFT, IOC_IOPULL_UP); ti_lib_ioc_io_port_pull_set(BOARD_IOID_KEY_RIGHT, IOC_IOPULL_UP); /* I2C controller */ board_i2c_init(); /* Sensor interface */ ti_lib_rom_ioc_pin_type_gpio_input(BOARD_IOID_MPU_INT); ti_lib_ioc_io_port_pull_set(BOARD_IOID_MPU_INT, IOC_IOPULL_DOWN); ti_lib_rom_ioc_pin_type_gpio_input(BOARD_IOID_REED_RELAY); ti_lib_ioc_io_port_pull_set(BOARD_IOID_REED_RELAY, IOC_IOPULL_DOWN); ti_lib_rom_ioc_pin_type_gpio_output(BOARD_IOID_MPU_POWER); /* Flash interface */ ti_lib_rom_ioc_pin_type_gpio_output(BOARD_IOID_FLASH_CS); ti_lib_gpio_pin_write(BOARD_FLASH_CS, 1); buzzer_init(); lpm_register_module(&sensortag_module); /* Re-enable interrupt if initially enabled. */ if(!int_disabled) { ti_lib_int_master_enable(); } }
/*---------------------------------------------------------------------------*/ uint_fast8_t rf_core_send_cmd(uint32_t cmd, uint32_t *status) { uint32_t timeout_count = 0; bool interrupts_disabled; bool is_radio_op = false; /* If cmd is 4-byte aligned, then it's a radio OP. Clear the status field */ if((cmd & 0x03) == 0) { is_radio_op = true; ((rfc_radioOp_t *)cmd)->status = RF_CORE_RADIO_OP_STATUS_IDLE; } /* * Make sure ContikiMAC doesn't turn us off from within an interrupt while * we are accessing RF Core registers */ interrupts_disabled = ti_lib_int_master_disable(); if(!rf_core_is_accessible()) { PRINTF("rf_core_send_cmd: RF was off\n"); if(!interrupts_disabled) { ti_lib_int_master_enable(); } return RF_CORE_CMD_ERROR; } if(is_radio_op) { uint16_t command_no = ((rfc_radioOp_t *)cmd)->commandNo; if((command_no & RF_CORE_COMMAND_PROTOCOL_MASK) != RF_CORE_COMMAND_PROTOCOL_COMMON && (command_no & RF_CORE_COMMAND_TYPE_MASK) == RF_CORE_COMMAND_TYPE_RADIO_OP) { last_radio_op = (rfc_radioOp_t *)cmd; } } HWREG(RFC_DBELL_BASE + RFC_DBELL_O_CMDR) = cmd; do { *status = HWREG(RFC_DBELL_BASE + RFC_DBELL_O_CMDSTA); if(++timeout_count > 50000) { PRINTF("rf_core_send_cmd: 0x%08lx Timeout\n", cmd); if(!interrupts_disabled) { ti_lib_int_master_enable(); } return RF_CORE_CMD_ERROR; } } while(*status == RF_CORE_CMDSTA_PENDING); if(!interrupts_disabled) { ti_lib_int_master_enable(); } /* * If we reach here the command is no longer pending. It is either completed * successfully or with error */ return (*status & RF_CORE_CMDSTA_RESULT_MASK) == RF_CORE_CMDSTA_DONE; }
/*---------------------------------------------------------------------------*/ void gpio_interrupt_register_handler(uint8_t ioid, gpio_interrupt_handler_t f) { uint8_t interrupts_disabled = ti_lib_int_master_disable(); /* Clear interrupts on specified pins */ ti_lib_gpio_event_clear(1 << ioid); handlers[ioid] = f; /* Re-enable interrupts */ if(!interrupts_disabled) { ti_lib_int_master_enable(); } }
/*---------------------------------------------------------------------------*/ int rf_core_power_up() { uint32_t cmd_status; bool interrupts_disabled = ti_lib_int_master_disable(); ti_lib_int_pend_clear(INT_RF_CPE0); ti_lib_int_pend_clear(INT_RF_CPE1); ti_lib_int_disable(INT_RF_CPE0); ti_lib_int_disable(INT_RF_CPE1); /* Enable RF Core power domain */ ti_lib_prcm_power_domain_on(PRCM_DOMAIN_RFCORE); while(ti_lib_prcm_power_domain_status(PRCM_DOMAIN_RFCORE) != PRCM_DOMAIN_POWER_ON); ti_lib_prcm_domain_enable(PRCM_DOMAIN_RFCORE); ti_lib_prcm_load_set(); while(!ti_lib_prcm_load_get()); while(!rf_core_is_accessible()) { PRINTF("rf_core_power_up: Not ready\n"); } HWREG(RFC_DBELL_NONBUF_BASE + RFC_DBELL_O_RFCPEIFG) = 0x0; HWREG(RFC_DBELL_NONBUF_BASE + RFC_DBELL_O_RFCPEIEN) = 0x0; ti_lib_int_enable(INT_RF_CPE0); ti_lib_int_enable(INT_RF_CPE1); if(!interrupts_disabled) { ti_lib_int_master_enable(); } /* Let CPE boot */ HWREG(RFC_PWR_NONBUF_BASE + RFC_PWR_O_PWMCLKEN) = RF_CORE_CLOCKS_MASK; /* Send ping (to verify RFCore is ready and alive) */ if(rf_core_send_cmd(CMDR_DIR_CMD(CMD_PING), &cmd_status) != RF_CORE_CMD_OK) { PRINTF("rf_core_power_up: CMD_PING fail, CMDSTA=0x%08lx\n", cmd_status); return RF_CORE_CMD_ERROR; } return RF_CORE_CMD_OK; }
/*---------------------------------------------------------------------------*/ void cc26xx_rf_cpe0_isr(void) { ENERGEST_ON(ENERGEST_TYPE_IRQ); if(!rf_core_is_accessible()) { printf("RF ISR called but RF not ready... PANIC!!\n"); if(rf_core_power_up() != RF_CORE_CMD_OK) { PRINTF("rf_core_power_up() failed\n"); return; } } ti_lib_int_master_disable(); if(HWREG(RFC_DBELL_NONBUF_BASE + RFC_DBELL_O_RFCPEIFG) & RX_FRAME_IRQ) { /* Clear the RX_ENTRY_DONE interrupt flag */ HWREG(RFC_DBELL_NONBUF_BASE + RFC_DBELL_O_RFCPEIFG) = 0xFF7FFFFF; process_poll(&rf_core_process); } if(RF_CORE_DEBUG_CRC) { if(HWREG(RFC_DBELL_NONBUF_BASE + RFC_DBELL_O_RFCPEIFG) & RX_NOK_IRQ) { /* Clear the RX_NOK interrupt flag */ HWREG(RFC_DBELL_NONBUF_BASE + RFC_DBELL_O_RFCPEIFG) = 0xFFFDFFFF; rx_nok_isr(); } } if(HWREG(RFC_DBELL_NONBUF_BASE + RFC_DBELL_O_RFCPEIFG) & (IRQ_LAST_FG_COMMAND_DONE | IRQ_LAST_COMMAND_DONE)) { /* Clear the two TX-related interrupt flags */ HWREG(RFC_DBELL_NONBUF_BASE + RFC_DBELL_O_RFCPEIFG) = 0xFFFFFFF5; } ti_lib_int_master_enable(); ENERGEST_OFF(ENERGEST_TYPE_IRQ); }
/*---------------------------------------------------------------------------*/ void cc26xx_rtc_init(void) { uint32_t compare_value; bool interrupts_disabled; /* Disable and clear interrupts */ interrupts_disabled = ti_lib_int_master_disable(); ti_lib_aon_rtc_disable(); ti_lib_aon_rtc_event_clear(AON_RTC_CH0); ti_lib_aon_rtc_event_clear(AON_RTC_CH2); /* Setup the wakeup event */ ti_lib_aon_event_mcu_wake_up_set(AON_EVENT_MCU_WU0, AON_EVENT_RTC0); ti_lib_aon_event_mcu_wake_up_set(AON_EVENT_MCU_WU1, AON_EVENT_RTC2); ti_lib_aon_rtc_combined_event_config(AON_RTC_CH0 | AON_RTC_CH2); /* Configure channel 2 in continuous compare, 128 ticks / sec */ ti_lib_aon_rtc_inc_value_ch2_set(RTIMER_SECOND / CLOCK_SECOND); ti_lib_aon_rtc_mode_ch2_set(AON_RTC_MODE_CH2_CONTINUOUS); compare_value = (RTIMER_SECOND / CLOCK_SECOND) + ti_lib_aon_rtc_current_compare_value_get(); ti_lib_aon_rtc_compare_value_set(AON_RTC_CH2, compare_value); /* Enable channel 2 and the RTC */ ti_lib_aon_rtc_channel_enable(AON_RTC_CH2); ti_lib_aon_rtc_enable(); ti_lib_int_enable(INT_AON_RTC); /* Re-enable interrupts */ if(!interrupts_disabled) { ti_lib_int_master_enable(); } }
/** * \brief Main function for CC26xx-based platforms * * The same main() is used for all supported boards */ int main(void) { /* Enable flash cache and prefetch. */ ti_lib_vims_mode_set(VIMS_BASE, VIMS_MODE_ENABLED); ti_lib_vims_configure(VIMS_BASE, true, true); ti_lib_int_master_disable(); /* Set the LF XOSC as the LF system clock source */ oscillators_select_lf_xosc(); lpm_init(); board_init(); gpio_interrupt_init(); leds_init(); /* * Disable I/O pad sleep mode and open I/O latches in the AON IOC interface * This is only relevant when returning from shutdown (which is what froze * latches in the first place. Before doing these things though, we should * allow software to first regain control of pins */ ti_lib_pwr_ctrl_io_freeze_disable(); fade(LEDS_RED); ti_lib_int_master_enable(); soc_rtc_init(); clock_init(); rtimer_init(); watchdog_init(); process_init(); random_init(0x1234); /* Character I/O Initialisation */ #if CC26XX_UART_CONF_ENABLE cc26xx_uart_init(); #endif serial_line_init(); printf("Starting " CONTIKI_VERSION_STRING "\n\r"); printf("With DriverLib v%u.%u\n\r", DRIVERLIB_RELEASE_GROUP, DRIVERLIB_RELEASE_BUILD); printf(BOARD_STRING "\n\r"); process_start(&etimer_process, NULL); ctimer_init(); energest_init(); ENERGEST_ON(ENERGEST_TYPE_CPU); fade(LEDS_YELLOW); printf(" Net: "); printf("%s\n\r", NETSTACK_NETWORK.name); printf(" MAC: "); printf("%s\n\r", NETSTACK_MAC.name); printf(" RDC: "); printf("%s", NETSTACK_RDC.name); if(NETSTACK_RDC.channel_check_interval() != 0) { printf(", Channel Check Interval: %u ticks", NETSTACK_RDC.channel_check_interval()); } printf("\n\r"); netstack_init(); set_rf_params(); #if NETSTACK_CONF_WITH_IPV6 memcpy(&uip_lladdr.addr, &linkaddr_node_addr, sizeof(uip_lladdr.addr)); queuebuf_init(); process_start(&tcpip_process, NULL); #endif /* NETSTACK_CONF_WITH_IPV6 */ fade(LEDS_GREEN); process_start(&sensors_process, NULL); autostart_start(autostart_processes); watchdog_start(); fade(LEDS_ORANGE); while(1) { uint8_t r; do { r = process_run(); watchdog_periodic(); } while(r > 0); /* Drop to some low power mode */ lpm_drop(); } }
/*---------------------------------------------------------------------------*/ void lpm_shutdown(uint32_t wakeup_pin, uint32_t io_pull, uint32_t wake_on) { lpm_registered_module_t *module; int i; uint32_t io_cfg = (IOC_STD_INPUT & ~IOC_IOPULL_M) | io_pull | wake_on; /* This procedure may not be interrupted */ ti_lib_int_master_disable(); /* Disable the RTC */ ti_lib_aon_rtc_disable(); ti_lib_aon_rtc_event_clear(AON_RTC_CH0); ti_lib_aon_rtc_event_clear(AON_RTC_CH1); ti_lib_aon_rtc_event_clear(AON_RTC_CH2); /* Reset AON even fabric to default wakeup sources */ for(i = AON_EVENT_MCU_WU0; i <= AON_EVENT_MCU_WU3; i++) { ti_lib_aon_event_mcu_wake_up_set(i, AON_EVENT_NONE); } for(i = AON_EVENT_AUX_WU0; i <= AON_EVENT_AUX_WU2; i++) { ti_lib_aon_event_aux_wake_up_set(i, AON_EVENT_NONE); } ti_lib_sys_ctrl_aon_sync(); watchdog_periodic(); /* Notify all modules that we're shutting down */ for(module = list_head(modules_list); module != NULL; module = module->next) { if(module->shutdown) { module->shutdown(LPM_MODE_SHUTDOWN); } } /* Configure the wakeup trigger */ if(wakeup_pin != IOID_UNUSED) { ti_lib_gpio_dir_mode_set((1 << wakeup_pin), GPIO_DIR_MODE_IN); ti_lib_ioc_port_configure_set(wakeup_pin, IOC_PORT_GPIO, io_cfg); } /* Freeze I/O latches in AON */ ti_lib_aon_ioc_freeze_enable(); /* Turn off RFCORE, SERIAL and PERIPH PDs. This will happen immediately */ ti_lib_prcm_power_domain_off(PRCM_DOMAIN_RFCORE | PRCM_DOMAIN_SERIAL | PRCM_DOMAIN_PERIPH); oscillators_switch_to_hf_rc(); oscillators_select_lf_rcosc(); /* Configure clock sources for MCU and AUX: No clock */ ti_lib_aon_wuc_mcu_power_down_config(AONWUC_NO_CLOCK); ti_lib_aon_wuc_aux_power_down_config(AONWUC_NO_CLOCK); /* Disable SRAM and AUX retentions */ ti_lib_aon_wuc_mcu_sram_config(0); ti_lib_aon_wuc_aux_sram_config(false); /* * Request CPU, SYSBYS and VIMS PD off. * This will only happen when the CM3 enters deep sleep */ ti_lib_prcm_power_domain_off(PRCM_DOMAIN_CPU | PRCM_DOMAIN_VIMS | PRCM_DOMAIN_SYSBUS); /* Request JTAG domain power off */ ti_lib_aon_wuc_jtag_power_off(); /* Turn off AUX */ ti_lib_aux_wuc_power_ctrl(AUX_WUC_POWER_OFF); ti_lib_aon_wuc_domain_power_down_enable(); while(ti_lib_aon_wuc_power_status_get() & AONWUC_AUX_POWER_ON); /* * Request MCU VD power off. * This will only happen when the CM3 enters deep sleep */ ti_lib_prcm_mcu_power_off(); /* Set MCU wakeup to immediate and disable virtual power off */ ti_lib_aon_wuc_mcu_wake_up_config(MCU_IMM_WAKE_UP); ti_lib_aon_wuc_mcu_power_off_config(MCU_VIRT_PWOFF_DISABLE); /* Latch the IOs in the padring and enable I/O pad sleep mode */ ti_lib_pwr_ctrl_io_freeze_enable(); /* Turn off VIMS cache, CRAM and TRAM - possibly not required */ ti_lib_prcm_cache_retention_disable(); ti_lib_vims_mode_set(VIMS_BASE, VIMS_MODE_OFF); /* Enable shutdown and sync AON */ ti_lib_aon_wuc_shut_down_enable(); ti_lib_sys_ctrl_aon_sync(); /* Deep Sleep */ ti_lib_prcm_deep_sleep(); }
/*---------------------------------------------------------------------------*/ void lpm_drop() { lpm_registered_module_t *module; uint8_t max_pm = LPM_MODE_MAX_SUPPORTED; uint8_t module_pm; clock_time_t next_event; uint32_t domains = LOCKABLE_DOMAINS; if(RTIMER_CLOCK_LT(soc_rtc_get_next_trigger(), RTIMER_NOW() + STANDBY_MIN_DURATION)) { lpm_sleep(); return; } /* Collect max allowed PM permission from interested modules */ for(module = list_head(modules_list); module != NULL; module = module->next) { if(module->request_max_pm) { module_pm = module->request_max_pm(); if(module_pm < max_pm) { max_pm = module_pm; } } } /* Check if any events fired during this process. Last chance to abort */ if(process_nevents()) { return; } /* Drop */ if(max_pm == LPM_MODE_SLEEP) { lpm_sleep(); } else { /* Critical. Don't get interrupted! */ ti_lib_int_master_disable(); /* * Reschedule AON RTC CH1 to fire an event N ticks before the next etimer * event */ next_event = etimer_next_expiration_time(); if(next_event) { next_event = next_event - clock_time(); soc_rtc_schedule_one_shot(AON_RTC_CH1, RTIMER_NOW() + (next_event * (RTIMER_SECOND / CLOCK_SECOND))); } /* * Notify all registered modules that we are dropping to mode X. We do not * need to do this for simple sleep. * * This is a chance for modules to delay us a little bit until an ongoing * operation has finished (e.g. uart TX) or to configure themselves for * deep sleep. * * At this stage, we also collect power domain locks, if any. * The argument to PRCMPowerDomainOff() is a bitwise OR, so every time * we encounter a lock we just clear the respective bits in the 'domains' * variable as required by the lock. In the end the domains variable will * just hold whatever has not been cleared */ for(module = list_head(modules_list); module != NULL; module = module->next) { if(module->shutdown) { module->shutdown(max_pm); } /* Clear the bits specified in the lock */ domains &= ~module->domain_lock; } /* Pat the dog: We don't want it to shout right after we wake up */ watchdog_periodic(); /* Clear unacceptable bits, just in case a lock provided a bad value */ domains &= LOCKABLE_DOMAINS; /* * Freeze the IOs on the boundary between MCU and AON. We only do this if * PERIPH is not needed */ if(domains & PRCM_DOMAIN_PERIPH) { ti_lib_aon_ioc_freeze_enable(); } /* * Among LOCKABLE_DOMAINS, turn off those that are not locked * * If domains is != 0, pass it as-is */ if(domains) { ti_lib_prcm_power_domain_off(domains); } /* * Before entering Deep Sleep, we must switch off the HF XOSC. The HF XOSC * is predominantly controlled by the RF driver. In a build with radio * cycling (e.g. ContikiMAC), the RF driver will request the XOSC before * using the Freq. Synth, and switch back to the RC when it is about to * turn back off. * * If the radio is on, we won't even reach here, and if it's off the HF * clock source should already be the HF RC. * * Nevertheless, request the switch to the HF RC explicitly here. */ oscillators_switch_to_hf_rc(); /* Configure clock sources for MCU and AUX: No clock */ ti_lib_aon_wuc_mcu_power_down_config(AONWUC_NO_CLOCK); ti_lib_aon_wuc_aux_power_down_config(AONWUC_NO_CLOCK); /* Full RAM retention. */ ti_lib_aon_wuc_mcu_sram_config(MCU_RAM0_RETENTION | MCU_RAM1_RETENTION | MCU_RAM2_RETENTION | MCU_RAM3_RETENTION); /* Disable retention of AUX RAM */ ti_lib_aon_wuc_aux_sram_config(false); /* * Always turn off RFCORE, CPU, SYSBUS and VIMS. RFCORE should be off * already */ ti_lib_prcm_power_domain_off(PRCM_DOMAIN_RFCORE | PRCM_DOMAIN_CPU | PRCM_DOMAIN_VIMS | PRCM_DOMAIN_SYSBUS); /* Request JTAG domain power off */ ti_lib_aon_wuc_jtag_power_off(); /* Turn off AUX */ ti_lib_aux_wuc_power_ctrl(AUX_WUC_POWER_OFF); ti_lib_aon_wuc_domain_power_down_enable(); while(ti_lib_aon_wuc_power_status_get() & AONWUC_AUX_POWER_ON); /* Configure the recharge controller */ ti_lib_sys_ctrl_set_recharge_before_power_down(XOSC_IN_HIGH_POWER_MODE); /* * If both PERIPH and SERIAL PDs are off, request the uLDO as the power * source while in deep sleep. */ if(domains == LOCKABLE_DOMAINS) { ti_lib_pwr_ctrl_source_set(PWRCTRL_PWRSRC_ULDO); } /* We are only interested in IRQ energest while idle or in LPM */ ENERGEST_IRQ_RESTORE(irq_energest); ENERGEST_SWITCH(ENERGEST_TYPE_CPU, ENERGEST_TYPE_LPM); /* Sync the AON interface to ensure all writes have gone through. */ ti_lib_sys_ctrl_aon_sync(); /* * Explicitly turn off VIMS cache, CRAM and TRAM. Needed because of * retention mismatch between VIMS logic and cache. We wait to do this * until right before deep sleep to be able to use the cache for as long * as possible. */ ti_lib_prcm_cache_retention_disable(); ti_lib_vims_mode_set(VIMS_BASE, VIMS_MODE_OFF); /* Deep Sleep */ ti_lib_prcm_deep_sleep(); /* * When we reach here, some interrupt woke us up. The global interrupt * flag is off, hence we have a chance to run things here. We will wake up * the chip properly, and then we will enable the global interrupt without * unpending events so the handlers can fire */ wake_up(); ti_lib_int_master_enable(); } }