SAM B11 Wake up by BLE Event from ULP

Go To Last Post
19 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I need help how I can put my device into ULP for most of the time while being connected to the central device.

 

From documentation from BluSDK, it states that SAMB11 can wake up from ULP by BLE event.

In every BLE examples, it acquires sleep lock to never get the device to ULP, or just use the AON GPIO to show ULP as an example.

 

In my understanding, for the device to be "low power", this SoC should only be active on BLE connection intervals ,user app and firmware code.

However the example code never puts the device to sleep waiting for the next BLE event. (Am I wrong?)

I need help on how I can get the device in ULP between the connection intervals.

Thanks in advance.

Last Edited: Sat. Sep 17, 2016 - 02:30 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

The beacon example shows BLE and sleeping.

 

I'm currently using the ULP mode without BLE (AON Timer sending platform event to wakeup).

 

I've already experimented using ULP with BLE and doing a release_sleep_lock() and then call either the platform_event_get or at_ble_event_get should put the device to sleep. The ble stack will automatically keep advertising and the function only returns on plaform events or BLE events.

 

Some notes from my experiments :

 

* I never acquire the sleep lock. Doing so locks my SAMB11 most of the time. Will test more to validate the reason

* I release the sleep lock before every event_get.

* ble_set_ulp_mode(BLE_ULP_MODE_SET); just makes the ble library call the acquire/release sleep lock

* ULP and debug mode (Atmel ICE/Powerdebugger) does not work for me. Program crashes, no ULP, breakpoints not triggered etc.

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Any further progress on getting ULP operating properly.

A code example would be very helpful.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I have a functioning ULP at the moment (custom PCB at 130uA), but unfortunately it's not stable and crashes after a couple of days.

 

To get ULP :

In startup :

ble_device_init(NULL);

 

And in your loop 

ble_set_ulp_mode(BLE_ULP_MODE_SET);

ble_event_task(BLE_EVENT_TIMEOUT);

 

Wakeup : 

send_plf_int_msg_ind(1,0,NULL,0);

I send it from AON Timer (which has WAKEUP_ARM only)

Waking from AON_GPIO does not work for me (power usage goed up, but the send_plf_int_msg_ind does not work).

 

Also make sure to reinitialize all modules/gpio pins after wakeup

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thank you for that information.

 

By "reinitialize all modules/gpio pins" do you mean reinitialize them from scratch, including setting up their callbacks, etc.?  What is an example of a "module" in this case?

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Yes reinitialize from scratch. By modules I mean UART/SPI/I2C/Timers etc.

The callbacks are just static variables in ASF, and the ISR itself is registered in the init. But for your first version, just re-initialize everything ;)

I have noted that not initializing them at every wake, but just when needed is unstable (probably because of the gpio latches).

I have noted other irratic behaviour as well, and once I'm finished with my firmware I'll try to make a sample to send to Atmel to get it fixed. 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thank you very much. I will follow that path.

I'm now looking at the "simple starter app", which is structured with the calls you originally mentioned in your first reply above.

I'm also now looking more closely inside gpio.c at how the AOGPIO awaken configuration code is structured. I assume this is all part of ASF/BlueSDK. It's helpful to look at that API layer to fully grasp what's going on.

Unfortunately, as others have pointed out, the hardware registers do not appear to be clearly documented (or perhaps I missed that HW reference guide), so it is tough to follow fully. The BlueSDK release notes suggest fixes were made to both AOTIMER and AOGPIO for proper ULP operation, so that's encouraging.

If I figure out how to get AOGPIO wake up from ULP to work, I will publish my findings. Sure would be helpful to see a ULP Getting Started example from Atmel that's been tested and properly documented to save us all time and frustration and improve their customer success rate with Samb11.

Again, thanks for your help.

Rick

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

BluSDK 5.2 is still the latest version ?

Waking from AOGPIO seems to work (as I can see from my uCurrent the processor wakes up from 0.13mA to 2mA power levels), but the platform message is not being sent. 

Currently I have the AON_Timer set at 16384 (every 0.5 seconds) and I check the AO GPIO and then wakeup. This works, with a bit of latency, but is far from ideal.

Once I find the time (need to release my firmware first) I will try to transfer some AON Timer wakeup code to the AON GPIO ISR.

Maybe we can make the ULP Getting Started firmware together. I'm at 90% I think ;)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

5.2 is still latest I'm finding.

