Cortex M0不进入睡眠模式

时间:2016-05-16 12:55:48

标签: sleep power-management atmel cortex-m sleep-mode

在解释的专业版开发板上遇到了Atmel SAMB11的问题。我从Atmel加载了一个非常简单的例子,其中初始化32KHz定时器以从睡眠中唤醒μC并打开LED。问题是,控制器根本不睡觉。它只是立即激活LED,不等待中断。

#include <asf.h>

// Callback Func to enable LED
static void aon_sleep_timer_callback(void)
{
    gpio_pin_set_output_level(LED_0_PIN, LED_0_ACTIVE);
}
//Configure LED
static void configure_gpio_pins(void)
{
    struct gpio_config config_gpio_pin;
    gpio_get_config_defaults(&config_gpio_pin);
    config_gpio_pin.direction = GPIO_PIN_DIR_OUTPUT;
    gpio_pin_set_config(LED_0_PIN, &config_gpio_pin);
    gpio_pin_set_output_level(LED_0_PIN, LED_0_INACTIVE);
}
// Configure Timer with 10sec to overflow
static void configure_aon_sleep_timer(void)
{
    struct aon_sleep_timer_config config_aon_sleep_timer;
    aon_sleep_timer_get_config_defaults(&config_aon_sleep_timer);
    config_aon_sleep_timer.counter = 320000; // Wait about 10sec
    aon_sleep_timer_init(&config_aon_sleep_timer);
}
// Configure Callback and enable Interrupt
static void configure_aon_sleep_timer_callback(void)
{
    aon_sleep_timer_register_callback(aon_sleep_timer_callback);
    NVIC_EnableIRQ(AON_SLEEP_TIMER_IRQn);
}

int main(void)
{
    // Setup Clock, LED and Timer
    system_clock_config(CLOCK_RESOURCE_XO_26_MHZ, CLOCK_FREQ_26_MHZ);
    configure_gpio_pins();
    configure_aon_sleep_timer();
    configure_aon_sleep_timer_callback();

    // wait for timer to be active
    while(!aon_sleep_timer_sleep_timer_active());
    // Go to sleep
    asm volatile ("wfi");
    asm volatile ("nop");
    // Enable LED immediately if sleep doesn't work
    gpio_pin_set_output_level(LED_0_PIN, LED_0_ACTIVE);
    while (true) {}
}

代码似乎不言自明,但WFI命令在这里不起作用。有人可以帮忙吗?

2 个答案:

答案 0 :(得分:1)

只是为了增加Prestige Worldwide的答案。

确保AO_GPIO0 / 1/2为低电平(建议下拉),并且不会发生AON睡眠定时器中断,因为它们会从ULP唤醒SAMB11。

另请注意,在SWD上运行调试会话时,ULP模式似乎无法正常工作。

在运行调试和睡眠/唤醒时,我有各种奇怪的行为,但在没有调试的情况下运行相同的代码时完全没有问题。请注意,这是使用Atmel ICE。 Xplored板包含EDBG,这个调试器似乎可以正常使用ULP。

简历回调从未对我开火,也许是ASF中的一个错误。但我不需要它,因为我可以在平台等待后设置所有GPIO /设备。

答案 1 :(得分:0)

WFI调用有效,它只是在调用后几乎立即收到一个中断,这会导致WFI调用停止阻塞,然后执行继续到下一行。

您可以安全地删除// Go to sleep下面的所有内容,以便返回主函数。 AON计时器仍然会执行其回调。但是,这种方法存在一些潜在的缺点:

  • 这不允许SAMB11转换到低功耗模式。
  • 这将删除main末尾的while循环。在当前状态下,不需要while循环,但您可能计划稍后向其添加代码。

这是一个配置AON,配置SAMB11使用低功耗模式,然后循环等待平台和/或BLE事件的示例。目前没有循环接收的事件。如果您希望循环接收事件,那么您可以修改AON回调以使用at_ble_event_user_defined_post函数发布事件,或者在进入循环之前修改main()以配置BLE模块。

