Okay... I finally had time to look into this issue. I'm quite enamored with the TimeSquare kit, and the code is nothing short of gorgeous. Bravo!
A major selling point of Atmel's picoPower chips is that they can safely run on <1uA, but the only way to do that is disabling BOD during sleep. So if disabling BOD during sleep is unsafe, it's a
huge deal, which is why I think this issue is worth looking into.
Unfortunately, I was unable to replicate the BOD-disable problem. How certain are you that the problems during testing were related to disabling BOD? Is it possible that you were disabling BOD in the fuses (definitely unsafe) rather than in the code (allegedly safe--at least according to Atmel)?
I still have the test setup described below in a corner of my closet. Is there anything I could be doing better?
EDIT: Just to be clear, I am
not criticizing the TimeSquare design or code, and I agree that there is little to no benefit of lowering sleep current further in the watch. But I am trying figure out if my favorite power-saving trick--disabling BOD during sleep--is actually something I should stop doing, at least with a bootloader.
Testing method: On the TimeSquare, I changed the sleep code to disable BOD in Watch.cpp:
Code: Select all
cli();
uint8_t mcucr1, mcucr2;
mcucr1 = MCUCR | _BV(BODS) | _BV(BODSE); //turn off the brown-out detector
mcucr2 = mcucr1 & ~_BV(BODSE);
MCUCR = mcucr1;
MCUCR = mcucr2;
sei(); // Keep interrupts enabled during sleep
sleep_cpu();
I'm not sure if it was necessary, but I also disabled the analog comparator with "ACSR = _BV(ACD);" in the Watch::begin() function. With those changes, the watch consumed less than a microamp while sleeping.
To simulate the kind of brown-outs that might happen during battery replacement, I breadboarded a DC Boarduino to control the simulation, a LM317 to provide battery-like voltage, and three n-FETs to toggle buttons and power. A 0.1 uF cap in parallel with the watch allowed voltage to sag more gradually after the power was turned off:
- BOD-disable test setup
- breadboard.jpg (53.34 KiB) Viewed 1504 times
The DC Boarduino ran the following sketch. In the loop, the code allows the watch to sleep, cuts watch power for a specified amount of time, restores power, and presses a button to wake the watch.
Code: Select all
#define SET_FET 2 // digital 2 (PD2) on timesquare
#define PLUS_FET 3 // digital 3 (PD3) on timesquare
#define POWER_FET 4
//#define OFF_TIME 199 // max w/ multimeter
#define OFF_TIME 258 // max w/o multimeter
void setup() {
pinMode(SET_FET, OUTPUT);
pinMode(PLUS_FET, OUTPUT);
pinMode(POWER_FET, OUTPUT);
// start with power off and no buttons pressed
digitalWrite(SET_FET, LOW);
digitalWrite(PLUS_FET, LOW);
digitalWrite(POWER_FET, LOW);
delay(1000);
// power on; wait for startup
digitalWrite(POWER_FET, HIGH);
delay(2000);
// push button for 0.1 seconds
digitalWrite(SET_FET, HIGH);
delay(100);
digitalWrite(SET_FET, LOW);
delay(100);
// exit set-time mode
digitalWrite(SET_FET, HIGH);
digitalWrite(PLUS_FET, HIGH);
delay(2500);
digitalWrite(SET_FET, LOW);
digitalWrite(PLUS_FET, LOW);
delay(5000);
}
void loop() {
// briefly turn off power
digitalWrite(POWER_FET, LOW);
delay(OFF_TIME);
digitalWrite(POWER_FET, HIGH);
delay(5000);
// display time
digitalWrite(SET_FET, HIGH);
delay(100);
digitalWrite(SET_FET, LOW);
delay(5000);
}
With a multimeter measuring voltage, the watch could consistently endure a 199ms power loss while sleeping, which caused voltage to sag to just under one volt. A longer power loss caused the watch to reset when power was restored. That makes sense because, according to the Atmel literature, the RAM/registers are valid to ~0.3v, but a voltage below ~1v will trigger a power-on reset when power is restored, thereby ensuring the validity of the RAM/registers when BOD is disabled during sleep.
- Voltage during test
- measurements.jpg (30.7 KiB) Viewed 1504 times
It surprised me that my multimeter was pulling enough current to make a significant difference in the maximum length of a power-loss, but it did. So for my actual testing, I increased the duration of the power loss to 258ms.
After over 12 hours and more than 3000 simulated brown-outs, the TimeSquare watch still works perfectly. If the probability of program corruption was 1%, the probability of no corruption is 99%. That means the probability of no corruption after 3000 trials would be 0.99^3000--less than one in a trillion.
EDIT 2: My test methodology was quite specific, so I only proved that my brown-out test was not sufficient to cause program memory corruption with a frequency of 1%. It is entirely possible that a different test would cause program memory corruption with a frequency of 1%, as claimed in the comment I quoted in the initial post of this thread.
pburgess wrote:...bringing it up with Limor, who was like, "Oh yeah, that. Ran into that with the x0xb0x. Don't disable BOD when you have a bootloader, bad mojo happens." So there's apparently a long precedent with this...
I was looking at the
parts list for the x0xb0x, and it uses the ATmega162, which is not a picoPower device and does not support software BOD-disable. The only way to disable BOD would have been in the fuses, and disabling BOD that way will definitely cause problems (unless lockbits are set to prevent self-programming).