My use case may be similar. I'm using Samb11 MCU as a frequency counter, where the AOGPIO0 pin will receive a square wave at up to 50 KHz. I'm assuming the MCU will wake up during the low to high transition, trigger the wake up, interrrupt and callback, whereby the ISR callback simply increments a counter. Then every 100 to 500 milliseconds the AONTIMER will fire and calculate the frequency based upon the number of GPIO interrupts. The BLE is only used occasionally for external status reporting, configuration and OTAU.

This all occurs over a several second period. Given how touchy the ULP wake up and related context switching seems to be, I'm starting to rethink a few things...

Like using the first AOGPIO interrupt to awaken from ULP, then remain awake (block sleeping) until the frequency counting cycle has completely finished, to avoid the ULP context switching issues and overhead.

So this discussion has been very helpful as I'm still in the design phase.

Last Edited: Thu. Apr 13, 2017 - 03:43 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Well, making some progress at getting AO_GPIO_0 to interrupt, but ULP mode remains elusive.  The following code works in that the button can toggle the LED; however, when I do get AO_GPIO0 interrupts, I typically get two in a row then no more. Sometimes they occur without me doing anything (just starting the debugger up) and other times I am able to trigger the AOGPIO0 callback by switching the input from GND to VCC, but I always get two of them, then they cease to function.  I tried redefining them after the initial callback, but didn't seem to work.

 

Here's my almost working code, modified from the Samb11 Startup Template example:

 

#include <asf.h>

#include "platform.h"
#include "at_ble_api.h"
#include "console_serial.h"
#include "timer_hw.h"
#include "ble_manager.h"
#include "ble_utils.h"
#include "button.h"
#include "led.h"
#include "startup_template_app.h"

static void delay(uint32_t count)
{
    for (uint32_t i = 0; i < count; i++) {
        for (uint32_t j = 0; j < 100; j++)
        asm volatile ("nop");
    }
}

/* timer callback function */
static void timer_callback_handler(void)
{
    /* Add timer callback functionality here */
    puts("Timer1 trigger\r\n");
}

static void button_cb(void)
{
    /* Add button callback functionality here */
    gpio_pin_toggle_output_level(LED_0_PIN);
}

static void configure_gpio_callbacks(void);
static void configure_gpio_pins(void);
static void ao0_gpio_callback(void)
{
    int i = 0;
    i++;
    NVIC_ClearPendingIRQ(GPIO0_IRQn);
    //    NVIC_SetPriority(GPIO0_IRQn,1);
    gpio_pin_toggle_output_level(LED_0_PIN);
    puts("AO GPIO 0 triggered\r\n");
    send_plf_int_msg_ind(1,0,NULL,0);

//    configure_gpio_pins();
//    configure_gpio_callbacks();
}

static void configure_gpio_callbacks(void)
{
    button_register_callback(button_cb);
        
    gpio_register_callback(PIN_AO_GPIO_0, ao0_gpio_callback, GPIO_CALLBACK_RISING);
    gpio_enable_callback(PIN_AO_GPIO_0);
        
    NVIC_EnableIRQ(GPIO0_IRQn);  // enable sleep interruption by AON_GPIO0
}

static void configure_gpio_pins(void)
{
    /* Add GPIO configuration functionality here */
    struct gpio_config config_gpio_pin;

    gpio_get_config_defaults(&config_gpio_pin);

    // Configure LED output pin
    config_gpio_pin.direction  = GPIO_PIN_DIR_INPUT;
    config_gpio_pin.input_pull = GPIO_PIN_PULL_NONE;
    gpio_pin_set_config(LED_0_PIN, &config_gpio_pin);
    
    
    // Configure auto-on wakeup pin (pull down to enable ULP sleep, pull up to waken from ULP)
    gpio_pinmux_cofiguration(PIN_AO_GPIO_0, MUX_LP_GPIO_0_MEGAMUX);  // set to WAKEUP mode
//    gpio_pinmux_cofiguration(PIN_AO_GPIO_0, 0);  // set to regular I/O mode
    config_gpio_pin.direction  = GPIO_PIN_DIR_INPUT;
    config_gpio_pin.input_pull = GPIO_PIN_PULL_NONE;
    config_gpio_pin.aon_wakeup = true;
    gpio_pin_set_config(PIN_AO_GPIO_0, &config_gpio_pin);

    // Configure auto-on wakeup pin (pull down to enable ULP sleep, pull up to waken from ULP)
    config_gpio_pin.direction  = GPIO_PIN_DIR_INPUT;
    config_gpio_pin.input_pull = GPIO_PIN_PULL_DOWN;
    gpio_pin_set_config(PIN_AO_GPIO_1, &config_gpio_pin);

    // Configure auto-on wakeup pin (pull down to enable ULP sleep, pull up to waken from ULP)
    config_gpio_pin.direction  = GPIO_PIN_DIR_INPUT;
    config_gpio_pin.input_pull = GPIO_PIN_PULL_DOWN;
    gpio_pin_set_config(PIN_AO_GPIO_2, &config_gpio_pin);
}

