add listenModeSleep() + example

This commit is contained in:
Felix Rusu 2020-05-18 13:54:21 -04:00
parent 1bc4b02f22
commit 64eb36ba85
3 changed files with 217 additions and 0 deletions

View File

@ -0,0 +1,142 @@
// **********************************************************************************
// Sample RFM69 sender/node sketch with radio listen mode sleep
// Saves additional 2-3uA over WDT sleep
// **********************************************************************************
// Copyright Felix Rusu 2020, http://www.LowPowerLab.com/contact
// **********************************************************************************
// License
// **********************************************************************************
// This program is free software; you can redistribute it
// and/or modify it under the terms of the GNU General
// Public License as published by the Free Software
// Foundation; either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will
// be useful, but WITHOUT ANY WARRANTY; without even the
// implied warranty of MERCHANTABILITY or FITNESS FOR A
// PARTICULAR PURPOSE. See the GNU General Public
// License for more details.
//
// Licence can be viewed at
// http://www.gnu.org/licenses/gpl-3.0.txt
//
// Please maintain this license information along with authorship
// and copyright notices in any redistribution of this code
// **********************************************************************************
#include <RFM69.h>
#include <RFM69_ATC.h>
#include <LowPower.h>
#include <PString.h> //easy string manipulator: http://arduiniana.org/libraries/pstring/
//*********************************************************************************************
//************ IMPORTANT SETTINGS - YOU MUST CHANGE/CONFIGURE TO FIT YOUR HARDWARE ************
//*********************************************************************************************
#define NODEID 123 //must be unique for each node on same network (range up to 254, 255 is used for broadcast)
#define NETWORKID 100 //the same on all nodes that talk to each other (range up to 255)
#define GATEWAYID 1
#define FREQUENCY RF69_915MHZ //match the RFM69 version! Others: RF69_433MHZ, RF69_868MHZ
//#define FREQUENCY_EXACT 916000000
#define IS_RFM69HW //uncomment only for RFM69HW! Leave out if you have RFM69W!
#define ENCRYPTKEY "sampleEncryptKey" //exactly the same 16 characters/bytes on all nodes!
#define ENABLE_ATC //comment out this line to disable AUTO TRANSMISSION CONTROL
#define ATC_RSSI -90
// **********************************************************************************
//to avoid the buggy listen mode high resolution timer TRANSMITPERIOD should always be > 262ms
#define TRANSMITPERIOD 3000 //sleep time in ms
//#define WDTSLEEP //uncomment to sleep with WDT instead (compare sleep currents!)
// **********************************************************************************
#define SERIAL_EN //comment this out when deploying to an installed SM to save a few KB of sketch size
#define SERIAL_BAUD 115200
#ifdef SERIAL_EN
#define DEBUG(input) Serial.print(input)
#define DEBUGln(input) Serial.println(input)
#define DEBUGFlush() Serial.flush()
#else
#define DEBUG(input)
#define DEBUGln(input)
#define DEBUGFlush()
#endif
// **********************************************************************************
#ifdef ENABLE_ATC
RFM69_ATC radio;
#else
RFM69 radio;
#endif
char buff[61]; //61 max payload for radio
PString Pbuff(buff, sizeof(buff));
// **********************************************************************************
void setup() {
pinMode(LED_BUILTIN, OUTPUT);
#ifdef SERIAL_EN
Serial.begin(SERIAL_BAUD);
#endif
if (!radio.initialize(FREQUENCY,NODEID,NETWORKID))
DEBUG("radio.init() FAIL");
else
DEBUG("radio.init() SUCCESS");
#ifdef IS_RFM69HW
radio.setHighPower(); //uncomment only for RFM69HW!
#endif
#ifdef FREQUENCY_EXACT
radio.setFrequency(FREQUENCY_EXACT); //set frequency to some custom frequency
#endif
#ifdef ENCRYPTKEY
radio.encrypt(ENCRYPTKEY);
#endif
#ifdef ENABLE_ATC
radio.enableAutoPower(ATC_RSSI);
#endif
Pbuff = F("Transmitting at ");
Pbuff.print(FREQUENCY==RF69_433MHZ ? 433 : FREQUENCY==RF69_868MHZ ? 868 : 915);
Pbuff.print(F("Mhz..."));
DEBUGln(buff);
#ifdef ENABLE_ATC
DEBUGln("RFM69_ATC Enabled (Auto Transmission Control)\n");
#endif
}
uint32_t packetCounter=0;
void loop() {
Pbuff = F("PACKET #");
Pbuff.print(packetCounter++);
DEBUGln(buff);
digitalWrite(LED_BUILTIN, HIGH);
radio.sendWithRetry(GATEWAYID, buff, Pbuff.length());
digitalWrite(LED_BUILTIN, LOW);
DEBUGFlush();
#ifdef WDTSLEEP
radio.sleep();
LowPower.longPowerDown(TRANSMITPERIOD);
#else
if (TRANSMITPERIOD%262 && TRANSMITPERIOD > 262*2)
{
DEBUG("Sleeping "); DEBUGln(TRANSMITPERIOD-TRANSMITPERIOD%262-262); DEBUGFlush();
radio.listenModeSleep(TRANSMITPERIOD-TRANSMITPERIOD%262-262);
DEBUG("Sleeping "); DEBUGln(TRANSMITPERIOD%262 + 262); DEBUGFlush();
radio.listenModeSleep(TRANSMITPERIOD%262 + 262);
}
else {
DEBUG("Sleeping "); DEBUGln(TRANSMITPERIOD); DEBUGFlush();
radio.listenModeSleep(TRANSMITPERIOD);
}
//wakeup (must reinit)
radio.RFM69::initialize(FREQUENCY,NODEID,NETWORKID); //call base init!
#ifdef ENCRYPTKEY
radio.encrypt(ENCRYPTKEY);
#endif
#ifdef FREQUENCY_EXACT
radio.setFrequency(FREQUENCY_EXACT);
#endif
#endif
}

