Hi,
Peter: yes I guess it could be a current spike, that would explain why things seems more stable at the bench where I use an Arduino UNO with USB power supply from a powered hub. The target board is an Modern Device RBBB (http://moderndevice.com/product/rbbb-kit/) running at 3.3V, regulator L493133 max 250mA, however I shouldn't be close to that. Measuring at the bench with UNO 5V I'm getting ~150mA full power. I can't measure peaks very well with my meter. Power is coming from 4AA Duracell, reasonably new.
Yeah, I have to confess I didn't write the sleep code, just copied from elsewhere.
Nick: see code below. I had to remove some comments as it was exceeding the 9K limit. It's hard to streamline further without knowing the cause of the problem.
Regards,
Luiz
#include <avr/sleep.h>
#include <avr/power.h>
#include <AltSoftSerial.h>
#include <PinChangeInt.h>
#include <XBee.h>
XBeeAddress64 COORDINATOR = XBeeAddress64(0x00, 0x00);
XBee xbee = XBee();
uint8_t ssRX = 2;
uint8_t ssTX = 3;
AltSoftSerial nss;
const int numPins = 6;
const int START_PIN = 2;
const int XBEE_SLEEP = 10;
const int PIN_LED = 11;
const uint8_t pins[numPins] = { 2, 3, 4, 5, 6, 7 };
const uint8_t NO_PIN = 255;
volatile bool interruptState = false;
int sleepIterations = 0;
volatile bool watchdogActivated = false;
#define LOGGING_FREQ_SECONDS 3600 // Seconds to wait before a new sensor reading is logged.
#define MAX_SLEEP_ITERATIONS LOGGING_FREQ_SECONDS / 8 // Number of times to sleep (for 8 seconds) before
// a sensor sending XBee ping to the coordinator.
// Define watchdog timer interrupt.
ISR(WDT_vect)
{
// Set the watchdog activated flag.
watchdogActivated = true;
}
void send(ZBTxRequest& zbTx)
{
// try a few times before giving up
for(int i=0;i<20;i++)
{
xbee.send(zbTx);
if (xbee.readPacket(1000))
{
ZBTxStatusResponse tx = ZBTxStatusResponse();
if (xbee.getResponse().getApiId() == ZB_TX_STATUS_RESPONSE)
{
xbee.getResponse().getZBTxStatusResponse(tx);
int st = tx.getDeliveryStatus();
Serial.print("TX status: ");
Serial.println(st);
// get the delivery status, the fifth byte
if (st == SUCCESS)
{
Serial.println("Transmission OK");
// Reset the number of sleep iterations.
sleepIterations = 0;
return;
}
}
}
Serial.println("Error sending command. Will try again");
delay(500);
}
Serial.println("Failed to transmit!");
}
bool sendAtCommand(AtCommandRequest& atRequest, uint8_t* buffer, int& size)
{
Serial.println("Sending command to the XBee");
AtCommandResponse atResponse = AtCommandResponse();
// send the command
xbee.send(atRequest);
if (xbee.readPacket(5000))
{
// should be an AT command response
if (xbee.getResponse().getApiId() == AT_COMMAND_RESPONSE)
{
xbee.getResponse().getAtCommandResponse(atResponse);
if (atResponse.isOk())
{
Serial.print("Command [");
Serial.print(atResponse.getCommand()[0]);
Serial.print(atResponse.getCommand()[1]);
Serial.println("] was successful!");
if (atResponse.getValueLength() > 0)
{
Serial.print("Command value length is ");
Serial.println(atResponse.getValueLength(), DEC);
Serial.print("Command value: ");
uint8_t* r = atResponse.getValue();
for (int i = 0; i < atResponse.getValueLength() && i<size; i++)
{
Serial.print(r[i], HEX);
buffer[i] = r[i];
Serial.print(" ");
}
size = atResponse.getValueLength();
Serial.println("");
return true;
}
}
else
{
Serial.print("Command return error code: ");
Serial.println(atResponse.getStatus(), HEX);
}
}
else
{
Serial.print("Expected AT response but got ");
Serial.print(xbee.getResponse().getApiId(), HEX);
}
}
else
{
// at command failed
if (xbee.getResponse().isError())
{
Serial.print("Error reading packet. Error code: ");
Serial.println(xbee.getResponse().getErrorCode());
}
else
{
Serial.print("No response from radio");
}
}
return false;
}
void waitXBeeJoinNetwork()
{
// serial high
uint8_t shCmd[] = {'S','H'};
// serial low
uint8_t slCmd[] = {'S','L'};
// association status
uint8_t assocCmd[] = {'A','I'};
uint8_t buffer[16];
AtCommandRequest atRequest = AtCommandRequest(shCmd);
// set command to AI
atRequest.setCommand(assocCmd);
Serial.println("Waiting XBee to join network...");
for(int i=0;i<1000;i++)
{
int size = 16;
if (sendAtCommand(atRequest,buffer,size) && buffer[0]==0)
{
Serial.print("Done. Number of tries: ");
Serial.println(i+1, DEC);
return;
}
Serial.println("Not yet, trying again...");
delay(1000);
}
}
void txStates(char reasonTX)
{
uint8_t pinsState[numPins];
digitalWrite(PIN_LED, HIGH);
digitalWrite(XBEE_SLEEP, LOW); // Wakeup Xbee
delay(50);
// Prepare for read
for(int i=0;i<numPins;i++)
pinMode(pins[i], INPUT_PULLUP); //set the pin to input
bool tx = true;
while(tx)
{
char buffer[numPins+2];
for(int i=0;i<numPins;i++)
{
buffer[i] = digitalRead(pins[i]) + '0';
}
buffer[numPins] = reasonTX;
buffer[numPins+1] = 0;
Serial.print("Sending ");
Serial.println(buffer);
ZBTxRequest zbTx = ZBTxRequest(COORDINATOR, (uint8_t*)buffer, numPins+2);
send(zbTx);
tx = false;
// The code above can be slow. Check at the end if
// we are still current
for(int i=0;i<numPins;i++)
{
if (buffer[i] != (digitalRead(pins[i]) + '0'))
{
tx = true;
Serial.println("Retransmit required...");
break;
}
}
}
digitalWrite(PIN_LED, LOW);
}
void setup()
{
pinMode(PIN_LED, OUTPUT);
digitalWrite(PIN_LED, HIGH);
Serial.begin(115200);
Serial.print("PinChangeInt test on pins ");
for(int i=0;i<numPins;i++)
{
Serial.print(pins[i]);
Serial.print(',');
pinMode(pins[i], INPUT_PULLUP); //set the pin to input
//pinsState[i] = digitalRead(pins[i]);
}
Serial.println(' ');
// Turn off the ADC while asleep.
power_adc_disable();
pinMode(XBEE_SLEEP, OUTPUT); // XBee sleep control
digitalWrite(XBEE_SLEEP, LOW); // deassert to keep radio awake when sleep mode selected
nss.begin(9600);
// Tell XBee to use AltSoftwareSerial
xbee.setSerial(nss);
waitXBeeJoinNetwork();
txStates('I');
noInterrupts();
// Set the watchdog reset bit in the MCU status register to 0.
MCUSR &= ~(1<<WDRF);
// Set WDCE and WDE bits in the watchdog control register.
WDTCSR |= (1<<WDCE) | (1<<WDE);
// Set watchdog clock prescaler bits to a value of 8 seconds.
WDTCSR = (1<<WDP0) | (1<<WDP3);
// Enable watchdog as interrupt only (no reset).
WDTCSR |= (1<<WDIE);
// Enable interrupts again.
interrupts();
digitalWrite(PIN_LED, LOW);
Serial.println("setup completed!");
}
void sleepNow() // here we put the arduino to sleep
{
digitalWrite(XBEE_SLEEP, HIGH); // put XBee to sleep
set_sleep_mode(SLEEP_MODE_PWR_DOWN); // sleep mode is set here
sleep_enable(); // enables the sleep bit in the mcucr register
// so sleep is possible. just a safety pin
for(int i=0;i<numPins;i++) // setup interrupt handlers
PCintPort::attachInterrupt(pins[i], interruptHandler, CHANGE);
Serial.println("Going to sleep...");
//delay(50);
sleep_mode(); // here the device is actually put to sleep!!
// THE PROGRAM CONTINUES FROM HERE AFTER WAKING UP
sleep_disable(); // first thing after waking from sleep: disable sleep...
//delay(50);
Serial.println("Awake!");
for(int i=0;i<numPins;i++) // remove interrupt handlers to avoid being called until next sleep cycle.
PCintPort::detachInterrupt(pins[i]);
}
void interruptHandler()
{
interruptState = true;
delay(500);
}
void loop()
{
// Check if awaken because of watchDog.
if (watchdogActivated)
{
Serial.println("Watchdog");
watchdogActivated = false;
sleepIterations += 1;
if (sleepIterations >= MAX_SLEEP_ITERATIONS)
{
Serial.println("Active!");
sleepIterations = 0;
txStates('F');
}
}
if (interruptState)
{
Serial.println("Pin change");
interruptState = false;
txStates('C');
}
sleepNow();
}