int main(void)
{
    system_clock_config(CLOCK_RESOURCE_XO_26_MHZ, CLOCK_FREQ_26_MHZ);
    platform_driver_init();
    acquire_sleep_lock();

    /* Initialize serial console */
    serial_console_init();
    
    /* GPIO */
    gpio_init();
      button_init();
    configure_gpio_pins();
    configure_gpio_callbacks();
    led_init();
    

    /* Hardware timer */
    hw_timer_init();
    hw_timer_register_callback(timer_callback_handler);

    DBG_LOG("Initializing BLE Application");
//    hw_timer_start(10);
    
    release_sleep_lock();
    /* initialize the BLE chip  and Set the Device Address */
    ble_device_init(NULL);
    
    
    while(true)
    {
        /* Set ULP mode */
        ble_set_ulp_mode(BLE_ULP_MODE_SET);
        /* BLE Event task */
        ble_event_task(BLE_EVENT_TIMEOUT);
        
        /* Write application task */
//        delay(500);
    }

}

 

 

Last Edited: Fri. Apr 14, 2017 - 03:02 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Getting very close now. Still getting double interrupts on AOGPIO0 callback, but it's working now.  Still can't reliably send PLF message from interrupt callback through system into main loop, so use basic BLE loop for now.  It's not reliably dropping into ULP mode yet, but when it does, it's only drawing around 30 to 40 microamps, which is great!  Very, very unreliable when running it with the debugger, which screws the timing of everything up.  I'm using inline ammeter to monitor current usage to determine when it's going into ULP.

#include <asf.h>
#include "platform.h"
#include "at_ble_api.h"
#include "console_serial.h"
#include "timer_hw.h"
#include "ble_manager.h"
#include "ble_utils.h"
#include "button.h"
#include "led.h"
#include "startup_template_app.h"

static int    aogpio0_count = 0;

/* timer callback function */
static void timer_callback_handler(void)
{
    /* Add timer callback functionality here */
    puts("Timer1 trigger\r\n");
}

static void button_cb(void)
{
    /* Add button callback functionality here */
    gpio_pin_toggle_output_level(LED_0_PIN);
}

static void configure_gpio_callbacks(void);
static void configure_gpio_pins(void);

static void ao0_gpio_callback(void)
{
    aogpio0_count++;
    
    gpio_pin_toggle_output_level(LED_0_PIN);
    send_plf_int_msg_ind(GPIO0_IRQn, PIN_AO_GPIO_0,NULL,0);

    configure_gpio_pins();
    configure_gpio_callbacks();
    led_init();
}

static void configure_gpio_callbacks(void)
{
    button_register_callback(button_cb);
        
    gpio_register_callback(PIN_AO_GPIO_0, ao0_gpio_callback, GPIO_CALLBACK_RISING);
    gpio_enable_callback(PIN_AO_GPIO_0);
        
    NVIC_EnableIRQ(GPIO0_IRQn);  // enable sleep interruption by AON_GPIO0
}

