4 Replies Latest reply on May 26, 2016 2:57 AM by Pratik_PP

    Intel Quark D2000: Delay function not working after wake up

    Pratik_PP

      Hello, I want to know if we have to separately restore the system clock after microcontroller wake up from sleep? If yes, the How?

      clk_sys_udelay(DELAY) function not providing delay after system wake- up.

        • 1. Re: Intel Quark D2000: Delay function not working after wake up
          Intel_Peter

          Hello Pratik__PP,

           

          Could you please provide us a simple example/code of when this behavior is happening? We would like to see what is going on the board at the time and to replicate the behavior.

           

          Peter.

          • 2. Re: Intel Quark D2000: Delay function not working after wake up
            Pratik_PP

            Hello Peter, kindly refer the code below. Here the system will come out of sleep after 30sec. Kindly observe the delay provided for LED blinking after wake-up.

             

            #include "qm_common.h"

            #include "qm_power.h"

            #include "qm_rtc.h"

            #include "qm_interrupt.h"

            #include "qm_soc_regs.h"

            #include "qm_gpio.h"

            #include "qm_scss.h"

             

             

            #define LED_BIT 24     /*LED*/

            #define PIN_INTR 2     /*Switch on D2000 Dev Board*/

            #define DELAY 300000UL

             

            static void rtc_example_callback();

            static void gpio_example_callback();

             

             

            static qm_gpio_port_config_t cfg1;

            volatile unsigned char flag = 0;

             

            int main(void)

            {

            qm_rtc_config_t rtc_cfg;

            cfg1.direction = BIT(LED_BIT);

            qm_gpio_set_config(QM_GPIO_0, &cfg1);

             

             

             

             

            clk_periph_enable(CLK_PERIPH_RTC_REGISTER | CLK_PERIPH_CLK);

             

            /*  Initialize RTC configuration. */

            rtc_cfg.init_val = 0;

            rtc_cfg.alarm_en = 1;

            rtc_cfg.alarm_val = QM_RTC_ALARM_MINUTE/2;

            rtc_cfg.callback = rtc_example_callback;

             

             

            qm_gpio_set_pin(QM_GPIO_0, LED_BIT);

            clk_sys_udelay(DELAY);

            clk_sys_udelay(DELAY);

            clk_sys_udelay(DELAY);

            qm_gpio_clear_pin(QM_GPIO_0, LED_BIT);

            clk_sys_udelay(DELAY);

            clk_sys_udelay(DELAY);

            clk_sys_udelay(DELAY);

             

            /* Set  alarm for 30sec from now. */

            qm_rtc_set_alarm(QM_RTC_0,QM_RTC_ALARM_MINUTE/2);

            qm_gpio_set_pin(QM_GPIO_0, LED_BIT);

             

            qm_irq_request(QM_IRQ_RTC_0, qm_rtc_isr_0);

            qm_rtc_set_config(QM_RTC_0, &rtc_cfg);

             

            soc_sleep();

             

            while(1)

            {

             

                    qm_gpio_clear_pin(QM_GPIO_0, LED_BIT);

                    clk_sys_udelay(DELAY);

                    clk_sys_udelay(DELAY);

                    clk_sys_udelay(DELAY);

                     

             

                    qm_gpio_set_pin(QM_GPIO_0, LED_BIT);

             

                    clk_sys_udelay(DELAY);

                    clk_sys_udelay(DELAY);

                    clk_sys_udelay(DELAY);

                   

              }

             

            return 0;

             

            }

             

            void rtc_example_callback()

            {

             

            }

            • 3. Re: Intel Quark D2000: Delay function not working after wake up
              Intel_Peter

              Hello Pratik_PP,

               

              I have successfully replicated the behavior you described. I am currently debugging the code to see if I can find out the reason why this is happening. I will post any updates I have as soon as I can.

               

              Peter.

              • 4. Re: Intel Quark D2000: Delay function not working after wake up
                Pratik_PP

                Hey Peter, I think the problem lies in the soc_sleep() function and the solution is found.

                Before sleep the system clock is set to 512KHz the same clock frequency is restored after system wake-up in the recovery section of sleep function after halt. It should actually be set back to 32MHz.

                Kindly check out this edited soc_sleep() wherein I restore the system clock to 32MHz. The code provides correct delay after wake- up.

                 

                void soc_sleep(void)

                {

                    /* Variables to save register values. */

                    qm_ac_config_t ac_cfg;

                    uint32_t ac_power_save;

                    uint32_t clk_gate_save = QM_SCSS_CCU->ccu_periph_clk_gate_ctl;

                    uint32_t sys_clk_ctl_save = QM_SCSS_CCU->ccu_sys_clk_ctl;

                    uint32_t osc0_cfg_save = QM_SCSS_CCU->osc0_cfg1;

                    uint32_t adc_mode_save = QM_ADC->adc_op_mode;

                 

                    /* Clear any pending interrupts. */

                    clear_all_pending_interrupts();

                 

                    qm_adc_set_mode(QM_ADC_0, QM_ADC_MODE_PWR_DOWN);

                 

                    /* Turn off high power comparators. */

                    qm_ac_get_config(&ac_cfg);

                    ac_power_save = ac_cfg.power;

                    ac_cfg.power &= QM_AC_HP_COMPARATORS_MASK;

                    qm_ac_set_config(&ac_cfg);

                 

                    /*

                     * Program WAKE_MASK.WAKE_MASK[31:0],

                     * CCU_LP_CLK_CTL.WAKE_PROBE_MODE_MASK registers identical to Interrupt

                     * Mask registers.

                     */

                    QM_SCSS_CCU->ccu_lp_clk_ctl &= ~QM_WAKE_PROBE_MODE_MASK;

                 

                    /*

                     * Ensure that powering down of oscillators is delayed by hardware until

                     * core  executes HALT instruction.

                     */

                    /* HYB_OSC_PD_LATCH_EN = 0, RTC_OSC_PD_LATCH_EN=0 */

                    QM_SCSS_CCU->ccu_lp_clk_ctl &=

                        ~(QM_HYB_OSC_PD_LATCH_EN | QM_RTC_OSC_PD_LATCH_EN);

                 

                    /* Ensure that at exit, hardware will switch system clock to Hybrid

                     * oscillator clock so as to minimize exit latency by running at higher

                     * frequency than RTC clock.

                     */

                    /* CCU_LP_CLK_CTL.CCU_EXIT_TO_HYBOSC */

                    QM_SCSS_CCU->ccu_lp_clk_ctl |= QM_CCU_EXIT_TO_HYBOSC;

                 

                    /* Power down hybrid oscillator after HALT instruction is executed. */

                    QM_SCSS_CCU->osc0_cfg1 |= QM_OSC0_PD;

                 

                    /*

                     * Only the following peripherals can be used as a wakeup source:

                     *  - GPIO Interrupts

                     *  - AON timers

                     *  - RTC

                     *  - low power comparators

                     */

                    clk_periph_disable(

                        CLK_PERIPH_I2C_M0 | CLK_PERIPH_SPI_S | CLK_PERIPH_SPI_M0 |CLK_PERIPH_WDT_REGISTER |CLK_PERIPH_PWM_REGISTER |

                        CLK_PERIPH_SPI_M0_REGISTER | CLK_PERIPH_SPI_S_REGISTER |CLK_PERIPH_UARTA_REGISTER | CLK_PERIPH_UARTB_REGISTER |CLK_PERIPH_I2C_M0_REGISTER);

                 

                    /* Set system clock source to hyb osc, 4 MHz, scaled to 512 kHz. */

                    clk_sys_set_mode(CLK_SYS_HYB_OSC_4MHZ, CLK_SYS_DIV_8);

                 

                    /* Set the RAR to retention mode. */

                    rar_set_mode(RAR_RETENTION);

                 

                    /*

                     * If wake source is any of AON Timer, RTC, GPIO interrupt, program

                     * CCU_SYS_CLK_CTL.CCU_SYS_CLK_SEL to RTC Oscillator.

                     */

                    /* Enter SoC sleep mode. */

                    cpu_halt();

                 

                    /* From here on, restore the SoC to an active state. */

                    /* Set the RAR to normal mode. */

                    rar_set_mode(RAR_NORMAL);

                    /* Restore all previous values. */

                    QM_SCSS_CCU->ccu_sys_clk_ctl = sys_clk_ctl_save;

                    /* Re-apply clock divider values. DIV_EN must go 0 -> 1. */

                    QM_SCSS_CCU->ccu_sys_clk_ctl &=

                        ~(QM_CCU_SYS_CLK_DIV_EN | QM_CCU_RTC_CLK_DIV_EN);

                    QM_SCSS_CCU->ccu_sys_clk_ctl |=

                        QM_CCU_SYS_CLK_DIV_EN | QM_CCU_RTC_CLK_DIV_EN;

                 

                    /* Wait for the XTAL or SI oscillator to stabilise. */

                    while (!(QM_SCSS_CCU->osc0_stat1 &

                         (QM_OSC0_LOCK_SI | QM_OSC0_LOCK_XTAL))) {

                    };

                 

                    /* Restore original clocking, ADC, analog comparator states. */

                    QM_SCSS_CCU->osc0_cfg1 = osc0_cfg_save;

                    QM_SCSS_CCU->ccu_periph_clk_gate_ctl = clk_gate_save;

                 

                    ac_cfg.power = ac_power_save;

                    qm_ac_set_config(&ac_cfg);

                    QM_ADC->adc_op_mode = adc_mode_save;

                 

                    clk_sys_set_mode(CLK_SYS_HYB_OSC_32MHZ, CLK_SYS_DIV_1);

                }