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

    Intel Quark D2000 wake-up using RTC and Hardware interrupt.

    Pratik_PP

      Hello, I want the microcontroller to wake-up from sleep mode by RTC interrupt after 30 seconds by alarm or by the Hardware switch on the board if pressed before 30 seconds. Kindly go through the code below and help out if any correction required.

      In this program the controller comes out of sleep only by RTC interrupt. The hardware interrupt does not work.

      There is one more problem, the delay function doesn't provide the same delay  after wake up as compared to the delay before sleep. Kindly help if any dedicated clock settings are to be done.

      Thanks in Advance.

       

       

       

      #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);

      cfg1.int_en = BIT(PIN_INTR);       /* Interrupt enabled */

       

      cfg1.int_type = BIT(PIN_INTR);     /* Edge sensitive interrupt */

       

      cfg1.int_polarity = BIT(PIN_INTR); /* Rising edge */

       

      cfg1.int_debounce = 0; /* Debounce disabled */

       

      cfg1.int_bothedge = 0x0;  /* Both edge disabled */

       

      cfg1.callback = gpio_example_callback;

      qm_irq_request(QM_IRQ_GPIO_0, qm_gpio_isr_0);

       

      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)

      {

          if(flag == 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);

                   flag = 0;

          }

       

      }

      return 0;

       

      }

       

      void rtc_example_callback()

      {

       

      }

      void gpio_example_callback()

      {

          flag = 1;

       

      }

        • 1. Re: Intel Quark D2000 wake-up using RTC and Hardware interrupt.
          DiegoV_Intel

          Hi Pratik_PP,

           

          There is an example code that shows how to configure the RTC and the comparator as wake up sources, but it doesn't show how to use a GPIO as wake up source.

           

          Let me run a couple of tests to see if I'm able to configure the GPIO as a wake up source. In case you haven't seen the example code I'm talking about, here is the link: qmsi/main.c at fd5a6a783df1ab99260302ea25e1efb6208dbd8f · 01org/qmsi · GitHub

           

          I'll post an update as soon as possible.

           

          Regards,

          Diego

          • 2. Re: Intel Quark D2000 wake-up using RTC and Hardware interrupt.
            Pratik_PP

            Hey Diego, I think I've found the solution. We have to make some changes in the soc_sleep() function as GPIO register is wrongly disabled I presume, as according to the Functionality of soc_sleep() even the GPIO interrupt should wake- up the system by default.

             

            This edited soc_sleep() wakes- up at GPIO interrupt.

             

            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;

             

                 }