static void configure_gpio_pins(void)
{
    /* Add GPIO configuration functionality here */
    struct gpio_config config_gpio_pin;

    gpio_get_config_defaults(&config_gpio_pin);

    // Configure LED output pin
    config_gpio_pin.direction  = GPIO_PIN_DIR_INPUT;
    config_gpio_pin.input_pull = GPIO_PIN_PULL_NONE;
    gpio_pin_set_config(LED_0_PIN, &config_gpio_pin);
    
    
    // Configure auto-on wakeup pin (pull down to enable ULP sleep, pull up to waken from ULP)
    gpio_pinmux_cofiguration(PIN_AO_GPIO_0, MUX_LP_GPIO_0_MEGAMUX);  // set to WAKEUP mode
//    gpio_pinmux_cofiguration(PIN_AO_GPIO_0, 0);  // set to regular I/O mode
    config_gpio_pin.direction  = GPIO_PIN_DIR_INPUT;
    config_gpio_pin.input_pull = GPIO_PIN_PULL_NONE;
    config_gpio_pin.aon_wakeup = true;
    gpio_pin_set_config(PIN_AO_GPIO_0, &config_gpio_pin);

    // Configure auto-on wakeup pin (pull down to enable ULP sleep, pull up to waken from ULP)
    config_gpio_pin.direction  = GPIO_PIN_DIR_INPUT;
    config_gpio_pin.input_pull = GPIO_PIN_PULL_DOWN;
    gpio_pin_set_config(PIN_AO_GPIO_1, &config_gpio_pin);

    // Configure auto-on wakeup pin (pull down to enable ULP sleep, pull up to waken from ULP)
    config_gpio_pin.direction  = GPIO_PIN_DIR_INPUT;
    config_gpio_pin.input_pull = GPIO_PIN_PULL_DOWN;
    gpio_pin_set_config(PIN_AO_GPIO_2, &config_gpio_pin);
}

int main(void)
{
    system_clock_config(CLOCK_RESOURCE_XO_26_MHZ, CLOCK_FREQ_26_MHZ);
    platform_driver_init();
    acquire_sleep_lock();

    /* Initialize serial console */
    serial_console_init();
    
    /* GPIO */
    gpio_init();
      button_init();
    configure_gpio_pins();
    configure_gpio_callbacks();
    led_init();
    

    /* Hardware timer */
    hw_timer_init();
    hw_timer_register_callback(timer_callback_handler);

    DBG_LOG("Initializing BLE Application");
//    hw_timer_start(10);
    
    release_sleep_lock();
    /* initialize the BLE chip  and Set the Device Address */
    ble_device_init(NULL);

#define BLE_ONLY
#ifdef BLE_ONLY    
    while(true)
    {
        /* Set ULP mode */
        ble_set_ulp_mode(BLE_ULP_MODE_SET);
        /* BLE Event task */
        ble_event_task(BLE_EVENT_TIMEOUT);
        
        /* Write application task */
    }
    
#else
    uint16_t plf_event_type;
    uint8_t plf_event_data[16];
    uint16_t plf_event_data_len;
 
    while( 1 )
    {
        ble_set_ulp_mode(BLE_ULP_MODE_SET);
        ble_event_task(BLE_EVENT_TIMEOUT);            // briefly process BLE tasks

        plf_drv_status rc;
        rc = platform_event_wait(500);  // wait for a platform event
        rc = platform_event_get(&plf_event_type,plf_event_data,&plf_event_data_len);
        if( rc == STATUS_RECEIVED_PLF_EVENT_MSG )  // we received a platform event (not BLE)
        {
            acquire_sleep_lock();
        //    printf("platform event: type: %d\r\n", plf_event_type);
            if(plf_event_type == 7959)
            {
                //Do what you wanted to do on event can be handled here.
                printf("Received AO_GPIO_0 event: AOGPIO count: %d", aogpio0_count);
            }
            release_sleep_lock();
        }
    }
#endif

}

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Below is my AO_GPIO_0 low power BLE with event-triggered wakeup. In my measurements, I'm not seeing full ULP but what appears to instead be "MCU Idle" mode, which draws about 40 microamps (0.04 ma.), which is still reasonably low. I'm testing this using the Atmel Samb11 XPlained board.  During boot, I have shorted pin 9 of EXT1 (AO_GPIO_0/IRQ) to GND (pin 19).  It drops into low-power mode within about 5 seconds and stays there until I move the wire from GND to VCC (pin 20 of EXT1). Be sure you're on EXT1 and not EXT3 (made that mistake - wasted some time).

This code is a modified version of the sample starter application file "startup_template_app.c", which was originally part of the Atmel Samb11 example application "STARTUP_TEMPLATE_SAMB11_XPLAINED_PRO" project.

Some things I tried that did not work well or at all:

- Testing with the SWD debugger - VERY flaky!  Recommend using the debugger only to upload the firmware changes, then stop debugger, then press the Reset button on the board to reboot it.

- Serial port worked well for standard out messages.  Definitely avoid logging to standard out during interrupt handler callbacks.

- Framework messaging from interrupt handler, did not work reliably at all, so stopped using it.

Other key items to note:

1. Note that unused AO_GPIO_1/2 are both pulled down to GND during configuration (to keep them from floating randomly and allow low-power mode).

