RedBear

Blend / Blend Micro Low Power Settings


Description

This guide will show you how to achieve low power consumption (average 2.6mA) for Blend Micro while the BLE function is active; there are some addtional steps for Blend.

Blend / Blend Micro goes into sleep mode when there is no event to be dealt with. While in sleep mode, the main MCU (ATmega32u4) shuts off all its internal peripherals, including ADC, Analog Comparator, Watch Dog, on-chip debug system, digital input buffer except interrupts that used, TWI, Timer, SPI, USB and USART. When the BLE chip (nRF8001) receives data, it will pull RDYN down to interrupt ATmega32u4 to wake it up. After ATmega32u4 has read the data, it will fall back to sleep mode again. If there is a falling edge on D1 (Int.3), it will also interrupt the ATmega32u4 and wake it up.


Sample files

You can download this Blend_LowPowerSettings.zip which contains all the source files in this guide


Library file changes

1. Follow our Getting Started Guide for Blend Micro or Blend to set up the Arduino IDE, libraries and our BLE Controller app

2. Navigate to folder "Arduino" > "libraries" > "RBL_nRF8001" and open RBL_nRF8001.cpp

3. Add a static variable and initialize it with zero

static unsigned char is_LowPower = 0;

4. Add an API to enable low power consumption. Add a static function to achieve low power consumption and make Blend Micro or Blend go to sleep mode

#if defined(BLEND) || defined(BLEND_MICRO)
void ble_low_power(void)
{
    is_LowPower = 1;
}

static void atmega32u4_Sleep()
{
    ADCSRA &= ~(_BV(ADEN)); // Turn off ADC
    ADCSRB &= ~(_BV(ACME)); // Turn off Analog Comparator
    // Brown-out Detector is disable in Arduino\hardware\blend\boards.txt.
    // The Extended Fuse Byte is setted to 0x0F to achieve this.

    // turn off Watch dog
    SREG = 0X00;
    __asm__ __volatile__ ("wdr" ::);//WDR();
    MCUSR &= ~(1<<WDRF);
    WDTCSR |= _BV(WDCE)|_BV(WDE);
    WDTCSR = 0X00;
    SREG |= 0X80;

    MCUCR |= _BV(JTD); // Disable on-chip debug system.

    DIDR0 = 0xFF; // Analog to digital pin's digital input buffer is turned off

    // Int.6 and Int.3 is used in this example
    EIMSK &= 0xF8;  // Disable INT2..0

    PCICR &=0xFE;  //Disable PCINT7..0
    PCMSK0 = 0x00;

    PRR0 = 0xAD;  // Power Reduction Register
    PRR1 = 0x99;

    set_sleep_mode(SLEEP_MODE_PWR_DOWN);
    sleep_enable();
    sei();
    sleep_cpu();

    sleep_disable();
    sei();
}
#endif

5. Call the function atmega32u4_Sleep() in function process_events()

if (lib_aci_event_get(&aci_state, &aci_data))
{
    ......
}
else
{
    //Serial.println(F("No ACI Events available"));
    // No event in the ACI Event queue and if there is no event in the ACI command queue the arduino can go to sleep
    // Arduino can go to sleep now
#if defined(BLEND) || defined(BLEND_MICRO)
    if(is_LowPower)
    {
        atmega32u4_Sleep();
    }
#endif
    // Wakeup from sleep from the RDYN line
}

6. Replace the ACI interface to use interrupt in function ble_begin(). Since Blend Micro's RDYN is located to D7, the interrupt number is 4, please refer to Arduino's attachInterrupt() for more information about the interrupt numbers

if(is_LowPower)
{
    aci_state.aci_pins.interface_is_interrupt     = true;
}
else
{
    aci_state.aci_pins.interface_is_interrupt     = false;
}

aci_state.aci_pins.interrupt_number           = 4;

7. Open RBL_nRF8001.h in the same folder, add function declaration for ble_low_power();

#if defined(BLEND) || defined(BLEND_MICRO)
void ble_low_power(void);
#endif

8. Navigate to folder "Arduino" > "libraries" > "BLE", open hal_aci_tl.cpp, add code at the beginning of the function m_aci_isr() so that you can use the Arduino delay API

#if defined(__AVR_ATmega32U4__)
    PRR0 = 0x00;  // Power Reduction Register: open timer
    PRR1 = 0x00;
#endif

9. Save the changes you made to all files


Sample Sketch

1. Start the Arduino IDE and create a new sketch, copy the sample code below

#include <SPI.h>
#include <boards.h>
#include <RBL_nRF8001.h>

int LED = 13;
int Button = 1;

void setup()
{  
    pinMode(LED, OUTPUT);

    pinMode(Button, INPUT);
    digitalWrite(Button, HIGH);
    attachInterrupt(3, BtnDownCB, FALLING );

    // Call the function to enable low power consumption
    ble_low_power();

    // If you are using the Blend, uncomment below
    //ble_set_pins(6, 7);

    // Init. and start BLE library.
    ble_begin();
}

void loop()
{
    if (ble_available() )
    {
        uint8_t temp;
        while ( ble_available() )
        {
            temp = ble_read();
            if('o' == temp)
            {
                temp = ble_read();
                if('n' == temp)
                {
                    digitalWrite(13, HIGH);
                    ble_write_bytes((unsigned char *)"LED on", 6);
                }
                else if('f' == temp && 'f' == ble_read())
                {
                    digitalWrite(13, LOW);
                    ble_write_bytes((unsigned char *)"LED off", 7);
                }
            }
        }
    }

    ble_do_events();  
}

void BtnDownCB()
{   
    PRR0 = 0x00;  // Power Reduction Register: open timer
    PRR1 = 0x00;

    delay(100);  //jitters elimination
    if(LOW == digitalRead(1))
    {
        if ( ble_connected() )
        {
            ble_write_bytes((unsigned char *)"Button down", 11);
        }
    }
}

2. Connect Blend Micro to host PC. Select the board and serial port. Arduino IDE Menu: Tools > Board > Blend Micro 3.3v/8MHz , Arduino IDE Menu: Tools > Serial Port > (Your Serial Port). Then compile and upload the sketch to Blend Micro. If there isn't a serial port for Blend Micro or it can't upload the sketch automatically, you can press the on-board reset button at the beginning of uploading progress

3. Run our BLE Controller app and select Simple Chat from the top-left menu

4. Click "Scan" - if everything is correct, the list will show your BLE devices, select BlendMicro to connect. On success, you can send "on" to light up the on-board LED and send "off" to shut it off

5. Connect a button to Ground and D1. If you press the button down, Simple Chat will receive a message "Button down".


Additional Steps for Blend

You should move the connector to make RDYN conenct to D7 and add the function ble_set_pins(REQN, RDYN); before ble_begin() in you sketch, since we use the interrupt number 4 for RDYN and the corresponding pin is D7.

For example, if we change default settings of REQN from 9 to 6 and RDYN from 8 to 7, the Blend should look like this

And you should add the below line inside the setup() of your sketch

ble_set_pins(6, 7);