View File

@ -26,6 +26,7 @@
#include "RFM69.h"
#include "RFM69registers.h"
#include <SPI.h>
#include <LowPower.h> //http://github.com/LowPowerLab/LowPower
uint8_t RFM69::DATA[RF69_MAX_DATA_LEN+1];
uint8_t RFM69::_mode; // current transceiver state
@ -864,6 +865,73 @@ void RFM69::rcCalibration()
while ((readReg(REG_OSC1) & RF_OSC1_RCCAL_DONE) == 0x00);
}
// ListenMode sleep/timer
void RFM69::listenModeSleep(uint16_t millisInterval)
{
setMode( RF69_MODE_STANDBY );
while ((readReg(REG_IRQFLAGS1) & RF_IRQFLAGS1_MODEREADY) == 0x00); // wait for ModeReady
detachInterrupt( _interruptNum );
//attachInterrupt( _interruptNum, delayIrq, RISING);
writeReg( REG_DIOMAPPING1, RF_DIOMAPPING1_DIO0_11 );
writeReg( REG_BITRATEMSB, RF_BITRATEMSB_200000);
writeReg( REG_BITRATELSB, RF_BITRATELSB_200000);
writeReg( REG_FDEVMSB, RF_FDEVMSB_100000 );
writeReg( REG_FDEVLSB, RF_FDEVLSB_100000 );
writeReg( REG_RXBW, RF_RXBW_DCCFREQ_000 | RF_RXBW_MANT_16 | RF_RXBW_EXP_0 );
uint8_t idleResol;
uint32_t divisor;
uint32_t microInterval = millisInterval * 1000L;
if( microInterval > 255 * 4100L ) {
idleResol = RF_LISTEN1_RESOL_IDLE_262000;
divisor = 262000;
}
else if( microInterval > 255 * 64L ) {
idleResol = RF_LISTEN1_RESOL_IDLE_4100;
divisor = 4100;
}
else {
idleResol = RF_LISTEN1_RESOL_IDLE_64;
divisor = 64;
}
writeReg( REG_LISTEN1, RF_LISTEN1_RESOL_RX_64 | idleResol | RF_LISTEN1_CRITERIA_RSSI | RF_LISTEN1_END_10 );
writeReg( REG_LISTEN2, (microInterval + (divisor >> 1 ) ) / divisor );
writeReg( REG_LISTEN3, 4 );
writeReg( REG_RSSITHRESH, 255 );
writeReg( REG_RXTIMEOUT2, 1 );
writeReg( REG_OPMODE, RF_OPMODE_SEQUENCER_ON | RF_OPMODE_STANDBY );
writeReg( REG_OPMODE, RF_OPMODE_SEQUENCER_ON | RF_OPMODE_STANDBY | RF_OPMODE_LISTEN_ON );
attachInterrupt( _interruptNum, delayIrq, RISING);
LowPower.powerDown( SLEEP_FOREVER, ADC_OFF, BOD_OFF );
LowPower.powerDown( SLEEP_FOREVER, ADC_OFF, BOD_OFF );
LowPower.powerDown( SLEEP_FOREVER, ADC_OFF, BOD_OFF );
endListenModeSleep();
}
//=============================================================================
// endListenModeSleep() - called by listenModeSleep()
//=============================================================================
void RFM69::endListenModeSleep()
{
detachInterrupt( _interruptNum );
writeReg( REG_OPMODE, RF_OPMODE_SEQUENCER_ON | RF_OPMODE_LISTENABORT | RF_OPMODE_STANDBY );
writeReg( REG_OPMODE, RF_OPMODE_SEQUENCER_ON | RF_OPMODE_STANDBY );
writeReg( REG_RXTIMEOUT2, 0 );
setMode( RF69_MODE_STANDBY );
while ((readReg(REG_IRQFLAGS1) & RF_IRQFLAGS1_MODEREADY) == 0x00); // wait for ModeReady
}
//=============================================================================
// delayIRQ() - called by listenModeSleep()
//=============================================================================
void RFM69::delayIrq() { return; }
//=============================================================================
// ListenMode specific functions
//=============================================================================

View File

@ -228,6 +228,9 @@ class RFM69 {
void readAllRegs();
void readAllRegsCompact();
// ListenMode sleep/timer
void listenModeSleep(uint16_t millisInterval);
protected:
static void isr0();
void interruptHandler();
@ -235,6 +238,10 @@ class RFM69 {
static volatile bool _haveData;
virtual void sendFrame(uint16_t toAddress, const void* buffer, uint8_t size, bool requestACK=false, bool sendACK=false);
// for ListenMode sleep/timer
static void delayIrq();
void endListenModeSleep();
uint8_t _slaveSelectPin;
uint8_t _interruptPin;
uint8_t _interruptNum;