2. Note that AO_GPIO_0 pin configuration has the "wakeup" pin set to TRUE:   "config_gpio_pin.aon_wakeup = true;"

3. Note that AO_GPIO_0 pin configuration mux config is set to megamux, which is the WAKEUP setting:  gpio_pinmux_cofiguration(PIN_AO_GPIO_0, MUX_LP_GPIO_0_MEGAMUX); 

4. In the AO_GPIO_0 pin callback (interrupt handler), note that all pin configurations are being reconfigured after each interrupt callback. Just like the documentation suggests, when the SoC comes out of low-power mode, you must reset all modules and pin configs.  I realize now that I'm not resetting the UART for serial port operation, which may also need to be done (haven't verified that yet).

Hope this helps save you some time, as I could not find a complete example for wakeup from low-power mode that worked.  This one does work with BlueSDK 5.2 installed.

 

startup_template_app.c: (file is attached)

 

/**

 * \file
 *
 * \brief BLE Startup Template
 *
 * Copyright (c) 2016 Atmel Corporation. All rights reserved.
 *
 * \asf_license_start
 *
 * \page License
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution.
 *
 * 3. The name of Atmel may not be used to endorse or promote products derived
 *    from this software without specific prior written permission.
 *
 * 4. This software may only be redistributed and used in connection with an
 *    Atmel microcontroller product.
 *
 * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
 * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * \asf_license_stop
 *
 */

/*
 * Support and FAQ: visit <a href="http://www.atmel.com/design-support/">Atmel
 * Support</a>
 */

/**
 * \mainpage
 * \section preface Preface
 * This is the reference manual for the Startup Template
 */
/*- Includes ---------------------------------------------------------------*/
#include <asf.h>
#include "platform.h"
#include "at_ble_api.h"
#include "console_serial.h"
#include "timer_hw.h"
#include "ble_manager.h"
#include "ble_utils.h"
#include "button.h"
#include "led.h"
#include "startup_template_app.h"

static int    aogpio0_count = 0;

/* timer callback function */
static void timer_callback_handler(void)
{
    /* Add timer callback functionality here */
    puts("Timer1 trigger\r\n");
}

static void button_cb(void)
{
    /* Add button callback functionality here */
    gpio_pin_toggle_output_level(LED_0_PIN);
}

static void configure_gpio_callbacks(void);
static void configure_gpio_pins(void);

static void ao0_gpio_callback(void)
{
    aogpio0_count++;
    
    gpio_pin_toggle_output_level(LED_0_PIN);

    configure_gpio_pins();
    configure_gpio_callbacks();
    led_init();
}

static void configure_gpio_callbacks(void)
{
    button_register_callback(button_cb);
        
    gpio_register_callback(PIN_AO_GPIO_0, ao0_gpio_callback, GPIO_CALLBACK_RISING);
    gpio_enable_callback(PIN_AO_GPIO_0);
        
    NVIC_EnableIRQ(GPIO0_IRQn);  // enable sleep interruption by AON_GPIO0
}

static void configure_gpio_pins(void)
{
    /* Add GPIO configuration functionality here */
    struct gpio_config config_gpio_pin;

    gpio_get_config_defaults(&config_gpio_pin);

    // Configure LED output pin
    config_gpio_pin.direction  = GPIO_PIN_DIR_INPUT;
    config_gpio_pin.input_pull = GPIO_PIN_PULL_NONE;
    gpio_pin_set_config(LED_0_PIN, &config_gpio_pin);
    
    
    // Configure auto-on wakeup pin (pull down to enable ULP sleep, pull up to waken from ULP)
    gpio_pinmux_cofiguration(PIN_AO_GPIO_0, MUX_LP_GPIO_0_MEGAMUX);  // set to WAKEUP mode
    config_gpio_pin.direction  = GPIO_PIN_DIR_INPUT;
    config_gpio_pin.input_pull = GPIO_PIN_PULL_DOWN;
    config_gpio_pin.aon_wakeup = true;
    gpio_pin_set_config(PIN_AO_GPIO_0, &config_gpio_pin);

    // Configure auto-on wakeup pin (pull down to enable ULP sleep, pull up to waken from ULP)
    config_gpio_pin.direction  = GPIO_PIN_DIR_INPUT;
    config_gpio_pin.input_pull = GPIO_PIN_PULL_DOWN;
    gpio_pin_set_config(PIN_AO_GPIO_1, &config_gpio_pin);

    // Configure auto-on wakeup pin (pull down to enable ULP sleep, pull up to waken from ULP)
    config_gpio_pin.direction  = GPIO_PIN_DIR_INPUT;
    config_gpio_pin.input_pull = GPIO_PIN_PULL_DOWN;
    gpio_pin_set_config(PIN_AO_GPIO_2, &config_gpio_pin);
}

