Hello,
I am building a long range sensor that will take a reading once an hour, and I'd like not to have to change the battery more often than 6 months.
I am using an RFM69HW off an ATTiny1614:
(https://user-images.githubusercontent.com/534681/110448035-bb524180-80b8-11eb-82c9-c8b545f603ad.png)
(note the current measurements below are after the regulator)
Using the ATTiny1614 PIT with `SLEEP_MODE_PWR_DOWN` enabled I can get 0.5uA sleep current without the RFM69HW module connected.
When I attach the RFM69HW as per the above schematic, without doing anything else, I get a sleep current of 1500uA, ie. the RFM69 is consuming ~1500uA in idle which matches the datasheet value of `IDDST`.
When I initialise the radio and run `radio.sleep()` this drops to 200uA, which is still a ways above the `IDDSL` value of max 1uA.
I'm wondering if I'm missing anything basic in the sketch below? Or should I add in a power switch like a BSS84 to electrically isolate the radio?
// go to sleep with lowest power mode, for profiling
// burn bootloader with brown out detection disabled
// set clock to 1MHz
#include <avr/sleep.h>
#include <util/delay.h>
#include <RFM69.h> // https://github.com/lowpowerlab/rfm69
#include <SPI.h>
#define NODEID 99 // id of this device
#define NETWORKID 1 // your network id
#define GATEWAYID 1 // id of your gateway
#define FREQUENCY RF69_433MHZ
#define IS_RFM69HW_HCW //uncomment only for RFM69HW/HCW! Leave out if you have RFM69W/CW! See https://lowpowerlab.com/guide/moteino/transceivers/
RFM69 radio;
// setup for the RTC
void RTC_init(void) {
// initialise RTC:
RTC.CLKSEL = RTC_CLKSEL_INT1K_gc; // 1.024kHz Internal Ultra-Low-Power Oscillator (from OSCULP32K)
while (RTC.STATUS > 0 || RTC.PITSTATUS); // Wait for all registers to be synchronised
RTC.PITINTCTRL = RTC_PI_bm; // PIT Interrupt: enabled
RTC.PITCTRLA = RTC_PERIOD_CYC1024_gc // Num cycles between interrupt. RTC Clock Cycles 1024, resulting in 1024/1024Hz = every 1 seconds
| RTC_PITEN_bm; // enable PIT counter
}
// interrupt subroutine, runs when PIT wakes up
ISR(RTC_PIT_vect) {
RTC.PITINTFLAGS = RTC_PI_bm; // clear interrupt flag by writing '1' (required)
}
void setup() {
// define unused pins as PULLUP to save power
pinMode(PIN_PA0, INPUT_PULLUP);
//pinMode(PIN_PA1, INPUT_PULLUP); // MOSI
//pinMode(PIN_PA2, INPUT_PULLUP); // MISO
//pinMode(PIN_PA3, INPUT_PULLUP); // SCK
//pinMode(PIN_PA4, INPUT_PULLUP); // NSS
pinMode(PIN_PA5, INPUT_PULLUP);
//pinMode(PIN_PA6, INPUT_PULLUP); // DIO0
pinMode(PIN_PA7, INPUT_PULLUP);
pinMode(PIN_PB0, INPUT_PULLUP);
pinMode(PIN_PB1, INPUT_PULLUP);
pinMode(PIN_PB2, INPUT_PULLUP);
pinMode(PIN_PB3, INPUT_PULLUP);
radio.initialize(FREQUENCY,NODEID,NETWORKID);
#ifdef IS_RFM69HW_HCW
radio.setHighPower(); //must include this only for RFM69HW/HCW!
#endif
radio.sleep(); // sleep radio
RTC_init(); // initialise the RTC timer
set_sleep_mode(SLEEP_MODE_PWR_DOWN); // set sleep mode to POWER DOWN mode
sleep_enable(); // enable sleep mode, but not going to sleep yet
sei(); // enable interrupts
}
void loop() {
_delay_ms(1000); // 1000ms delay for power measurements
sleep_cpu();
}
Update: trying a different board I can get down to 20uA, so there may be some funky parasitic load on the traces? Some bad soldering? Still a way off 1uA
LDO eats about 2-4uA.
MCU Watchdog another few uA. So you can probably cut another 10uA if you do a really good job with the board and the code.
Good layout and clean tracing is essential.