Continue from where you left on the ATtiny85 sleep modes tutorial to be able to save more power.
Introduction
Last time, Basic Coding taught you how to code for the ATtiny85 sleep modes. However, you may have observed you were only having minimal power savings. With this, you should learn how to optimize your power saving setup. You’ll learn this here in this blog.
Why You're not Saving Enough Power
There are several factors you have to consider why you’re not saving enough power during sleep mode and they are listed below.
- You’re not powering down unused peripherals or blocks on your MCU.
- You’ve failed to disable unused clock sources to peripherals especially on Idle mode.
- You’re wasting power on unnecessary I/O port functions.
Disable or Power Down Unused Peripherals or Blocks
You should be able to power down peripherals that you don’t use during sleep, such as the one’s below:
ADC—You can easily power off the ADC using the library and statement below. Note that the ADC is enabled by default and can still be enabled even during power down.
#include
// Turn OFF ADC to save power
ADCSRA &= ~(1 << ADEN);
Comparator – Disable the Comparator through the library and statement below if it is enabled.
#include
// Disable the analog comparator by setting the ACD bit in ACSR
ACSR |= (1 << ACD);
3. BOD or Brown-out Detect Circuit. – The brown-out detect circuit can be disabled through the option fuses. You may use AVRDUDESSÂ for this. Some revisions of ATtiny85 (version C) can have their BOD disabled by software through assembly routines. You can search for a Lowpower library for this.
4. Internal Voltage Reference – This block can be disabled by disabling the ADC, Comparator, and BOD circuit.
5. Watchdog Timer—If enabled, the watchdog timer can be disabled in code through the library and statements below. You can also disable it through the option fuses.
#include
// Disable the watchdog timer
wdt_disable();
Disable Clocks to Unused Peripherals
You may disable clocks on unused peripherals by utilizing the Power Reduction Register (PRR). You can disable clocks to Timer0/1, the USI, and ADC peripherals by writing a one to their corresponding PRR bit register. Note that the ADC should be disabled before shutting it down. Disabling clocks to peripherals is particularly useful on Idle sleep and active modes. You usually don’t need to use PRR in power down mode since the oscillator is alrady stpped in this mode.
Don't Waste Power on your Ports
Don’t waste precious power on these critical lines, be they analog or digital ports. Most importantly, and obviously, don’t drive resistive loads during sleep, as this will incur additional current.
On input ports, some digital input ports can have their input buffers still turned on on certain sleep mode setups. With this, it’s important for that input to have a defined value and not keep it floating. Not doing so can increase your circuit’s overall current. Put a pull-up resistor or activate an internal pull-up for this.
You also can’t ignore the input analog ports when using the ADC since some ports are multiplexed with digital pins. Because of this, it’s better to forcefully disable the digital input buffers on that port. Having an undetermined analog voltage on that pin can result in additional current because of the digital input buffer. Disable that digital buffer using the Digital Input Disable Register (DIDR0).
Testing with Optimized Power Savings Setup
Wake Up with User Intervention (Button Press)
Last time, you tried waking up your MCU by pressing a button. However, power savings can only go up to 300uA. Why? It’s because the ADC is still enabled. Fortunately, the other peripherals (such as the comparator) and some fuses (such as the Watchdog and BOD) are not enabled by default. Below is an improved and optimized version of the code.
#include
#include
#define BUZZER PB3
#define BUTTON PB4
void setup() {
// put your setup code here, to run once:
pinMode(BUTTON, INPUT_PULLUP);
pinMode(BUZZER, OUTPUT);
// Turn OFF ADC to save power
ADCSRA &= ~(1 << ADEN);
// Sleep Mode
set_sleep_mode(SLEEP_MODE_PWR_DOWN);
// Set Change on Interrupt Pin
attachPCINT(digitalPinToPinChangeInterrupt(BUTTON), PinChangeDet, FALLING);
}
void loop() {
// put your main code here, to run repeatedly:
// Enable Sleep
sleep_enable();
// Sleep upon startup Zzzz..
sleep_cpu();
// Unsleep here... must wake-up on pin change interrupt
sleep_disable();
// Door Melody Chime
chime();
}
void PinChangeDet(void) {
// do nothing... must wake up the MCU
}
void chime(void)
{
byte i;
for(i=0;i<10;i++)
{
digitalWrite(BUZZER, HIGH);
delay(100);
digitalWrite(BUZZER, LOW);
delay(100);
}
}
With this code, you can go down to almost a fraction of a micro ampere. With proper setup (such as a lower supply voltage – 3.0V and lower oscillator value – 1 MHz), you should ideally be able to go down up to 0.2uA.
Periodic Wake Up Using a Watchdog Timer
The same goes for the periodic wakeup using the watchdog timer. However, note that the watchdog timer incurs a small amount of current that can add to the power down current.
#include
#include
#include
#include
#define LED PB3
void setup() {
pinMode(LED, OUTPUT);
// Set Watchdog Timer to trigger every 1 second
WDTCR |= (1 << WDCE) | (1 << WDE); // Enable Watchdog Timer configuration mode
WDTCR = (1 << WDP2) | (1 << WDP1) | (1 << WDP0); // Set timeout to 1 second
WDTCR |= (1 << WDIE); // Enable Watchdog Timer interrupt
sei(); // Enable global interrupts
// ADC is enabled by default
// Turn OFF ADC to save power
ADCSRA &= ~(1 << ADEN);
// Set the sleep mode to power-down
set_sleep_mode(SLEEP_MODE_PWR_DOWN);
}
ISR(WDT_vect) {
// Watchdog Timer interrupt service routine (ISR)
// This code will run every time the Watchdog Timer triggers
// Turn ON LED
PORTB ^= (1 << PB3);
}
void loop() {
// Put the MCU into sleep mode
sleep_enable();
sleep_cpu(); // Enter sleep mode
// The MCU will continue here after waking up
sleep_disable(); // Disable sleep mode
}
With this code, you can go down up to approximately 6uA, considering that the Watchdog timer is running during power down mode. You’ll see this reading when the scale is brought down to 50uA scale max from the video below.
Hope you’ve learned a lot on this ATtiny85 Sleep Mode Tutorial 🙂