int main(void)
{
    system_clock_config(CLOCK_RESOURCE_XO_26_MHZ, CLOCK_FREQ_26_MHZ);
    platform_driver_init();
    acquire_sleep_lock();

    /* Initialize serial console */
    serial_console_init();
    
    /* GPIO */
    gpio_init();
      button_init();
    configure_gpio_pins();
    configure_gpio_callbacks();
    led_init();
    

    /* Hardware timer */
    hw_timer_init();
    hw_timer_register_callback(timer_callback_handler);

    DBG_LOG("Initializing BLE Application");
//    hw_timer_start(10);
    
    release_sleep_lock();
    /* initialize the BLE chip  and Set the Device Address */
    ble_device_init(NULL);

    while(true)
    {
        /* Set ULP mode */
        ble_set_ulp_mode(BLE_ULP_MODE_SET);
        /* BLE Event task */
        ble_event_task(500);  // amount of time to wait before going into low power mode (in 10ms, so 5,000 is 5 seconds)
        
        /* Write application task */
    }
}

 

Attachment(s): 

Last Edited: Fri. Apr 14, 2017 - 10:24 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Shouldn't mcu idle be much more than 40 uA? Datasheet says MCU_idle is 0.85 mA. Errata shows 2 uA sleep. Have you tried to turn off the flash? You are not using the current measurement system on board?

Is there a schematic available for the SAMB11 Xplained Pro?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

It appears the additional current above ULP sleep comes from the AO GPIO pull-down resistors required to keep those pins low. I was trying to explain the 40 uA and closest thing I could see in documented power levels was MCU idle.  I have no idea how to discern what sleep level it's actually running at.

I have not tried turning off flash. In fact, no idea how to do that. The datasheet discusses all the various power modes, but the ASF/BluDSK provides relatively little information on how to manage the power modes, so it's taken a lot of experimentation, trial and error.  For example, right now while the sleep and wake-up works once, after processing the first time and attempt to yield again to BLE subsystem via ble_event_task(), and the system just freezes.  Within a minute or so, I see a strange "BOUT!" message, then the entire board reboots!  My assumption is that means the BLE subsystem crashed and then the board rebooted due to a watchdog (or something). Others have reported the mysterious "BOUT!" message, but no idea what it is for sure or why things lock up as they do.

Yes, I'm using the current measurement pins on the board, which is how I know how much its drawing.

Last Edited: Mon. Apr 17, 2017 - 07:54 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I was reading this: https://community.atmel.com/proje... and got the flash off idea from it. It also shows the command needed.

 

I didn't mean the current measuremnt pins, but the current measuring system that seems to be onboard so that you could log the current on your PC. Haven't used that and haven't got any SAMB11, but datasheet shows one.

 

Is something pulling the GPIO pins up? If not, pulldown shouldn't add any consumption.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Interesting link. Lots of Samb11 crashes being reported, including my own.

I wasn't aware of the current measuring system. Where is it documented?

Last Edited: Mon. Apr 17, 2017 - 09:17 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

The current measurement system is documented in hte SAM B11 Xplained Pro User Guide: http://ww1.microchip.com/downloa...

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I'm getting closer to the ULP currents in the datasheet: https://community.atmel.com/foru...

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

I finally figured out how to get Samb11 to drop into ULP sleep mode, and reliably interrupt to wake it up using AO_GPIO_0 as an external interrupt.  I'm providing a modified version of the Battery app that has the workarounds required to make Samb11 work as advertised; i.e., use ASF to put it into ULP sleep mode, then wake it up using a combination of AO_GPIO_0 interrupt and AO_TIMER.

 

First, the bug. Using BluSDK 5.1, you can put Samb11 into ULP sleep in the main loop using:

 

    ble_set_ulp_mode(BLE_ULP_MODE_SET);   // this causes ble_event_task() to automatically acquire and release the ULP sleep lock, so no further lock management is required

    ble_event_task(BLE_EVENT_TIMEOUT);      // this puts the Samb11 into ULP deep sleep mode with an infinite timeout; i.e., it will sleep until awakened by a BLE event or Platform event

 