使用ASF向导将任何BLE模块添加到项目中以编译此示例。

#include <asf.h>
#include "platform.h"

// Configure LED
static void configure_gpio_pins(void)
{
    struct gpio_config config_gpio_pin;
    gpio_get_config_defaults(&config_gpio_pin);
    config_gpio_pin.direction = GPIO_PIN_DIR_OUTPUT;
    gpio_pin_set_config(LED_0_PIN, &config_gpio_pin);
    gpio_pin_set_output_level(LED_0_PIN, LED_0_INACTIVE);
}

// Callback Func to toggle LED
static bool led_is_on = false;
static void aon_sleep_timer_callback(void)
{
    configure_gpio_pins();
    if(led_is_on) {
        gpio_pin_set_output_level(LED_0_PIN, LED_0_INACTIVE);
        led_is_on = false;
    } else {
        gpio_pin_set_output_level(LED_0_PIN, LED_0_ACTIVE);
        led_is_on = true;
    }
}

// Configure Timer to fire periodically
static void configure_aon_sleep_timer(void)
{
    struct aon_sleep_timer_config config_aon_sleep_timer;
    aon_sleep_timer_get_config_defaults(&config_aon_sleep_timer);
    config_aon_sleep_timer.counter = 32000; // Wait about 1 sec
    config_aon_sleep_timer.mode = AON_SLEEP_TIMER_RELOAD_MODE;
    aon_sleep_timer_init(&config_aon_sleep_timer);
}
// Configure Callback and enable Interrupt
static void configure_aon_sleep_timer_callback(void)
{
    aon_sleep_timer_register_callback(aon_sleep_timer_callback);
    NVIC_EnableIRQ(AON_SLEEP_TIMER0_IRQn);
}

int main(void)
{
    // Setup Clock
    system_clock_config(CLOCK_RESOURCE_XO_26_MHZ, CLOCK_FREQ_26_MHZ);

    plf_drv_status plf_status;
    if((plf_status = platform_driver_init()) == STATUS_SUCCESS) {

        // Setup LED and Timer
        configure_gpio_pins();
        configure_aon_sleep_timer();
        configure_aon_sleep_timer_callback();

        // wait for timer to be active
        while(!aon_sleep_timer_sleep_timer_active());

        // Go to sleep
        release_sleep_lock();
        while(true) {
            // Replace platform_event_wait with at_ble_event_get if you would like to read the received event.
            plf_status = platform_event_wait(0);
        }
    }
}

关于WFI,以下示例说明如何关闭大多数中断并使用WFI来阻止main()。每次收到中断时,LED都会切换。我不建议使用它,因为我不确定为什么最初启用这些中断。这只是为了说明WFI如何阻止SAMB11。

#include <asf.h>
#include "platform.h"

// Configure LED
static void configure_gpio_pins(void)
{
    struct gpio_config config_gpio_pin;
    gpio_get_config_defaults(&config_gpio_pin);
    config_gpio_pin.direction = GPIO_PIN_DIR_OUTPUT;
    gpio_pin_set_config(LED_0_PIN, &config_gpio_pin);
    gpio_pin_set_output_level(LED_0_PIN, LED_0_INACTIVE);
}

// Callback Func to toggle LED
static bool led_is_on = false;
static void toggle_led(void)
{
    configure_gpio_pins();
    if(led_is_on) {
        gpio_pin_set_output_level(LED_0_PIN, LED_0_INACTIVE);
        led_is_on = false;
    } else {
        gpio_pin_set_output_level(LED_0_PIN, LED_0_ACTIVE);
        led_is_on = true;
    }
}

int main(void)
{
    // Setup Clock
    system_clock_config(CLOCK_RESOURCE_XO_26_MHZ, CLOCK_FREQ_26_MHZ);

    // Clear all interrupts.
    NVIC->ICER[0] = 0xFFFFFFFF;

    // During testing, interrupts were received about once per second; stopped receiving interrupts (LED stopped flashing) after about 2 minutes.
    int loop_count = 0;
    while(true) {
        __WFI();
        toggle_led();
    }
}