I am trying to create a software disable of BOD. I currently have the fuses set for BOD to be enabled at 1.8v on my tiny84. However, I want to disable the BOD during sleep in order to save power (i know its not much but its relevant). My attiny84 (running arduino-tiny core) is version C so according to the datasheet it should have the feature to do the disable.
According to the datasheet:
In order to disable BOD during sleep (see Table 7-1 on page 33) the BODS bit must be written to
logic one. This is controlled by a timed sequence and the enable bit, BODSE in MCUCR. First,
both BODS and BODSE must be set to one. Second, within four clock cycles, BODS must be set to one and BODSE must be set to zero. The BODS bit is active three clock cycles after it is set. A sleep instruction must be executed while BODS is active in order to turn off the BOD for the actual sleep mode. The BODS bit is automatically cleared after three clock cycles.
So currently my code has a watchdog timer set for every 4 seconds.
The following method ensures all the pins are correctly positioned before sleep and allows me to sleep in multiples of 4 seconds to reach longer sleeps (30-60 seconds)
void timedSleep(int waitTime)
{
digitalWrite(ampPowPin,LOW);
pinMode(transPowPin,INPUT); // transmitter power pin
pinMode(ampPowPin,INPUT);
pinMode(txPin,INPUT);
pinMode(ledPin,INPUT);
// Calculate the delay time
int waitCounter = 0;
while (waitCounter != waitTime)
{
system_sleep();
waitCounter++;
}
pinMode(txPin,OUTPUT);
pinMode(ledPin,OUTPUT);
pinMode(ampPowPin,OUTPUT);
digitalWrite(ampPowPin,HIGH);
}
This method is called by the above method and should stop the BOD and put the chip to sleep but its not working properly.
void system_sleep() {
cbi(ADCSRA,ADEN); // switch Analog to Digitalconverter OFF
set_sleep_mode(SLEEP_MODE_PWR_DOWN); // sleep mode is set here
sleep_enable();
MCUCR = (1<<BODS) | (1<<BODSE); // set both BODS and BODSE to 1
MCUCR = (1<<BODS) | (0<<BODSE); // set BODS to 1 and BODSE to 0
sleep_cpu (); // sleep within 3 clock cycles of above
//sleep_mode(); // System sleeps here
sleep_disable(); // System continues execution here when watchdog timed out
sbi(ADCSRA,ADEN); // switch Analog to Digitalconverter ON
}
The problem is that you are disabling the Sleep enable bit when you set the BODS and BODSE bits because you are using an assignment not a bitwise or. However in this case you have to as you are clearing a bit as well.
You need to replace this code:
sleep_enable();
MCUCR = (1<<BODS) | (1<<BODSE); // set both BODS and BODSE to 1
MCUCR = (1<<BODS) | (0<<BODSE); // set BODS to 1 and BODSE to 0
With one of these two
(1)
MCUCR = (1<<BODS) | (1<<BODSE); // set both BODS and BODSE to 1
MCUCR = (1<<BODS) | (0<<BODSE); // set BODS to 1 and BODSE to 0
sleep_enable(); //this should allow sleep_cpu() to still be called within 3 clock cycles as this only takes one (sbi instruction)
(2)
MCUCR = (1<<BODS) | (1<<BODSE); // set both BODS and BODSE to 1
MCUCR = (1<<SE) | (1<<BODS) | (0<<BODSE); // set BODS to 1 and BODSE to 0, set the sleep enable bit at the same time.
For some reason both of the code examples you gave me ended up not working. They both caused my tiny84 to not go to a complete sleep state (sleep at .74mA rather than .02mA) so im not sure exactly what it did.
However I did find code that does work properly in my project
set_sleep_mode(SLEEP_MODE_PWR_DOWN); // sleep mode is set here
sleep_enable();
MCUCR = MCUCR | bit(BODSE) | bit(BODS); // timed sequence
MCUCR = MCUCR & ~ bit(BODSE) | bit(BODS);
sleep_cpu();
MCUCR |= _BV(SE)
in other words:
MCUCR = MCUCR | (1<<SE);
EDIT:
I see what happened, you were not just overwriting the SE bit, but also the sleep mode select bits essentially putting it into idle mode sleep.
Just for pretty codes sake, your code can be written equally as:
set_sleep_mode(SLEEP_MODE_PWR_DOWN); // sleep mode is set here
sleep_enable();
MCUCR |= bit(BODSE) | bit(BODS); // timed sequence
MCUCR = (MCUCR & ~bit(BODSE)) | bit(BODS);
sleep_cpu();
But that is just personal preference as it better shows what is happening. Both are perfectly valid.
Out of curiosity, does this work:
set_sleep_mode(SLEEP_MODE_PWR_DOWN); // sleep mode is set here
sleep_enable();
MCUCR |= bit(BODSE) | bit(BODS); // timed sequence
MCUCR &= ~bit(BODSE); //BODS is already high.
sleep_cpu();
It may not do as the second modification of MCUCR will optimise to use the cbi() which means both are not being written at the same time. It would be interesting to know if it does work though.
Your rewrite code did work perfectly. However your second code block does not work. It does allow the mC to go into power down sleep but does not disable the BOD.
Thanks alot btw. Bitwise operators sometimes hurt my head... gotta sit down and take it step by step haha.