static void rtc_example_callback() { /* Log the interrupt event. */ SOC_WATCH_LOG_EVENT(SOCW_EVENT_INTERRUPT, QM_IRQ_RTC_0_INT_VECTOR); /* Invert On-board LED. */ led_flip(BOARD_LED_PIN); ++rtc_tick; /* Reschedule next tick. */ qm_rtc_set_alarm(QM_RTC_0, (QM_RTC[QM_RTC_0]->rtc_ccvr + (QM_RTC_ALARM_SECOND(CLK_RTC_DIV_1) / 2))); }
static void print_accel_callback(void) { bmc150_accel_t accel = {0}; qm_rc_t rc; rc = bmc150_read_accel(&accel); QM_PRINTF("rc %d x %d y %d z %d\n", rc, accel.x, accel.y, accel.z); #if (__IPP_ENABLED__) print_axis_stats(accel.z); #endif qm_rtc_set_alarm(QM_RTC_0, (QM_RTC[QM_RTC_0].rtc_ccvr + ALARM)); }
static int rtc_qmsi_set_alarm(struct device *dev, u8_t chan_id, const struct counter_alarm_cfg *alarm_cfg) { qm_rtc_config_t qm_cfg; int result = 0; qm_cfg.init_val = 0; qm_cfg.alarm_en = 1; qm_cfg.alarm_val = alarm_cfg->ticks; user_cb = alarm_cfg->callback; /* Casting callback type due different input parameter from QMSI * compared aganst the Zephyr callback from void cb(struct device *dev) * to void cb(void *) */ qm_cfg.callback = rtc_callback; qm_cfg.callback_data = (void *)alarm_cfg; /* Set prescaler value. Ideally, the divider should come from struct * rtc_config instead. It's safe to use RTC_DIVIDER here for now since * values defined by clk_rtc_div and by QMSI's clk_rtc_div_t match for * both D2000 and SE. */ qm_cfg.prescaler = (clk_rtc_div_t)CONFIG_RTC_PRESCALER - 1; if (IS_ENABLED(CONFIG_RTC_QMSI_API_REENTRANCY)) { k_sem_take(RP_GET(dev), K_FOREVER); } if (qm_rtc_set_config(QM_RTC_0, &qm_cfg)) { result = -EIO; } if (IS_ENABLED(CONFIG_RTC_QMSI_API_REENTRANCY)) { k_sem_give(RP_GET(dev)); } k_busy_wait(60); qm_rtc_set_alarm(QM_RTC_0, alarm_cfg->ticks); return result; }
/* Low power app example */ int main(void) { /* Setup the RTC to get out of sleep mode. deep sleep will require an */ /* analog comparator interrupt to wake up the system. */ /* Variables */ uint32_t pmux_sel_save[2], pmux_in_en_save, pmux_pullup_save; qm_ac_config_t ac_cfg; qm_rtc_config_t rtc_cfg; QM_PUTS("Low power mode example."); clk_periph_enable(CLK_PERIPH_RTC_REGISTER | CLK_PERIPH_CLK); /* Initialise RTC configuration. */ rtc_cfg.init_val = 0; rtc_cfg.alarm_en = 1; rtc_cfg.alarm_val = QM_RTC_ALARM_SECOND; rtc_cfg.callback = rtc_example_callback; qm_rtc_set_config(QM_RTC_0, &rtc_cfg); qm_irq_request(QM_IRQ_RTC_0, qm_rtc_isr_0); QM_PUTS("CPU Halt."); /* Halt the CPU, RTC alarm will wake me up. */ cpu_halt(); QM_PUTS("CPU Halt wakeup."); /* Set another alarm one minute from now. */ qm_rtc_set_alarm(QM_RTC_0, QM_RTC[QM_RTC_0].rtc_ccvr + QM_RTC_ALARM_SECOND); QM_PUTS("Go to sleep."); /* Go to sleep, RTC will wake me up. */ soc_sleep(); QM_PUTS("Wake up from sleep."); /* Physical step at this stage to raise the V on the comparator pin. */ /* Go to deep sleep, a comparator should wake me up. */ QM_PUTS("Go to deep sleep."); ac_cfg.reference = BIT(WAKEUP_COMPARATOR_PIN); /* Ref internal voltage */ ac_cfg.polarity = 0x0; /* Fire if greater than ref (high level) */ ac_cfg.power = BIT(WAKEUP_COMPARATOR_PIN); /* Normal operation mode */ ac_cfg.int_en = BIT(WAKEUP_COMPARATOR_PIN); /* Enable comparator */ ac_cfg.callback = ac_example_callback; qm_ac_set_config(&ac_cfg); qm_irq_request(QM_IRQ_AC, qm_ac_isr); /* * Comparator pin will fire an interrupt when the input voltage is * greater than the reference voltage (0.95V). */ /* * In order to minimise power, pmux_sel must be set to 0, input enable * must be cleared for any pins not expecting to be used to wake the * SoC from deep sleep mode, in this example we are using AC 6. */ pmux_sel_save[0] = QM_SCSS_PMUX->pmux_sel[0]; pmux_sel_save[1] = QM_SCSS_PMUX->pmux_sel[1]; pmux_in_en_save = QM_SCSS_PMUX->pmux_in_en[0]; pmux_pullup_save = QM_SCSS_PMUX->pmux_pullup[0]; QM_SCSS_PMUX->pmux_sel[0] = QM_SCSS_PMUX->pmux_sel[1] = 0; QM_SCSS_PMUX->pmux_in_en[0] = BIT(WAKEUP_COMPARATOR_PIN); QM_SCSS_PMUX->pmux_pullup[0] = 0; /* Mux out comparator */ qm_pmux_select(QM_PIN_ID_6, QM_PMUX_FN_1); qm_pmux_input_en(QM_PIN_ID_6, true); soc_deep_sleep(); /* Restore previous pinmuxing settings. */ QM_SCSS_PMUX->pmux_sel[0] = pmux_sel_save[0]; QM_SCSS_PMUX->pmux_sel[1] = pmux_sel_save[1]; QM_SCSS_PMUX->pmux_in_en[0] = pmux_in_en_save; QM_SCSS_PMUX->pmux_pullup[0] = pmux_pullup_save; QM_PUTS("Wake up from deep sleep."); return 0; }
int main(void) { qm_rtc_config_t rtc_cfg; uint32_t aonc_start; uint32_t rtc_trigger; /* Initialise RTC configuration. */ rtc_cfg.init_val = 0; /* Set initial value to 0. */ rtc_cfg.alarm_en = 1; /* Enable alarm. */ rtc_cfg.alarm_val = QM_RTC_ALARM_SECOND(CLK_RTC_DIV_1); /* 1s alarm. */ rtc_cfg.callback = NULL; rtc_cfg.callback_data = NULL; rtc_cfg.prescaler = CLK_RTC_DIV_1; qm_rtc_set_config(QM_RTC_0, &rtc_cfg); /* * The RTC clock resides in a different clock domain * to the system clock. * It takes 3-4 RTC ticks for a system clock write to propagate * to the RTC domain. * If an entry to sleep is initiated without waiting for the * transaction to complete the SOC will not wake from sleep. */ aonc_start = QM_AONC[QM_AONC_0]->aonc_cnt; while (QM_AONC[QM_AONC_0]->aonc_cnt - aonc_start < RTC_SYNC_CLK_COUNT) { } QM_IR_UNMASK_INT(QM_IRQ_RTC_0_INT); QM_IRQ_REQUEST(QM_IRQ_RTC_0_INT, qm_rtc_0_isr); /* * Enable LPSS by the Sensor Subsystem. * This will clock gate sensor peripherals. */ qm_ss_power_soc_lpss_enable(); /* * Signal to the x86 core that the Sensor Subsystem * is ready to enter LPSS mode. */ QM_SCSS_GP->gps2 |= QM_SCSS_GP_SENSOR_READY; rtc_trigger = switch_rtc_to_level(); /* Go to LPSS, RTC will wake the Sensor Subsystem up. */ qm_ss_power_cpu_ss2(); /* Log the interrupt event in soc_watch. */ SOC_WATCH_LOG_EVENT(SOCW_EVENT_INTERRUPT, QM_IRQ_RTC_0_INT_VECTOR); restore_rtc_trigger(rtc_trigger); /* Clear the SENSOR_READY flag in General Purpose Sticky Register 2. */ QM_SCSS_GP->gps2 &= ~QM_SCSS_GP_SENSOR_READY; /* * Disable LPSS. * This will restore clock gating of sensor peripherals. */ qm_ss_power_soc_lpss_disable(); /* Core still in C2 mode. */ qm_gpio_clear_pin(QM_GPIO_0, PIN_OUT); clk_sys_udelay(GPIO_TOGGLE_DELAY); qm_gpio_set_pin(QM_GPIO_0, PIN_OUT); clk_sys_udelay(GPIO_TOGGLE_DELAY); qm_gpio_clear_pin(QM_GPIO_0, PIN_OUT); /* Set another alarm 1 second from now. */ qm_rtc_set_alarm(QM_RTC_0, QM_RTC[QM_RTC_0]->rtc_ccvr + (QM_RTC_ALARM_SECOND(CLK_RTC_DIV_1))); /* * The RTC clock resides in a different clock domain * to the system clock. * It takes 3-4 RTC ticks for a system clock write to propagate * to the RTC domain. * If an entry to sleep is initiated without waiting for the * transaction to complete the SOC will not wake from sleep. */ aonc_start = QM_AONC[QM_AONC_0]->aonc_cnt; while (QM_AONC[QM_AONC_0]->aonc_cnt - aonc_start < RTC_SYNC_CLK_COUNT) { } /* * Enable LPSS by the Sensor Subsystem. * This will clock gate sensor peripherals. */ qm_ss_power_soc_lpss_enable(); /* * Signal to the x86 core that the Sensor Subsystem * is ready to enter LPSS mode. */ QM_SCSS_GP->gps2 |= QM_SCSS_GP_SENSOR_READY; rtc_trigger = switch_rtc_to_level(); /* Go to LPSS, RTC will wake the Sensor Subsystem up. */ qm_ss_power_cpu_ss2(); /* Log the interrupt event in soc_watch. */ SOC_WATCH_LOG_EVENT(SOCW_EVENT_INTERRUPT, QM_IRQ_RTC_0_INT_VECTOR); restore_rtc_trigger(rtc_trigger); /* Clear the SENSOR_READY flag in General Purpose Sticky Register 2. */ QM_SCSS_GP->gps2 &= ~QM_SCSS_GP_SENSOR_READY; /* * Disable LPSS. * This will restore clock gating of sensor peripherals. */ qm_ss_power_soc_lpss_disable(); /* Core still in C2LP mode. */ qm_gpio_clear_pin(QM_GPIO_0, PIN_OUT); clk_sys_udelay(GPIO_TOGGLE_DELAY); qm_gpio_set_pin(QM_GPIO_0, PIN_OUT); clk_sys_udelay(GPIO_TOGGLE_DELAY); qm_gpio_clear_pin(QM_GPIO_0, PIN_OUT); /* Trigger soc_watch flush. */ SOC_WATCH_TRIGGER_FLUSH(); return 0; }