How to disable BOD during sleep mode ?

ATmega328P going to power-down sleep mode.
I would like to disable the Brown-out Detector (BOD) during sleeping cycles.

The datasheet of the MCU (Sections 7.2 and 7.11.2) states that we must follow a sequence as follows:
"The BODS bit must be written to logic one in order to turn off BOD during sleep, see Table 7-1
on page 39. Writing to the BODS bit is controlled by a timed sequence and an enable bit,
BODSE in MCUCR. To disable BOD in relevant sleep modes, both BODS and BODSE must first be set to one. Then, to set the BODS bit, BODS must be set to one and BODSE must be set to zero within four clock cycles.
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."

I tried to do this in my code:
sbi(MCUCR,BODS);
sbi(MCUCR,BODSE);
sbi(MCUCR,BODS);
cbi(MCUCR,BODSE);
sleep_mode();

But it did not work (sleep OK, but no difference in the power consumption).

I also tried to use only:
sbi(MCUCR,BODS);
sbi(MCUCR,BODSE);
sleep_mode();
but it also did not work.

Any ideas?
Thanks

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

How many clock cycles are passing before sleep mode is activated? You'll need to look in sleep_mode() function to see what order the code is executed. You may have to put the BOD disable code right before the sleep code.

Problem solved !!
Actually, there was no problem at all but I discovered something new.

  1. During one of my tests, I edited boards.txt (Arduino IDE) and change the following fuses from 0xFD to 0xFF. Therefore, I voided BOD in hardware and the commands in software have no effect at all... In other words, the BOD is always disabled no matter the state of the MCU (active or sleep).

atmega328.name=Arduino Duemilanove or Nano w/ ATmega328
...
atmega328.bootloader.extended_fuses=0xFF

  1. Related to the BOD deactivation, I found a recent code (http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1295177740/1) that I believe will work. I saw many similar examples at the Internet. However, I still have the opinion that the datasheet was not very good on this BOD explanation:

// turn bod off
MCUCR |= (1<<BODS) | (1<<BODSE);
MCUCR &= ~(1<<BODSE); // must be done right before sleep
sleep_cpu(); // sleep here

  1. New... new... (at least for me). I solved the problem and achieved 1.5 microamp @3.3V, 16MHz crystal. The issue was not related to the BOD, which was already disabled, but the Arduino bootloader!!!!! I do not know why, but when I used AVR Studio 4 to upload the HEX code without the Arduino bootloader, the sleep power consumption changed from 52 microwatt to less than 5 microwatts... By the way, no components external to the MCU, except the crystal and resistor/LED which is activated only when the MCU is active state. I checked the result twice, with 2 different chips and the same program.

Thanks

3.3V, 16MHz crystal

Is that within the operating range of the processor?

Is that within the operating range of the processor?

