/** **************************************************************************************** * @brief Set sleep timer wakeup * @param[in] clk_src 32KHz clock source * @description * This function is used to set MCU wakeup by sleep timer. ***************************************************************************************** */ void wakeup_by_sleep_timer(int clk_src) { uint32_t dis_type, en_type; uint32_t pd_type; // Enable sleep timer wakeup syscon_SetPGCR2WithMask(QN_SYSCON, SYSCON_MASK_OSC_WAKEUP_EN, MASK_ENABLE); sleep_env.wakeup_by_sleeptimer = 1; if (clk_src == RCO_32K) { // Enable 32k RCO dis_type = SYSCON_MASK_DIS_RCO; en_type = MASK_ENABLE; pd_type = SYSCON_MASK_PD_XTAL32; sleep_env.retention_modules |= SYSCON_MASK_DIS_RCO; } else { // Enable 32k XTAL dis_type = SYSCON_MASK_DIS_XTAL32; en_type = MASK_DISABLE; pd_type = SYSCON_MASK_PD_RCO; sleep_env.retention_modules |= SYSCON_MASK_DIS_XTAL32; } syscon_SetPGCR1WithMask(QN_SYSCON, dis_type, MASK_DISABLE); syscon_SetCMDCRWithMask(QN_SYSCON, SYSCON_MASK_SEL_CLK_32K, en_type); syscon_SetPGCR0WithMask(QN_SYSCON, SYSCON_MASK_PD_XTAL32|SYSCON_MASK_PD_RCO, pd_type); }
static int app_32k_xtal_wakeup_timer(ke_msg_id_t const msgid, void const *param, ke_task_id_t const dest_id, ke_task_id_t const src_id) { // disable schmitt trigger in 32.768KHz buffer syscon_SetIvrefX32WithMask(QN_SYSCON, SYSCON_MASK_X32SMT_EN, MASK_DISABLE); syscon_SetIvrefX32WithMask(QN_SYSCON, SYSCON_MASK_X32ICTRL, 16); // switch 32k RCO to 32k XTAL syscon_SetCMDCRWithMask(QN_SYSCON, SYSCON_MASK_SEL_CLK_32K, MASK_DISABLE); syscon_SetPGCR1WithMask(QN_SYSCON, SYSCON_MASK_DIS_RCO, MASK_ENABLE); // allow ble sleep enable_ble_sleep(true); return (KE_MSG_CONSUMED); }
/** **************************************************************************************** * @brief Wakeup 32k XTAL * @description * This function will be called after waking up from deep sleep mode. ***************************************************************************************** */ void wakeup_32k_xtal_switch_clk(void) { if(sleep_env.deep_sleep) { // prevent ble sleep enable_ble_sleep(false); // ensable schmitt trigger in 32.768KHz buffer syscon_SetIvrefX32WithMask(QN_SYSCON, SYSCON_MASK_X32SMT_EN, MASK_ENABLE); // Set 32.768KHz xtal higher current, that can let the 32k xtal stable fastly (decrease stable time). syscon_SetIvrefX32WithMask(QN_SYSCON, SYSCON_MASK_X32ICTRL, 32); // switch to 32k RCO syscon_SetPGCR1WithMask(QN_SYSCON, SYSCON_MASK_DIS_RCO, MASK_DISABLE); #if (QN_PMU_VOLTAGE) delay(10); #else delay(300); #endif syscon_SetCMDCRWithMask(QN_SYSCON, SYSCON_MASK_SEL_CLK_32K, MASK_ENABLE); } }
/** **************************************************************************************** * @brief Init sleep power down modules * @description * This function is used to init MCU sleep mode. ***************************************************************************************** */ void sleep_init(void) { // -------------------------------------------- // sleep // -------------------------------------------- //23 : PD_XTAL32 //10 : PD_RCO // 7 : PD_MEM7 // 6 : PD_MEM6 // 5 : PD_MEM5 // 4 : PD_MEM4 // 3 : PD_MEM3 // 2 : PD_MEM2 // 1 : PD_MEM1 // 0 : PL_VREG_D sleep_env.retention_modules |= QN_MEM_RETENTION; // power down all module in sleep except retention modules #if (defined(QN_9020_B2) || defined(QN_9020_B1)) syscon_SetPGCR0WithMask(QN_SYSCON, 0xF7FFFCFE, (0xFFFFFC00 | QN_MEM_UNRETENTION)); #elif defined(QN_9020_B0) syscon_SetPGCR0WithMask(QN_SYSCON, 0xFFFFFCFE, (0xFFFFFC00 | QN_MEM_UNRETENTION)); #endif // power down all unretention memory all the time. // if you want to use the unretention memory in the active mode, remove the following snippet. syscon_SetPGCR1WithMask(QN_SYSCON, (SYSCON_MASK_DIS_MEM1 | SYSCON_MASK_DIS_MEM2 | SYSCON_MASK_DIS_MEM3 | SYSCON_MASK_DIS_MEM4 | SYSCON_MASK_DIS_MEM5 | SYSCON_MASK_DIS_MEM6 | SYSCON_MASK_DIS_MEM7), QN_MEM_UNRETENTION); }
/** **************************************************************************************** * @brief Enter low power mode * @param[in] en enabled peripheral at low power mode * @description * This function is used to set MCU entering into low power mode. ***************************************************************************************** */ void enter_low_power_mode(uint32_t en) { PGCR1_restore = syscon_GetPGCR1(QN_SYSCON); syscon_SetPGCR2WithMask(QN_SYSCON, SYSCON_MASK_PD_STATE|SYSCON_MASK_PMUENABLE, MASK_DISABLE); low_power_mode_en = 1; // set system clock to 32K syscon_set_sysclk_src(CLK_LOW_32K, __32K_TYPE); syscon_SetCMDCRWithMask(QN_SYSCON, SYSCON_MASK_AHB_DIV_BYPASS|SYSCON_MASK_APB_DIV_BYPASS, MASK_ENABLE); uint32_t mask; // power off all not needed modules mask = SYSCON_MASK_DIS_OSC | SYSCON_MASK_DIS_BG | SYSCON_MASK_DIS_V2I | SYSCON_MASK_DIS_BUCK | SYSCON_MASK_DIS_VREG_A | SYSCON_MASK_DIS_VREG_D | SYSCON_MASK_DIS_XTAL #if QN_32K_RCO == TRUE | SYSCON_MASK_DIS_XTAL32 #endif | SYSCON_MASK_DIS_REF_PLL | SYSCON_MASK_DIS_LO_VCO | SYSCON_MASK_DIS_LO_PLL | SYSCON_MASK_DIS_PA | SYSCON_MASK_DIS_LNA | SYSCON_MASK_DIS_LNA_PKDET | SYSCON_MASK_DIS_MIXER | SYSCON_MASK_DIS_PPF_PKDET | SYSCON_MASK_DIS_PPF | SYSCON_MASK_DIS_RX_PKDET | SYSCON_MASK_DIS_RX_ADC | SYSCON_MASK_DIS_SAR_ADC #if (QN_32K_RCO == FALSE) | SYSCON_MASK_DIS_RCO #endif | SYSCON_MASK_DIS_MEM7 | SYSCON_MASK_DIS_MEM6 | SYSCON_MASK_DIS_MEM5 | SYSCON_MASK_DIS_MEM4 | SYSCON_MASK_DIS_MEM3 | SYSCON_MASK_DIS_MEM2 | SYSCON_MASK_DIS_MEM1 | SYSCON_MASK_DIS_SAR_BUF ; syscon_SetPGCR1WithMask(QN_SYSCON, mask&(~QN_MEM_RETENTION), MASK_ENABLE); #if 0 // gating all not needed modules mask = SYSCON_MASK_GATING_TIMER3 | SYSCON_MASK_GATING_TIMER2 #if QN_32K_RCO == FALSE | SYSCON_MASK_GATING_TIMER1 #endif | SYSCON_MASK_GATING_TIMER0 | SYSCON_MASK_GATING_UART1 | SYSCON_MASK_GATING_UART0 | SYSCON_MASK_GATING_SPI1 | SYSCON_MASK_GATING_SPI0 //| SYSCON_MASK_GATING_32K_CLK | SYSCON_MASK_GATING_SPI_AHB //| SYSCON_MASK_GATING_GPIO | SYSCON_MASK_GATING_ADC | SYSCON_MASK_GATING_DMA //| SYSCON_MASK_GATING_BLE_AHB | SYSCON_MASK_GATING_PWM ; syscon_SetCRSS(QN_SYSCON, mask&(~en)); #endif // set PMU to 0.8V, b1 should set PMU after OSC disabled syscon_SetPGCR2WithMask(QN_SYSCON, SYSCON_MASK_DVDD12_PMU_SET, MASK_ENABLE); }
/** **************************************************************************************** * @brief Enable sleep mode * @param[in] mode sleep mode * @param[in] iconfig wakeup interrupt config * @param[in] callback callback after wakeup * @description * This function is used to set MCU into sleep mode, before enter sleep, wakeup source should be set. ***************************************************************************************** */ void enter_sleep(enum SLEEP_MODE mode, uint32_t iconfig, void (*callback)(void)) { if (mode == SLEEP_CPU_CLK_OFF) { // -------------------------------------------- // cpu clock disable // -------------------------------------------- // Ensure we use deep SLEEP - SLEEPDEEP should be set // SCR[2] = SLEEPDEEP SCB->SCR |= (1UL << 2); // set pd state to deep gating syscon_SetPGCR2WithMask(QN_SYSCON, SYSCON_MASK_PD_STATE|SYSCON_MASK_PMUENABLE, MASK_DISABLE); GLOBAL_INT_DISABLE(); #if SLEEP_CONFIG_EN == TRUE NVIC->ISER[0] = iconfig; #endif // Wait For Interrupt __WFI(); // Enter sleep mode // Wakeup when interrupt is triggered GLOBAL_INT_RESTORE(); // TODO } else if ((mode == SLEEP_NORMAL) || (mode == SLEEP_DEEP)) { #if QN_LOW_POWER_MODE_EN==TRUE enter_low_power_mode(0); // -------------------------------------------- // cpu clock disable // -------------------------------------------- // Ensure we use deep SLEEP - SLEEPDEEP should be set // SCR[2] = SLEEPDEEP SCB->SCR |= (1UL << 2); #else // -------------------------------------------- // sleep or deep sleep // -------------------------------------------- #ifdef BLE_PRJ // Save configuration before power down save_ble_setting(); #endif #if (defined(QN_9020_B1) && QN_PMU_VOLTAGE) // Switch off REF PLL power syscon_SetPGCR1WithMask(QN_SYSCON, SYSCON_MASK_DIS_REF_PLL, MASK_ENABLE); #endif // switch to internal 20MHz syscon_SetCMDCRWithMask(QN_SYSCON, SYSCON_MASK_CLK_MUX, CLK_INT_20M<<SYSCON_POS_CLK_MUX); if(mode == SLEEP_NORMAL) { #if (QN_DEEP_SLEEP_EN) sleep_env.deep_sleep = false; #endif // power down all module in sleep except 32K and retention memory syscon_SetPGCR0WithMask(QN_SYSCON, sleep_env.retention_modules|0x00000001, 0x00000001); } else { #if (QN_DEEP_SLEEP_EN) sleep_env.deep_sleep = true; #endif // power down all module in deep sleep except retention memory #if (defined(QN_9020_B2) || defined(QN_9020_B1)) syscon_SetPGCR0WithMask(QN_SYSCON, 0xF7FFFCFF, 0xFFFFFC01|~sleep_env.retention_modules); #elif defined(QN_9020_B0) syscon_SetPGCR0WithMask(QN_SYSCON, 0xFFFFFCFF, 0xFFFFFC01|~sleep_env.retention_modules); #endif } #if (defined(QN_9020_B0) && QN_PMU_VOLTAGE) syscon_SetCMDCRWithMask(QN_SYSCON, SYSCON_MASK_AHB_DIV_BYPASS|SYSCON_MASK_AHB_DIVIDER, (0xf<<SYSCON_POS_AHB_DIVIDER)); #endif // Ensure we use deep SLEEP - SLEEPDEEP should be set // SCR[2] = SLEEPDEEP SCB->SCR |= (1UL << 2); // set pd state to sleep #if !QN_PMU_VOLTAGE syscon_SetPGCR2WithMask(QN_SYSCON, SYSCON_MASK_PD_STATE|SYSCON_MASK_DVDD12_PMU_SET|SYSCON_MASK_PMUENABLE, MASK_ENABLE); #else syscon_SetPGCR2WithMask(QN_SYSCON, SYSCON_MASK_PD_STATE|SYSCON_MASK_PMUENABLE, MASK_ENABLE); #endif syscon_SetIvrefX32WithMask(QN_SYSCON, SYSCON_MASK_VREG12_A|SYSCON_MASK_VREG12_D|SYSCON_MASK_DVDD12_SW_EN, (0x0 << SYSCON_POS_VREG12_A)|(0x0 << SYSCON_POS_VREG12_D)); #endif // QN_LOW_POWER_MODE_EN==TRUE #if SLEEP_CONFIG_EN == TRUE NVIC->ICPR[0] = 0x00000020; // clear OSC_EN pending flag NVIC->ISER[0] = iconfig; #endif // Wait For Interrupt __WFI(); // Enter sleep mode // Wakeup when sleep timer, comparator or gpio is triggered // Disable interrupt in the wakeup procedure. NVIC->ICER[0] = iconfig; #if QN_LOW_POWER_MODE_EN==TRUE #ifdef BLE_PRJ restore_from_low_power_mode(NULL); #else restore_from_low_power_mode(callback); #endif #else // 1.2V syscon_SetIvrefX32WithMask(QN_SYSCON, SYSCON_MASK_VREG12_A|SYSCON_MASK_VREG12_D|SYSCON_MASK_DVDD12_SW_EN, (0x1 << SYSCON_POS_VREG12_A)|(0x0 << SYSCON_POS_VREG12_D)|SYSCON_MASK_DVDD12_SW_EN); #if (defined(QN_9020_B0) && QN_PMU_VOLTAGE) syscon_SetCMDCRWithMask(QN_SYSCON, SYSCON_MASK_AHB_DIV_BYPASS, MASK_ENABLE); #endif syscon_SetPGCR2WithMask(QN_SYSCON, SYSCON_MASK_PD_STATE|SYSCON_MASK_DVDD12_PMU_SET, MASK_DISABLE); #if SLEEP_CALLBACK_EN == TRUE if (callback != NULL) { callback(); } #endif #if (defined(QN_9020_B0) && QN_PMU_VOLTAGE) syscon_set_ahb_clk(__AHB_CLK); #endif // 16MHz/32MHz XTAL is ready while (!(syscon_GetBLESR(QN_SYSCON) & SYSCON_MASK_CLK_RDY)) { // XTAL shall be ready before BLE wakeup if(check_ble_wakeup()) { // In this case XTAL wakeup duration is larger than setting. // The parameter 'Oscillator wake-up time' in the NVDS should be revised. #if (QN_DBG_INFO) set_dbg_info(QN_DBG_INFO_XTAL_WAKEUP_DURATION); #endif } } syscon_SetCMDCRWithMask(QN_SYSCON, SYSCON_MASK_CLK_MUX, CLK_XTAL<<SYSCON_POS_CLK_MUX); #endif // QN_LOW_POWER_MODE_EN==TRUE #if ((defined(QN_9020_B2) || defined(QN_9020_B1)) && defined(BLE_PRJ)) sleep_post_process(); #endif } }
int main (void) { SystemInit(); #if ACMP_TEST == TRUE // -------------------------------------------- // analog comparator // -------------------------------------------- acmp_io_config(); #if CONFIG_ENABLE_DRIVER_ACMP0==TRUE analog_pin_enable(AIN0, MASK_ENABLE); analog_pin_enable(AIN1, MASK_ENABLE); acmp0_done = 0; // comparator0 test //comparator_init(ACMP0, VDD_1, ACMPO_0_GEN_INT, acmp0_test_cb); //comparator_init(ACMP0, VDD_8, ACMPO_1_GEN_INT, acmp0_test_cb); //comparator_init(ACMP0, VDD_15, ACMPO_0_GEN_INT, acmp0_test_cb); comparator_init(ACMP0, EXT_REF, ACMPO_1_GEN_INT, acmp0_test_cb); while (acmp0_done == 0); #endif #if CONFIG_ENABLE_DRIVER_ACMP1==TRUE analog_pin_enable(AIN2, MASK_ENABLE); analog_pin_enable(AIN3, MASK_ENABLE); acmp1_done = 0; // comparator1 test //comparator_init(ACMP1, VDD_1, ACMPO_0_GEN_INT, acmp1_test_cb); comparator_init(ACMP1, VDD_8, ACMPO_0_GEN_INT, acmp1_test_cb); //comparator_init(ACMP1, VDD_15, ACMPO_0_GEN_INT, acmp1_test_cb); while (acmp1_done == 0); #endif #endif #if RF_SWEEP_TEST == TRUE // -------------------------------------------- // analog RF // -------------------------------------------- int mask = SYSCON_MASK_DIS_REF_PLL | SYSCON_MASK_DIS_LO_VCO | SYSCON_MASK_DIS_LO_PLL | SYSCON_MASK_DIS_PA; syscon_SetPGCR1WithMask(QN_SYSCON, mask, MASK_DISABLE); rf_enable(RF_TX, MASK_ENABLE, MASK_ENABLE, 0x1F); rf_tx_power_level_set(TX_GAIN_LEVLE10); for (int i = 0; i < 40; i++) { rf_set_freq(RF_TX, i); delay(10000); } #endif while (1) /* Loop forever */ { } }
int main (void) { SystemInit(); #if 0 if (0x00000004 & inp32(0x40000038)) { outp32(0x40000038, 0x80000000); } else { Led_flash(); while(1); } #endif /* Initialize GPIO */ gpio_init(cb_gpio); #if TEST_SLEEP_NORMAL == TRUE // -------------------------------------------- // sleep wakeup // -------------------------------------------- //set all pin to gpio syscon_SetPMCR0(QN_SYSCON, 0x00000000); syscon_SetPMCR1(QN_SYSCON, 0x00000000); //set all gpio input gpio_set_direction_field(GPIO_PIN_ALL, GPIO_INPUT); gpio_write_pin_field(GPIO_PIN_ALL, (uint32_t)GPIO_HIGH); // pin pull ( 00 : High-Z, 01 : Pull-down, 10 : Pull-up, 11 : Reserved ) syscon_SetPPCR0(QN_SYSCON, 0xAAAA5AAA); // SWD pull-down save 20uA syscon_SetPPCR1(QN_SYSCON, 0x2AAAAAAA); // power down BUCK needed syscon_SetIvrefX32WithMask(QN_SYSCON, SYSCON_MASK_BUCK_BYPASS|SYSCON_MASK_BUCK_DPD, MASK_ENABLE); // power down Flash syscon_SetPGCR2WithMask(QN_SYSCON, SYSCON_MASK_FLASH_VCC_EN, MASK_DISABLE); // enable dbg power down syscon_SetPGCR2WithMask(QN_SYSCON, SYSCON_MASK_DBGPMUENABLE, MASK_ENABLE); // dis sar adc buffer syscon_SetPGCR1WithMask(QN_SYSCON, SYSCON_MASK_DIS_SAR_BUF, MASK_ENABLE); Led_flash(); do { delay(10); } while (gpio_read_pin(GPIO_P14) == GPIO_HIGH); sleep_init(); wakeup_by_sleep_timer(__32K_TYPE); wakeup_by_gpio(GPIO_P15, GPIO_WKUP_BY_LOW); do { gpio_set_direction(GPIO_P01, GPIO_INPUT); //enter_sleep(SLEEP_NORMAL, WAKEUP_BY_GPIO, Led_flash); if (wakeup_from_sleeptimer) { sleep_timer_set(32000); wakeup_from_sleeptimer = 0; #if QN_32K_RCO == TRUE clock_32k_correction_enable(clock_32k_correction_cb); #endif } #if QN_32K_RCO == TRUE if (gpio_sleep_allowed() && !dev_get_bf()) #else if (gpio_sleep_allowed()) #endif enter_sleep(SLEEP_NORMAL, WAKEUP_BY_OSC_EN|WAKEUP_BY_GPIO, Led_flash); } while(1); #endif #if TEST_SLEEP_DEEP == TRUE // -------------------------------------------- // deep sleep wakeup // -------------------------------------------- //set all pin to gpio syscon_SetPMCR0(QN_SYSCON, 0x00000000); syscon_SetPMCR1(QN_SYSCON, 0x00000000); //set all gpio input gpio_set_direction_field(GPIO_PIN_ALL, (uint32_t)GPIO_INPUT); gpio_write_pin_field(GPIO_PIN_ALL, (uint32_t)GPIO_HIGH); // pin pull ( 00 : High-Z, 01 : Pull-down, 10 : Pull-up, 11 : Reserved ) syscon_SetPPCR0(QN_SYSCON, 0xAAAA5AAA); // SWD pull-down save 20uA syscon_SetPPCR1(QN_SYSCON, 0x2AAAAAAA); // power down BUCK needed syscon_SetIvrefX32WithMask(QN_SYSCON, SYSCON_MASK_BUCK_BYPASS|SYSCON_MASK_BUCK_DPD, MASK_ENABLE); // power down Flash syscon_SetPGCR2WithMask(QN_SYSCON, SYSCON_MASK_FLASH_VCC_EN, MASK_DISABLE); // enable dbg power down syscon_SetPGCR2WithMask(QN_SYSCON, SYSCON_MASK_DBGPMUENABLE, MASK_ENABLE); // dis sar adc buffer syscon_SetPGCR1WithMask(QN_SYSCON, SYSCON_MASK_DIS_SAR_BUF, MASK_ENABLE); Led_flash(); do { delay(10); } while (gpio_read_pin(GPIO_P14) == GPIO_HIGH); sleep_init(); do { gpio_set_direction(GPIO_P01, GPIO_INPUT); wakeup_by_gpio(GPIO_P15, GPIO_WKUP_BY_CHANGE); enter_sleep(SLEEP_DEEP, WAKEUP_BY_GPIO, Led_flash); } while(1); #endif #if TEST_SLEEP_CPU_CLK_OFF == TRUE // -------------------------------------------- // clock gating // -------------------------------------------- // Set timer 0 wakeup timer_init(QN_TIMER0, NULL); timer_config(QN_TIMER0, TIMER_PSCAL_DIV, TIMER_COUNT_MS(1000, TIMER_PSCAL_DIV)); timer_enable(QN_TIMER0, MASK_ENABLE); sleep_init(); do { enter_sleep(SLEEP_CPU_CLK_OFF, WAKEUP_BY_TIMER0, NULL); Led_flash(); } while(1); #endif }