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 Setup the microcontroller system. * * Initialize the system clock and pins. ***************************************************************************************** */ void SystemInit(void) { /* ************************** * Sub module clock setting ************************** */ syscon_SetIvrefX32WithMask(QN_SYSCON, SYSCON_MASK_DVDD12_SW_EN, MASK_ENABLE); syscon_set_sysclk_src(CLK_XTAL, __XTAL); #if __XTAL == XTAL_32MHz calibration_init(XTAL_32M); #else calibration_init(XTAL_16M); #endif ref_pll_calibration(); clk32k_enable(__32K_TYPE); #if QN_32K_RCO rco_calibration(); #endif // Reset SPI1 module(since the default register value was changed in bootloader) syscon_SetCRSS(QN_SYSCON, SYSCON_MASK_USART1_RST); syscon_SetCRSC(QN_SYSCON, SYSCON_MASK_USART1_RST); /* Disable all peripheral clock, will be enabled in the driver initilization. The next function performs the equivalent effect of a collection of these functions. timer_clock_off(QN_TIMER0); timer_clock_off(QN_TIMER1); timer_clock_off(QN_TIMER2); timer_clock_off(QN_TIMER3); uart_clock_off(QN_UART0); uart_clock_off(QN_UART1); spi_clock_off(QN_SPI0); spi_clock_off(QN_SPI1); flash_clock_off(); gpio_clock_off(); adc_clock_off(); dma_clock_off(); pwm_clock_off(); */ syscon_SetCRSS(QN_SYSCON, SYSCON_MASK_GATING_TIMER0 | SYSCON_MASK_GATING_TIMER1 | SYSCON_MASK_GATING_TIMER2 | SYSCON_MASK_GATING_TIMER3 | SYSCON_MASK_GATING_UART0 | SYSCON_MASK_GATING_UART1 | SYSCON_MASK_GATING_SPI0 | SYSCON_MASK_GATING_SPI1 | SYSCON_MASK_GATING_SPI_AHB | SYSCON_MASK_GATING_GPIO | SYSCON_MASK_GATING_ADC | SYSCON_MASK_GATING_DMA | SYSCON_MASK_GATING_PWM); // calibration changed system clock setting // Configure sytem clock. syscon_set_sysclk_src(CLK_XTAL, __XTAL); syscon_set_ahb_clk(__AHB_CLK); syscon_set_apb_clk(__APB_CLK); syscon_set_ble_clk(__BLE_CLK); syscon_set_timer_clk(__TIMER_CLK); syscon_set_usart_clk((uint32_t)QN_UART0, __USART_CLK); syscon_set_usart_clk((uint32_t)QN_UART1, __USART_CLK); /* ************************** * IO configuration ************************** */ SystemIOCfg(); /* ************************** * Peripheral setting ************************** */ }
/** **************************************************************************************** * @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 } }
/** **************************************************************************************** * @brief Setup the microcontroller system. * * Initialize the system clock and pins. ***************************************************************************************** */ void SystemInit(void) { /* ************************** * Sub module clock setting ************************** */ syscon_SetIvrefX32WithMask(QN_SYSCON, SYSCON_MASK_DVDD12_SW_EN, MASK_ENABLE); syscon_set_sysclk_src(CLK_XTAL, __XTAL); #if __XTAL == XTAL_32MHz calibration_init(XTAL_32M); #else calibration_init(XTAL_16M); #endif ref_pll_calibration(); clk32k_enable(__32K_TYPE); #if QN_32K_RCO rco_calibration(); #endif // Disable all peripheral clock, will be enabled in the driver initilization. timer_clock_off(QN_TIMER0); timer_clock_off(QN_TIMER1); timer_clock_off(QN_TIMER2); timer_clock_off(QN_TIMER3); uart_clock_off(QN_UART0); uart_clock_off(QN_UART1); spi_clock_off(QN_SPI0); usart_reset((uint32_t) QN_SPI1); spi_clock_off(QN_SPI1); flash_clock_off(); gpio_clock_off(); adc_clock_off(); dma_clock_off(); pwm_clock_off(); // calibration will change system clock setting // Configure sytem clock. syscon_set_sysclk_src(CLK_XTAL, __XTAL); syscon_set_ahb_clk(__AHB_CLK); syscon_set_apb_clk(__APB_CLK); syscon_set_ble_clk(__BLE_CLK); syscon_set_timer_clk(__TIMER_CLK); syscon_set_usart_clk((uint32_t)QN_UART0, __USART_CLK); syscon_set_usart_clk((uint32_t)QN_UART1, __USART_CLK); /* ************************** * IO configuration ************************** */ SystemIOCfg(); /* ************************** * Peripheral setting ************************** */ }
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 }