To awaken Samb11 from ULP sleep mode, one must make a platform message call, like this:

 

    send_plf_int_msg_ind(PWR_WAKEUP_DOMAIN_ARM, TIMER_EXPIRED_CALLBACK_TYPE_DETECT, NULL, 0); // wake up the main loop

 

The above call triggers a "platform event" that awakens the device from ULP sleep, activating the main loop again, which executes the next instruction following ble_event_task(). Note that at this point, sleep lock was automatically acquired due to use of ble_set_ulp_mode(BLE_ULP_MODE_SET).

 

Unfortunately, there is a SEV0 bug in ASF that manifests later in release_sleep_lock() if send_plf_int_msg_ind() is called from external interrupt handler, such as the callback for AO_GPIO_0.  send_plf_int_msg_ind() will awaken the main loop as expected, but the next call to ble_event_task() that then calls release_sleep_lock() will actually lock the entire device up, rendering it useless (until later when the built-in watchdog reboots the locked up device and you see the "BOUT!" message, which apparently means it auto-reset itself.)  So do not use send_plf_int_msg_ind() within an external AO_GPIO interrupt handler to send a platform wakeup event (until this bug is, hopefully, fixed by Atmel in ASF).  I say "hopefully" because this bug has been reported and know since at least April 2017, if not before...

 

To work around this bug, here's what I did (and mvdzwaan also did, as posted above).  Inside the AO_GPIO handler, start an AO_TIMER with a very short interval, as shown below:

static void ao_gpio_callback(void)

{

    ao_count++;

    configure_start_timer();

}

 

static void configure_start_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 = 1;

    config_aon_sleep_timer.mode = AON_SLEEP_TIMER_SINGLE_MODE;

    config_aon_sleep_timer.wakeup = AON_SLEEP_TIMER_WAKEUP_ARM_BLE;

 

    aon_sleep_timer_init(&config_aon_sleep_timer);

    aon_sleep_timer_register_callback(timer_callback_handler);

    NVIC_EnableIRQ(AON_SLEEP_TIMER0_IRQn);

}

 

 

When the AO_TIMER fires, disable the timer and start over again, after sending the platform event.

 

static void disable_stop_timer(void)

{

    aon_sleep_timer_disable();

}

 

static void timer_callback_handler(void)

{

    if( ao_count > 0)

    {

        ao_count = 0;

        send_plf_int_msg_ind(PWR_WAKEUP_DOMAIN_ARM, TIMER_EXPIRED_CALLBACK_TYPE_DETECT, NULL, 0); // wake up the main loop

    }

    disable_stop_timer();

}

 

It seems ridiculous to have to work around such an obvious bug like this.  send_plf_int_msg_ind() is intended to work if called from any interrupt handler, but it only works properly when called from AO_TIMER callback when coming out of ULP sleep mode.

 

I'm attaching the modified Battery app as a complete example.  Using Data Visualizer, what I see is about 10.5 uA of current drain during ULP sleep mode.  It's higher than the usual 1 to 2 uA ULP sleep level because UART pins are still enabled (disabling the UART pins will reduce the current drain fully).  Also, be CERTAIN that you ground the AO_GPIO_0, AO_GPIO_1 and AO_GPIO2 pins!!  Failure to ground these pins will cause much higher current drain during ULP sleep mode.

 

BEGIN RANT

 

After 9 months of experimenting, researching, asking Atmel Support for help and virtually pulling my hair out, Finally the mysteries around Samb11 ULP are uncovered and understood. I wonder how many engineers have simply tossed this stuff in the trash can and given up, instead of investing the kind of time that was required to work around these product quality problems.  The only reason I'm still using the Samb11 is because it's still the lowest power BLE device available.... and I have so much time and effort invested in the firmware, I just can't face having to start over again.

 

END RANT

 

I hope this post and workaround helps others avoid the pain, misery and wasted time this has put me through.  Good news is, I am now able to continue with my project using the workaround.  I sure wish Atmel would wake up and post a useful, working example of the Samb11 device being used properly in ULP mode with external events, that actually works the way it's advertised in all the data sheets, web pages and marketing materials out there.  This device has so much potential, if the ASF team would simply get this stuff fixed and provide higher quality output and examples.

 

 

 

 

Attachment(s): 

Last Edited: Fri. Feb 16, 2018 - 04:15 PM