wzd5230 发表于 2024-5-25 12:01:55

NRF52832开启HFCLK后遇到低功耗和睡眠问题

在验证NRF52832的低功耗,没有使用softdevice,外接高速、低速晶振,并使用外部的晶振为时钟源。
现在做了一个简答的测试,功能主要是:
a、将HFCLK、LFCLK开启,分别使用外部晶振。
b、使能一个GPIO作为Led电灯,开启rtc0的比较中断0,作为唤醒,设置时间为5秒,rtc的中断中再次设置下次超时时间为5秒
c、while循环中包含以下几个步骤:
    - 关闭HFCLK(即HFXO)(降低功耗)
    - 进入休眠(这里为了测试,验证了几种写法:WFI、WFE、WFE SEV WFE、SEV WFE WFE)
    - 因rtc中断退出休眠,重新开启HFCLK(即HFXO)
    - 电量Led灯,循环等待一段时间,然后关闭Led,这样Led发光更为明显

预期结果:每隔5秒

测试遇到如下问题:
1、在main中的循环中,睡眠之前不关闭HFCLK,功耗比较高有280uA左右,如果关闭HCLK,低功耗可以到3uA。但是我从手册里面看HFCLK描述的是如果没有peripheral需要HCLK,不需要关闭,他自动会进入节能模式,这里的200uA已经是节能模式了吗?感觉还是在运行。从sdk里面看无softdevice的低功耗例程,睡眠之前并没有对HFCLK进行处理。


2、基于1中的需要在睡眠之前进行HCLK的开启和关闭,如果睡眠使用WFI,整个功能是正常的,但是使用WFE或WFE SEV WFE都是不正常的,其实也就是意味着执行WFE的时候,有“原因导致”无法进入低功耗。如果在睡眠前后不对HFCLK进行开启、关闭,则可以正常睡眠,只是功耗高,后定位与HFCLK关闭没有关系,主要是开启导致的问题。但是SEV WFE WFE是正常的,因为SEV WFE会把所有事件清除,后面的WFE会让MCU进入低功耗状态。但是这种方式是有风险的,先清除事件,会导致某个真实的唤醒没有阻止进入休眠。
这里的问题在于clock的中断都是开启的,低功耗后面的HFCLK开启时触发的中断已经在ISR进行事件清除,为什么还会影响接下来的睡眠呢?

以下是测试的代码:
static void _rtc0_timer_callback(nrfx_rtc_int_type_t int_type);

#define LED_PIN 13

static void led_init(void)
{
nrf_gpio_cfg_output(LED_PIN);
}

static void led_turn_on(void)
{
nrf_gpio_pin_write(LED_PIN, 0);
}

static void led_turn_off(void)
{
nrf_gpio_pin_write(LED_PIN, 1);
}

void _rtc_timer_start(void)
{
    nrfx_rtc_t            timer_inst = NRFX_RTC_INSTANCE(0);
    nrfx_rtc_config_t   timer_cfg = NRFX_RTC_DEFAULT_CONFIG;
   
    // low frequency clock
    nrf_clock_lf_src_set((nrf_clock_lfclk_t)1);
    nrfx_clock_lfclk_start();
   
    // config
    timer_cfg.prescaler = RTC_FREQ_TO_PRESCALER(32768);
   
    nrfx_rtc_init(&timer_inst, &timer_cfg, _rtc0_timer_callback);
    nrfx_rtc_counter_clear(&timer_inst);
    nrfx_rtc_overflow_enable(&timer_inst, true);
    nrfx_rtc_enable(&timer_inst);
}

void _rtc_timer_set_next(uint32_t time_us)
{
    uint32_t tick;
    tick = (uint32_t)(time_us / (1000000.0 / 32768));
   
    nrfx_rtc_t timer_inst = NRFX_RTC_INSTANCE(0);
    tick = (tick + nrfx_rtc_counter_get(&timer_inst));
    nrfx_rtc_cc_set(&timer_inst, 0, tick, true);
}

static void _rtc0_timer_callback(nrfx_rtc_int_type_t int_type)
{
    // set next timeout
    _rtc_timer_set_next(5000000);
}

static void clk_event_handler(nrfx_clock_evt_type_t event)
{
}

int main(void)
{
    nrfx_clock_init(clk_event_handler);
    nrfx_clock_enable();
    nrfx_clock_hfclk_start();
    while(nrfx_clock_hfclk_is_running() == false)
    {
    }
    nrfx_clock_lfclk_start();
    while(nrfx_clock_lfclk_is_running() == false)
    {
    }
   
    led_init();
    led_turn_off();
   
    _rtc_timer_start();
    _rtc_timer_set_next(5000000);
   
    while(1)
    {
      // 关闭外部高速晶振,切换到内部,降低功耗
      nrfx_clock_hfclk_stop();
      
      // 使用这个睡眠,灯一直在点亮,无法进入低功耗
      // __WFE();
      // __SEV();
      // __WFE();
      
      // 使用这个睡眠,行为符合预期,但是可能前面的某个事件无法中止进入睡眠
      // __SEV();
      // __WFE();
      // __WFE();
      
      // 使用这个睡眠,行为符合预期
      __WFI();
      
      // 使用这个睡眠,灯一直在点亮,无法进入低功耗
      // __WFE();
      
      // 重新开启外部高速晶振
      // 只要把这一行注释掉,上面的几种睡眠行为都符合预期,
      // 但是clock的中断是使能的,为什么会影响wfe的行为?
      nrfx_clock_hfclk_start();
      while(nrfx_clock_hfclk_is_running() == false)
      {
      }
      
      // 点亮一会Led,使其观察明显
      led_turn_on();
      for(uint32_t i = 1000000; i > 0; i--)
      {
            __NOP();
      }
      led_turn_off();
    }
}
页: [1]
查看完整版本: NRF52832开启HFCLK后遇到低功耗和睡眠问题