Cortex M0 不进入睡眠模式
Cortex M0 doesn't enter 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 命令在这里不起作用。有人可以帮忙吗?
WFI 调用有效,它只是在调用后几乎立即收到中断,这导致 WFI 调用停止阻塞,然后继续执行下一行。
您可以安全地删除 // Go to sleep
下面的所有内容,这将允许主函数 return。 AON 计时器仍将执行其回调。但是,这种方法有几个潜在的缺点:
- 这将不允许 SAMB11 转换到低功耗模式。
- 这将删除 main 末尾的 while 循环。在当前状态下,不需要 while 循环,但您可能计划稍后向其添加代码。
这里是配置AON的例子,配置SAMB11使用低功耗模式,然后循环等待平台and/or BLE事件。目前没有循环接收的事件。如果您希望循环接收事件,那么您可以将 AON 回调修改为 post 带有 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();
}
}
只是添加到 Prestige Worldwide 的答案中。
确保 AO_GPIO0/1/2 为低电平(建议下拉),并且没有发生 AON 睡眠定时器中断,因为这些会从 ULP 唤醒 SAMB11。
另请注意,当 运行 通过 SWD 进行调试会话时,ULP 模式似乎没有按预期工作。
当 运行 调试和 sleep/waking 启动时,我有各种奇怪的行为,但当 运行 相同的代码而不调试时,我完全没有问题。请注意,这是使用 Atmel ICE。 Xplored 板包含 EDBG,并且此调试器似乎可以与 ULP 一起使用。
我从未触发过恢复回调,可能是 ASF 中的错误。但我不需要它,因为我可以在平台等待后设置所有 GPIO/devices。
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 命令在这里不起作用。有人可以帮忙吗?
WFI 调用有效,它只是在调用后几乎立即收到中断,这导致 WFI 调用停止阻塞,然后继续执行下一行。
您可以安全地删除 // Go to sleep
下面的所有内容,这将允许主函数 return。 AON 计时器仍将执行其回调。但是,这种方法有几个潜在的缺点:
- 这将不允许 SAMB11 转换到低功耗模式。
- 这将删除 main 末尾的 while 循环。在当前状态下,不需要 while 循环,但您可能计划稍后向其添加代码。
这里是配置AON的例子,配置SAMB11使用低功耗模式,然后循环等待平台and/or BLE事件。目前没有循环接收的事件。如果您希望循环接收事件,那么您可以将 AON 回调修改为 post 带有 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();
}
}
只是添加到 Prestige Worldwide 的答案中。
确保 AO_GPIO0/1/2 为低电平(建议下拉),并且没有发生 AON 睡眠定时器中断,因为这些会从 ULP 唤醒 SAMB11。
另请注意,当 运行 通过 SWD 进行调试会话时,ULP 模式似乎没有按预期工作。
当 运行 调试和 sleep/waking 启动时,我有各种奇怪的行为,但当 运行 相同的代码而不调试时,我完全没有问题。请注意,这是使用 Atmel ICE。 Xplored 板包含 EDBG,并且此调试器似乎可以与 ULP 一起使用。
我从未触发过恢复回调,可能是 ASF 中的错误。但我不需要它,因为我可以在平台等待后设置所有 GPIO/devices。