0

Got a problem with the Atmel SAMB11 on an explained pro Devboard. I've loaded a quite simple example from Atmel, where a 32KHz Timer is initialized to wake up the µC from sleep and turn on a LED. Problem is, the controller doesn't sleep at all. It just activates the LED immediately and doesn't wait for an interrupt.

#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) {}
}

Code seems self-explanatory, but the WFI command doesn't work here. Anyone can help?

DK999
  • 33
  • 1
  • 7
  • 1
    What does `aon_sleep_timer_sleep_timer_active()` do - is it just polling a status register or something? It would be handy to use two different LEDs so you can tell whether you're actually taking the interrupt immediately, or falling through due to some other event. – Notlikethat May 16 '16 at 19:23

2 Answers2

1

Just to add to the answer by Prestige Worldwide.

Make sure AO_GPIO0/1/2 are low (pulldown advised), and no AON Sleep Timer interrupt is occuring, as these will wakeup the SAMB11 from ULP.

Also note that the ULP mode does not seem to work as expected while running a debug session over SWD.

I had all kinds of weirds behaviour when running the debug and sleep/waking up, but no problems at all when running the same code while not debugging. Note this was using Atmel ICE. The Xplored board contains EDBG, and this debugger seems to work ok with ULP.

The resume callback has never fired for me, maybe a bug in the ASF. But I do not need it as I can setup all GPIO/devices after the platform wait.

  • This does not provide an answer to the question. Once you have sufficient [reputation](http://stackoverflow.com/help/whats-reputation) you will be able to [comment on any post](http://stackoverflow.com/help/privileges/comment); instead, [provide answers that don't require clarification from the asker](http://meta.stackexchange.com/questions/214173/why-do-i-need-50-reputation-to-comment-what-can-i-do-instead). - [From Review](/review/low-quality-posts/13200186) – Inian Aug 03 '16 at 05:18
  • I've provided 3 reasons why 'Cortex M0 doesn't enter sleep mode' can occur which the author needs to check to see if it solves the problem. How is this not an answer ? – Maurice van der Zwaan Aug 03 '16 at 08:13
0

The WFI call works, it just receives an interrupt almost immediately after it is called, which causes the WFI call to stop blocking and then execution continues to the next line.

You could safely remove everything below // Go to sleep which would allow the main function to return. The AON timer would still execute its callback. However, there are a couple of potential downsides to this approach:

  • This would not allow the SAMB11 to transition to a lower power mode.
  • This removes your while-loop at the end of main. In its current state, the while-loop isn't needed, but you might have plans to add code to it later.

Here is an example that configures the AON, configures the SAMB11 to use low power modes, and then loops waiting for platform and/or BLE events. Currently there are no events for the loop to receive. If you want the loop to receive events then you could modify the AON callback to post an event with the at_ble_event_user_defined_post function or modify main() to configure the BLE module before entering the loop.

Use the ASF Wizard to add any of the BLE modules to your project in order to compile this example.

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

Regarding WFI, the following example shows how to turn off most of the interrupts and use WFI to block main(). The LED will toggle every time an interrupt is received. I don't recommend using this as I'm not sure why these interrupts are enabled initially. This is just intended to show how WFI can block on a 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();
    }
}
mch
  • 9,424
  • 2
  • 28
  • 42