You are completely right in making this question. Actually, for 3.3V, the maximum clock ("Safe operating area") is approx. 14MHz (based on interpolation at the Fig 28-1 (full ATmega328P datasheet pp321).

Therefore, I am at a dangerous region. It works, but if you have an oscillation of 0.2V, the MCU resets... For instance, when I turn-on the transceiver at maximum TX power (+17dBm), the supply voltage oscillation causes the RESET... Using a large capacitor solves the issue.

Again, you are right and my final design is for 2MHz and I can securely go down to 1.85V without any problem. However, to realize the development, the lack of support of the Arduino IDE for frequencies different than 16MHz is a real problem for me. I saw many hints about how to solve this problem (usually related to the guys wanting the MCU at 20MHz, not a smaller frequency...), but I was not successful due to the lack of a detailed step-by-step guide. It is a pity that the designers of Arduino IDE did not make this support before... I know that there are issues related to the accuracy of the clock-based functions, such as the serial communication, but the option could be there for the use and risk of the user.

Thanks for remembering this important detail about voltage and clock!!

but I was not successful due to the lack of a detailed step-by-step guide. It is a pity that the designers of Arduino IDE did not make this support before...

While I haven't done it personally yet, but the Arduino IDE has a means to define yourself a 'new' board running at any speed you define. There may be some libraries that won't work correctly at a non-standard speed, but that may not be a problem for you?

Anyway the procedure is as follows: (I think, again never done personally)

Locate your Arduino sketchbook folder (you can find its location in the preferences dialog in the Arduino software)
Create a new sub-folder called "hardware" in the sketchbook folder.
Put a copy of the file boards.txt that is located in the Arduino core into this new folder
Modify the file by editing one of the existing board definitions or create a new board definition
Restart the Arduino development environment.

Here is a typical board entry from the standard unmodified boards.txt file from Arduino version 22

##############################################################

atmega328.name=Arduino Duemilanove or Nano w/ ATmega328

atmega328.upload.protocol=stk500
atmega328.upload.maximum_size=30720
atmega328.upload.speed=57600

atmega328.bootloader.low_fuses=0xFF
atmega328.bootloader.high_fuses=0xDA
atmega328.bootloader.extended_fuses=0x05
atmega328.bootloader.path=atmega
atmega328.bootloader.file=ATmegaBOOT_168_atmega328.hex
atmega328.bootloader.unlock_bits=0x3F
atmega328.bootloader.lock_bits=0x0F

atmega328.build.mcu=atmega328p
atmega328.build.f_cpu=16000000L
atmega328.build.core=arduino

##############################################################

So you can either modify a existing board definition or create a whole new board definition. Just change the parameters to match your requirements, note the atmega328.build.f_cpu=16000000L line, that is the speed of crystal or resonator for the board, you would change it to =2000000L if you are using a 2Mhz crystal. After you save the file and reopen the Arduino IDE your board selection menu should include your newly defined board. Anyway that's how it is suppose to work and for something as simple as changing the clock speed I think you only have to change two parameters the one just mentioned and the atmega328.upload.speed=57600 line. If you are using the standard bootloader code the uploading baud rate would be eight times slower running at 2Mhz as it was at running at 16Mhz, so the line should be changed to atmega328.upload.speed=7200

Shouldn't be to hard to play with. No matter how lost you get you can just delete the boards.txt file from your sketch/hardware folder and the Arduino IDE will revert to using the boards.txt file in it's core directory.

Give it a shot and let us know if it worked for you.

Lefty

Lefty, thanks for the suggestion.
Actually, I made the modification at boards.txt and can compile/upload the code. After this point, I can change the crystal and check the functioning of the MCU at lower frequency.

But, suppose that I want to make debug using serial port or suppose that I want to upload a correction in the code WITHOUT changing the crystal back to 16MHz... These options do not work. lat week, I tried to modify the line, exactly as suggested: atmega328.upload.speed=7200. However, the IDE sends an error when I try to compile/upload code... We need to define "regular" baud rates, such as 9600, 19200, ... but not something like 7200. The FDDI driver accepts this, but the problem is the embedded compiler at the Arduino IDE. Someone said that we can easily modify this behavior but I was not successful and I gave up.

What I need is a "playground" topic showing how to do this modification.

Thanks for the comments.

but the problem is the embedded compiler at the Arduino IDE.

It's more likely the AVRDUDE program that the Arduino IDE calls to actually perform the upload. Sorry it didn't work.

However maybe if you can burn the bootloader for the one of the other 328 boards that use a different upload baud rate then that could be the basis to change from:

##############################################################

bt328.name=Arduino BT w/ ATmega328

bt328.upload.protocol=stk500
bt328.upload.maximum_size=28672
bt328.upload.speed=19200
bt328.upload.disable_flushing=true

bt328.bootloader.low_fuses=0xff
bt328.bootloader.high_fuses=0xd8
bt328.bootloader.extended_fuses=0x05
bt328.bootloader.path=bt
bt328.bootloader.file=ATmegaBOOT_168_atmega328_bt.hex
bt328.bootloader.unlock_bits=0x3F
bt328.bootloader.lock_bits=0x0F

bt328.build.mcu=atmega328p
bt328.build.f_cpu=16000000L
bt328.build.core=arduino

##############################################################

This if modified to run at 2mhz clock speed would result in a 2400 baud, 19200/8, upload rate which may be a standard speed the AVRDUDE would except ?

Lefty

Yes, good shot!! Good and simple idea: use 2400bps for the data transfer.

It will take a little bit longer for the upload, but I can still use the board with the 2MHz crystal for developing and tests...

For the debug, I only have to set the baud rate of the serial terminal to 2400bps (assuming that I am using Serial.begin(19200) at the code).

I will try these ideas tomorrow.

Thanks

For the debug, I only have to set the baud rate of the serial terminal to 2400bps (assuming that I am using Serial.begin(19200) at the code).

I don't think that is correct. Once you have modified the boards.txt file for 2Mhz operation then the compiler and libraries will know how to correctly calculate baudrate when using serial commands after you upload the sketch, so Serial.begin(19200) should work fine and your serial monitor can be set to 19200 baud and everything should work. It's just because the bootloader is a fixed hex file that doesn't get recompiled and therefore expects a specific baud rate when operating at a specific clock speed, therefore the need to fake out the upload command baud rate used in the boards.txt file. At least that is my logic if it makes sense to you.

Lefty

The v22 IDE has lots of boards that run at 8Mhz (and 3.3v)

You could run your CPU at 8Mhz during prototyping.. and be stable at 3.3v :slight_smile:
I don't know if it will get you much closer to 1.85v.

The wiring.c code has support for code at 16Mhz and 8Mhz - for example delayMicroseconds.

/* Delay for the given number of microseconds.  Assumes a 8 or 16 MHz clock. */
void delayMicroseconds(unsigned int us)
{
	// calling avrlib's delay_us() function with low values (e.g. 1 or
	// 2 microseconds) gives delays longer than desired.
	//delay_us(us);

#if F_CPU >= 16000000L
	// for the 16 MHz clock on most Arduino boards

	// for a one-microsecond delay, simply return.  the overhead
	// of the function call yields a delay of approximately 1 1/8 us.
	if (--us == 0)
		return;

	// the following loop takes a quarter of a microsecond (4 cycles)
	// per iteration, so execute it four times for each microsecond of
	// delay requested.
	us <<= 2;

	// account for the time taken in the preceeding commands.
	us -= 2;
#else
	// for the 8 MHz internal clock on the ATmega168

	// for a one- or two-microsecond delay, simply return.  the overhead of
	// the function calls takes more than two microseconds.  can't just
	// subtract two, since us is unsigned; we'd overflow.
	if (--us == 0)
		return;
	if (--us == 0)
		return;

	// the following loop takes half of a microsecond (4 cycles)
	// per iteration, so execute it twice for each microsecond of
	// delay requested.
	us <<= 1;
    
	// partially compensate for the time taken by the preceeding commands.
	// we can't subtract any more than this or we'd overflow w/ small delays.
	us--;
#endif

	// busy wait
	__asm__ __volatile__ (
		"1: sbiw %0,1" "\n\t" // 2 cycles
		"brne 1b" : "=w" (us) : "0" (us) // 2 cycles
	);
}