Brown out detection & sleep modes

Go To Last Post
43 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hello All,

My problem: I use the ADC pins (atmega64) to measure a few sensors and then transmit this data wirelessly using a xbee transceiver. If there is a power outage, the data measured and accumulated is lost. I have a 9V battery back up and a simple diode so that if Vin (15V to a 7805) drops, the battery will continue powering the chip... however, if this happens and i continue using the ADC, USART, and a few interrupts, the battery will last only a few hours...

so for now i think what i should do is put a simple voltage divider to measure Vin and send this to an ADC channel. if Vin < 10V, then put the chip to sleep. When Vin > 10V (grid power is good again) then wake it up. (Unless, there's a better way?) I am not sure how it works though / how should i code it to wake it up when Vin > 10V (is there an interrupt i could use?)

int main(void)				
{
	MCUCSR = (1<<JTD);					// this disables the JTAG - Atmel require 2 writes in 4 cycles
	MCUCSR = (1<<JTD);					// it will also consume less power in sleep mode p49 atmega64 datasheet

	//USART_init();	
	initADC();
	sei();

  	while(1)
    {	
		
		// does a lot of stuff

		// power ok?
		Vcheck = 0;
		Vcheck = Vin();

		if (Vcheck <= 10)	// power out, put to sleep
		{
			cli(); // disable interrupts

			MCUCR = (1<<SE);
			MCUCR |= (0<<SM1) | (0<<SM0) | (0<<SM2);	// Table 9.2 p.50 
			// IDLE MODE BEST? ADC still enabled.. 

			while (Vcheck <= 10)
			{
				Vcheck = Vin();
				// include sleep command here?
			}
			MCUCR = (0<<SE); // clear SE bit after waking up - p.50
		}	
    }
return 0;
}

i have a second external clock(32,768kHz) to keep track of time but it would be ok if it's disabled on sleep mode

On p.51 of the atmega64 datasheet, one of the reset sources is 'Brown-out reset'. Is it possible to not reset the chip when Vcc drops below 2.7V? Maybe by disabling the fuse BODEN?

thank you!
- Eric

EDIT i don't think the while loop will run after putting the chip to sleep. not sure how it works..

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

On p.51 of the atmega64 datasheet, one of the reset sources is 'Brown-out reset'. Is it possible to not reset the chip when Vcc drops below 2.7V? Maybe by disabling the fuse BODEN?

Very unwise - the core may "run wild" when Vcc drops away. That's the whole point of BOD - to put the chip into reset before "odd behaviour" can do serious damage. So thing long and hard before you consider not using BOD.

BTW if you don't want the chip to do very much when in the low voltage state then consider using the watchdog and sleeping. When reset/reawoken test the voltage again and if not sufficient rinse and repeat.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

But another of the reset sources is the watchdog reset

Quote:
Watchdog Reset. The MCU is reset when the Watchdog Timer period expires and the
Watchdog is enabled.

so every time the watchdog timer period expires, i'll lose the data stored in the mcu, correct?

but i had not thought about using timers... ISR(TIMER0_OVF_vect) would not cause a mcu reset, so using this interrupt and sleep idle mode will work i think

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

i'll lose the data stored in the mcu, correct?


Bzzt. What data is "lost" upon a reset of an AVR?

True, I/O registers will get their initial values.

SRAM, GP registers, EEPROM are unchanged.

Quote:

but i had not thought about using timers... ISR(TIMER0_OVF_vect) would not cause a mcu reset, so using this interrupt and sleep idle mode will work i think


How about the watchdog timer in interrupt mode?

Anyway, why a Mega64? Why not a P or PA model that has more power-saving features?

How much data is being "lost"? Like the current state? Put it in EEPROM in a race during powerdown, and reload later.

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
so every time the watchdog timer period expires, i'll lose the data stored in the mcu, correct?
Yes, because the startup code overwrites SRAM vars. How much data might you lose, you don't put the whole program on your post ? If it's not too big, use the "volatile" modifier , put it in the "noinit" section of sram and it / they would survive a reset.

Quote:
How about the watchdog timer in interrupt mode?
m64 don't have that mode.

1) Studio 4.18 build 716 (SP3)
2) WinAvr 20100110
3) PN, all on Doze XP... For Now
A) Avr Dragon ver. 1
B) Avr MKII ISP, 2009 model
C) MKII JTAGICE ver. 1

Last Edited: Wed. Feb 2, 2011 - 06:17 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

hmmm who's right then? is SRAM overwritten in a reset or not?
but yes, they are simple variables where i store 'energy accumulated' over a specific period of time, etc.. char/int/long types.

Quote:
How about the watchdog timer in interrupt mode?

if the watchdog period expiring does not clear these variables, then i'd like to learn how to use the watchdog functionality and i'll continue doing research on this. I've been looking for sample codes but haven't found anything clear yet (yes,i've been reading the datasheet too)

though i'm already using ISR(TIMER0_OVF_vect) in the program and it overflows every second...

Quote:
you can put the array in the "noinit" section of sram and it would survive a reset.

hmmm where is the 'noinit' section??

and this is probably the same question

Quote:
Put it in EEPROM in a race during powerdown, and reload later.
no idea how to do this, i'll research about it tomorrow.

here's the code / or an idea of how i'd put it to sleep without losing data


#define F_CPU 7372800UL									
#define BAUDRATE 19200		
#define UBRR_VALUE ((F_CPU/(BAUDRATE*16UL)) - 1)

#include 
#include 
#include 
#include 		
#include 
#include 
#include 
#include 
#include 					
#include 

#define true 1 
#define false 0 
#define precision	100

unsigned int Vw;

void initADC()
{	
	ADMUX |= (0 << REFS1) | (1 << REFS0);
// Set ADC reference voltage to AVCC
	ADCSRA |= (1 << ADEN);//| (1 << ADIE);
// Enable ADC. ADIE conflicts with ADIF		
	ADCSRA |= (1 << ADPS2) | (1 << ADPS1) | (1 << ADPS0);	
// Set ADC prescaler to 128 bits
}


// Reading an analog value
uint16_t ReadADC(uint8_t channel)		
{
	ADMUX = (ADMUX & 0xF0) | channel;

	ADCSRA |= (1 << ADSC);
// Start Single Conversion
	while(!(ADCSRA & (1 << ADIF)));	
// Waiting for conversion to complete
	ADCSRA |= (1 << ADIF);	
// Clear AD Interrupt Flag
	uint16_t adc_L = ADCL;				
  	uint16_t adc_H = ADCH;
  	uint16_t adc_final = adc_L + (adc_H << 8);
	return adc_final;
}


int Vin()
{	
	long double V_n = 0;
	unsigned int ADCv_batt = 0;
	ADCv_batt = 0;
	ADCv_batt = ReadADC(4);		
	V_n = ADCv_batt * 4.88281;
// 5000[mV]/1024=4.88281 -- (R2+R1)/R2=4
	V_n = V_n * 4.0;
// where R1 = 3k, R2 = 1k
	return (unsigned int)V_n;	
// [mV]
}	

// USED IN NORMAL OPERATION
//void USART_TX(unsigned int byt)				
//ISR(USART0_RX_vect)
//ISR(TIMER1_CAPT_vect)
//ISR(TIMER0_OVF_vect)						


int main(void)				
{
	MCUCSR = (1<<JTD);
// this disables the JTAG - Atmel require 2 writes in 4 cycles
	MCUCSR = (1<<JTD);
// it will also consume less power in sleep mode p49 atmega64 datasheet
	
	initADC();
	sei();

   	while(1)
    {	
		// does a lot of stuff

		// power ok?
		Vcheck = 0;
		Vcheck = Vin();

		if (Vcheck <= 10)
// power out, put to sleep
		{
			MCUCR = (1<<SE);
			MCUCR |= (0<<SM1) | (0<<SM0) | (0<<SM2);
// Table 9.2 p.50 
// iddle mode - interrupts can still operate. 
		}	
    }
return 0;
}

ISR(TIMER0_OVF_vect)			//overflow interrupt vector
{
	// USED IN NORMAL OPERATION

	Vcheck = Vin(); 
	/* I KNOW. BAD TO call function from inside an interrupt. 
	but mcu would be sleeping, ANY SUGGESTIONS? */
	
	if (Vcheck > 10) // wake up
	{
		MCUCR = (0<<SE);
// clear SE bit after waking up - p.50
	}
}	
Last Edited: Wed. Feb 2, 2011 - 06:11 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

schamton wrote:
if the watchdog period expiring does not clear these variables...

1) It WILL as it's a rst ! Like i said, m64s ain't got no w.dog ISR() mode. Compare with a m644 w.dog.
2) Open your *.LSS and see for yourself what happens to your SRAM vars after reset .

3) "noinit" ... http://www.nongnu.org/avr-libc/u... scan the 2 links that have "memory" in them.

general syntax:

uint8_t jerome __attribute__ ((section (".noinit")));

where var jerome can be declared like any other.

4) Would you edit your posted code and CLEARLY indicate which you want saved ( we're doin' this for FREE ) ?

5) Dealing with eeprom has a tutorial in that forum.

6) Maybe using the analog comparator instead of the timer0 will be more efficient on battery ? Saves on code for sure.

1) Studio 4.18 build 716 (SP3)
2) WinAvr 20100110
3) PN, all on Doze XP... For Now
A) Avr Dragon ver. 1
B) Avr MKII ISP, 2009 model
C) MKII JTAGICE ver. 1

Last Edited: Wed. Feb 2, 2011 - 04:40 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

thank you for the links, i will go over them tomorrow. and sorry about the code, it is much larger than what i posted and that's why i had not posted it before. i edited the code - it's an idea of what i think i could do to save the data if power goes out. I am interested in saving the values of only 3-4 variables (in the code i only have unsigned int Vw)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

m64 don't have that mode.

That's nearly the whole point. Why was a Mega64 chosen? Apparently, what was on hand, or on a whim. Or 'cause it was "big", and bigger is better.

-- a different processor choice gives more possibilities
-- saving in a non-volatile memory avoids the sleeping/wakeup problem altogether in this app
-- no mention of the amount of this important information
-- untruths/half-truths about the AVR information lost over a reset
-- note that other resets can cause corruption (BOD) or indeterminate (
power on), so all this sleep/wakeup is only half the problem

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

untruths/half-truths about the AVR information lost over a reset

There is a lot of misinformation isn't there?

The mechanism that GCC uses to setup SRAM contents is well documented. The bottom line is that after a WDT reset all RAM contents remain intact. After the JMP from location 0x0000 the piece of code that sets up the C environment before entering main() (the "C runtime" aka crtm) there may be two loops (only present if they are used) called _do_copy_data() and _do_clear_bss().

The first copies the initial values of any pre-initialised globals from flash out to their locations in SRAM and the second wipes any globals without initial value to 0x00 in accordance with the guarantee given in the C standard.

GCC's CRT does not touch any other SRAM locations so the programmer is free to place data into those areas knowing they will be untouched. One way would be to reserve an area above the stack by moving it's initial value down but GCC preserves the .noinit section that's already been mentioned so may be easier to use.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
Why was a Mega64 chosen?

I am a recent graduate, i've been developing a pretty big project for the last year or so, started working with a through hole atmega16 and the software got big enough that had to upgrade to an atmega64. I have like 2 thousand lines of code already, and all i need is to take care of this problem by putting it to sleep to save battery power in the event of a power outage.

when putting the chip to sleep, let's say idle mode, is it possible to leave only one interrupt and disable the others? just to use ISR(TIMER0_OVF_vect) as shown in the code?

Quote:
6) Maybe using the analog comparator instead of the timer0 will be more efficient on battery ? Saves on code for sure.
I'm already using this timer as a real time clock.

Quote:
uint8_t jerome __attribute__ ((section (".noinit")));
where var jerome can be declared like any other.

and according to one of the links, 'jerome'
Quote:
will not be initialized to zero during startup as would normal .bss data.

The main variable i do not want to have reset is 'Etot', the total energy that has been generated by a PV panel since the day of installation. So i could put

int Etot __attribute__ ((section (".noinit")));

but i would need to initialize this to 0 on day 1 (and then never again initialize it, it would accumulate energy in kWh for the rest of its life... how could i do this?

EDIT. one more question, as shown in the code, if i put to sleep the chip in the while(1) loop, it would be like an extended indefinite 'delay' and it will wake up when a condition (Vcheck > 10) is met. When this happens, will the chip start from the point in the program right after it was sent to sleep? just want to make sure...

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
when putting the chip to sleep, let's say idle mode, is it possible to leave only one interrupt and disable the others?
Of course.
Quote:

I'm already using this timer as a real time clock.
I wrote about using the COMPARATOR NOT a timer. That way you don't have to run timer0, adc code and conditionals ( MCU stays awake too long for all that, and may have to just go back to sleep. Wasted energy if the sure-shot comp. can do it. ) to check mains. But then a voltage divider on the MCU P.S. into the comp. would constantly be drawing power...

I'm unemployed, so I'm ALREADY init. to 0 ! Just do it, 'cause once you init. to 0, the system just...stays on.Well, you will need to test mcusr, so if there's a rst., code will bypass that init. to 0 section. Too bad the eeprom has limited writes, it would be alot easier using it instead.

Quote:
When this happens, will the chip start from the point in the program right after it was sent to sleep?
Yep.

Make sure ALL unneeded peripherals are OFF.

1) Studio 4.18 build 716 (SP3)
2) WinAvr 20100110
3) PN, all on Doze XP... For Now
A) Avr Dragon ver. 1
B) Avr MKII ISP, 2009 model
C) MKII JTAGICE ver. 1

Last Edited: Wed. Feb 2, 2011 - 07:04 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I'm out. It still hasn't been proven to me the need for this power-saving mode. And if it is warranted Mega64 is one of the poorer choices for an AVR model.

A line of code isn't the same as every other line of code. But if you are indeed averaging more than four AVR words for each C line, that is pretty tough to do.

indiana is promoting the analog comparator over a timer as a wakeup source? I'd suggest you investigate "Power Consumption of Perhipheral Units" or similar in your datasheet.

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

theusch wrote:
indiana is promoting the analog comparator over a timer as a wakeup source
Not after re-thinking power drain from the divider net. ! AND comp.'s on ALL the time... that was strike 2 !

theusch, how would YOU do it if you only had about 6 - 8 bytes that had to be protected ?

schamton, you have code investment, but porting over to a better MCU's always doable.

1) Studio 4.18 build 716 (SP3)
2) WinAvr 20100110
3) PN, all on Doze XP... For Now
A) Avr Dragon ver. 1
B) Avr MKII ISP, 2009 model
C) MKII JTAGICE ver. 1

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

i'm trying to find info about how to enable / disable individual interrupts - not just sei() - cli() - and i'm kind of lost. any hint / key word / function i should be looking for in the datasheet?

Quote:
I'm unemployed, so I'm ALREADY init. to 0 ! Just do it, 'cause once you init. to 0, the system just...stays on.Well, you will need to test mcusr, so if there's a rst., code will bypass that init. to 0 section.

good, so

int Etot __attribute__ ((section (".noinit"))) = 0;

will work..

i'll consider using the comparator and compare that with using an interrupt... the difference will probably be very small...

Quote:
schamton, you have code investment, but porting over to a better MCU's always doable.
hmmm not when you have already designed and printed PCBs... or maybe it would be worth porting to a better one... :P

Quote:
Mega64 is one of the poorer choices for an AVR model

good to know that i guess...

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

theusch, how would YOU do it if you only had about 6 - 8 bytes that had to be protected ?


That's easy. [We still don't know from OP whether it is 6 or 60 or 600 bytes of this "important" stuff.]

You race the loss of power, and write it to EEPROM. Now, you don't need any battery system; you aren't concerned with the AVR mode's power-draw characteristics; and generally makes things simpler.

See this thread:
http://www.avrfreaks.net/index.p...

and others from a "race eeprom" search.

The short answer is that with the given information, when the raw supply dips maybe 25% and there is an impending power loss, you have on the order of 100ms. Plenty for "smart" writing of a dozen or more bytes. Even more comfortable if you use a pre-erased block--on new AVR models; may not be available on the clunker '64.

See also this thread about finding "the number":
http://www.avrfreaks.net/index.p...

BTW, kids, have you ever thought of just using logic levels for your loss-of-power trip (and restore). Now you can use any modern AVR with pin-change interrupts on any pin, and wake from the deepest sleep, and not need to keep the comparator fired up. Or other external interrupt(s). Now, the clunker '64 may not have these features.

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

GOOD stuff Lee, thanks ! I'll put it all in my toolbox. What does a pre-erased block of eeprom get me ( won't the internal write routine erase before every write regardless ? ) ?

OP wrote:
int Etot __attribute__ ((section (".noinit"))) = 0; will work..
No IT WON'T, I meant just do it like any other var., BUT in main() ( since we know by the link it can't be done on the declaration line ). You got it right in one of your prv. posts ! Read the link and that prv. post AGAIN ( big no-no to TRY to init in "noinit" land ). You would need code to check mcusr and handle the "noinit" vars depending on the BOD rst flag's value.
Quote:
i'm trying to find info about how to enable / disable individual interrupts...
The best thing to do is to check out the ISR() tuts. in that forum.

schamton, You've been asked > once how many critical bytes you have and we still don't know. But if you ONLY have, say < 10 bytes, doin' the race thing with the eeprom ( maybe a big cap. too for a longer discharge time ) is the easiest. The comparator won't be less power 'cause it's running all the time, as well as divider net. .

1) Studio 4.18 build 716 (SP3)
2) WinAvr 20100110
3) PN, all on Doze XP... For Now
A) Avr Dragon ver. 1
B) Avr MKII ISP, 2009 model
C) MKII JTAGICE ver. 1

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

In case it's not obvious (I don't think anyone's actually mentioned it so far) the point is that the mega1281 may be a better chip to use than mega64. It has lots more modern power saving "goodies" to offer.

As for your Etot - for something so important why even consider only holding it in volatile RAM - what happens if the power browns-out, it's lost forever. I'd be putting it in EEPROM. Obviously caching it in RAM while the program runs but writing it to EEPROM from time to time and perhaps when power rail drop is detected.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

What does a pre-erased block of eeprom get me

If you are racing at power loss to save n critical bytes of information, it usually isn't known how many of these are "new"--different than existing EEPROM values. So to be safe you need to assume that all n need to be rewritten.

Then you get your "number"--how many bytes you can write to EEPROM before the BOD kicks in.

If the "number is close to n (I usually want a 2x safety factor), then it sure would be helpful if it only took half as long, right?

The clunker Mega64 takes 8.4ms/byte. A 100ms window then allows only 12; about 6 using my 2x safety factor.

But check the times on a modern AVR model:

0 0 3.4 ms Erase and Write in one operation (Atomic Operation)
0 1 1.8 ms Erase Only
1 0 1.8 ms Write Only

Not only is the rewrite time less than half, but a pre-erased block can be written in half of that time.

Quote:

( won't the internal write routine erase before every write regardless ? )

That will depend on >>your<< toolchain and the facilities it provides. If for infinite-value reasons you don't have the tools, you will need to forge them yourself.

Quote:

maybe a big cap. too for a longer discharge time

typically not needed. The raw supply will drop (in this case 15V into a regulator) and you trip at 75%-50% raw level.

When you react at that time, you turn off the power suckers such as backlights, and displays/LEDs and etc. At that time any real design will have quite some time (I'd be surprised if less than 100ms) before the raw cap and the regulated cap are exhausted and Vcc starts dropping, even with modest-sized caps.

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

ok, things to improve: the 'power on' surface mount led should be controlled by the chip - it draws 20mA and that's very significant... i'm also powering an xbee module at 3.3V, so i'll still need the 9V battery. - i think i wouldn't have enough time to write to eeprom otherwise.

from the 'race eeprom' link and Indianajones mentioning it, i could:

Quote:
Another option would be to have Vreg run to a comparator external to the CPU (powered from Vprot) which can then condition a "Power OK" signal to an interrupt pin on the CPU.

or just use the ADC... and also the use of a big cap to give some extra time to write to eeprom. (i have a 1000uF cap at the input to the 7805 because some power adapters are really crappy and w significant ripple voltage)

the values i'd need to save are declared globally:

int Etot 
//(total energy of the system -- wind turbine + pv panels since installation)
int Es_month 
//(received via xbee wirelessly from another chip - could be omitted and taken care in that other chip)
volatile double Ew_month; 
//(wind turbine's energy generation accumulated over a month)
 

The most important, by far, is Etot - Es_month & Ew_month if possible.

so i could write (Indiana: in main()? i do not find in the links where it says that i can't declare them globally):

int Etot __attribute__ ((section (".noinit")));
int Es_month __attribute__ ((section (".noinit")));
volatile double Ew_month __attribute__ ((section (".noinit")))

and i would need further code to check mcusr "and handle the "noinit" vars depending on the BOD rst flag's value."

however, indianajones and Lee mentioned that these bytes could be written to EEPROM instead of writing them to .noinit, and that seems to be the best solution. NOTE I will still have the 9V battery and 1000uF cap due to the other loads in the pcb, so I’d write to eeprom just in case, and put the chip to sleep – so there would be no absolute loss of power to the chip, and therefore, no reset. I’m working on the code right now, I’ll post it in a few minutes.

Cliff, no, it was not obvious and thank you. In case i decide to upgrade the chip, i'll go for the mega1281.

thank you!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

i think i wouldn't have enough time to write to eeprom otherwise.

Read the linked thread about "the number". Why would you "think" that if you have no idea? (and I'm WAY confused about a master 15V supply and a 9V battery for a 3V3 supply)

Short answer: measure it. Not having 100ms for a few bytes plus a safety factor would really surprise me. And you already described a power-sucker that can be extinguished.

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

but the 3V3 for the xbee can't be extinguished with the current design, so true, i assumed that this power sucker would considerably reduce those 100ms... i'll read about 'the number'

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

but the 3V3 for the xbee can't be extinguished with the current design,

Well, there are a lot of fundamental design decisions that I'm questioning.

My summary: if you don't need to be processing when the main power is lost, you have a straightforward app. Dual power sources seems a bit ridiculous. We'd have one of:
-- Two regulators off the raw 15V giving the two target Vccs
-- 5V regulator, output serving as the input to the 3V3 regulator (you may find less heating this way)
-- Single regulator with dual outputs
-- 3V3 design--probably the preferred approach nowadays

There is nothing that says you can't cut the RF module power (it probably has a shutdown feature anyway).

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

the current design has a 7805 (mains 15V to 5V), and a 2nd reg 5V to 3.3V. Since i'm modifying the design, i'll consider putting a transistor in between the 3.3V output of the reg and the rf module

the back up is 9V batt -> diode > 15V rail to input of 7805

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

schamton wrote:
...so i could write (Indiana: in main()? i do not find in the links where it says that i can't declare them globally): ...
You MUST declare such vars. globally, AND init. MUST be inside main(), lessons the compiler WILL teach you not the links.
Quote:

Another option would be to have Vreg run to a comparator external to the CPU (powered from Vprot) which can then condition a "Power OK" signal to an interrupt pin on the CPU.
I was talking about the internal comp.

1) Studio 4.18 build 716 (SP3)
2) WinAvr 20100110
3) PN, all on Doze XP... For Now
A) Avr Dragon ver. 1
B) Avr MKII ISP, 2009 model
C) MKII JTAGICE ver. 1

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

after having to deal with other stuff at work i'm back at this problem. I have already learned and written the code to write/read to/from eeprom, and i'm now working on putting the m64 to sleep. With the current design i don't have enough time to write to race eeprom at power down, but i'll be modifying it - anyway, i want to learn how to put it to sleep... the interrupt is set to trigger every 1 sec

the output of the following code is

CCCCCCCCCCDCDCDCDCDCDCCCCCCCCCCDCDC... etc

so it is not going to sleep - i would expect the output to be

CCCCCCCCCC  -sleeping 5secs- DCCCCCCCCCC

D showing it has waken up. What am i doing wrong?

Thank you!

#define F_CPU 7372800UL									
#define BAUDRATE 19200		
#define UBRR_VALUE ((F_CPU/(BAUDRATE*16UL)) - 1)

#include 
#include 
#include 
#include  

#include 		
#include 
#include 
#include 
#include 
#include 					
#include 

#define true 1 
#define false 0 

volatile int counter = 0;

void USART_init()
{	
	UBRR0L = UBRR_VALUE;				
	UBRR0H = (UBRR_VALUE >> 8);			
	UCSR0B |= (1<<RXEN0) | (1<<TXEN0) | (1<<RXCIE0);	
}

void USART_TX(unsigned int byt)				
{	
	while(!(UCSR0A & (1 << UDRE0))){}	
	UDR0 = byt;
}

int main(void)				
{
	USART_init();	
	sei();

    volatile int temp0,temp1;	
	for(temp0=0; temp0<0x0040; temp0++)	
    {	for(temp1=0; temp1<0xFFFF; temp1++);	}
// Wait for external clock crystal to stabilize

    TIMSK &=~((1<<TOIE0)|(1<<OCIE0));	
    ASSR |= (1<<AS0);					
//set Timer/Counter0 to be asynchronous from the CPU clock 
//with a second external clock(32,768kHz)driving it.

	OCR0 = 0x00;						
    TCNT0 = 0x00;
    TCCR0 = 0x05;		
/* 0101 - CS22 CS21 CS20 --- 
Prescale the timer to be clock source / 128 to make it exactly 
1 second for every overflow to occur */
	
	while(ASSR&0x07);					
    TIMSK |= (1<<TOIE0);				

	while(1)
    {	
		USART_TX(67);		
		// send C to show activity... 
		
		if (counter >= 5)
		{
			set_sleep_mode(0);	// 0 - iddle mode

			cli();			
			sleep_enable();	//MCUCR = (1<<SE);		
			sei();
			sleep_cpu();

// sleeping for 5 secs
			//sleep_disable();
			USART_TX(68);	// WAKE UP HERE?!
		}
		_delay_ms(500);
    }
return 0;
}

ISR(TIMER0_OVF_vect)			
{
	counter++;
	if(counter > 10) 
	{
		counter = 0;
		sleep_disable(); 
//MCUCR = (0<<SE); // wake up - p.50
	}		
}	
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

With the current design i don't have enough time to write to race eeprom at power down,

What >>is<< the number--how many bytes can you get written? Are you detecting power loss high/early enough in the power--at the "raw"?

In other words I'm questioning your premise.

You are using a Mega64 in a low-power app? Trying to make a silk purse out of a sow's ear?

Quote:

Prescale the timer to be clock source / 128 to make it exactly
1 second for every overflow to occur */

Quote:

D showing it has waken up. What am i doing wrong?


What are your wakeup sources for that mode? Like, any interrupt? How often are you getting an interrupt? Like, every second? And then your code is sending it back to sleep?

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I wouldn't put sleep_disable is the ISR(). I read here that someone couldn't get his MCU to sleep w/o some delay before sleeping first. I confirmed that for my m644.

In while(1), try

  _delay_ms(10);  // delay needed, could be lower
  sleep_mode();

Check on sleep_mode() in sleep.h. Since you only set sleep mode once, I'd put it outside the loop.

1) Studio 4.18 build 716 (SP3)
2) WinAvr 20100110
3) PN, all on Doze XP... For Now
A) Avr Dragon ver. 1
B) Avr MKII ISP, 2009 model
C) MKII JTAGICE ver. 1

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

I read here that someone couldn't get his MCU to sleep w/o some delay before sleeping first. I confirmed that for my m644.

Oh, please, tell all so the unwashed masses can participate as well! Under what conditions is a delay needed before sleeping?

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Well, I just retested mine and delay wasn't needed. That is what someone said had to be done in their case, though...for whatever reason.

1) Studio 4.18 build 716 (SP3)
2) WinAvr 20100110
3) PN, all on Doze XP... For Now
A) Avr Dragon ver. 1
B) Avr MKII ISP, 2009 model
C) MKII JTAGICE ver. 1

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

I wouldn't put sleep_disable is the ISR().

Also, why wouldn't you put a sleep_disable() inside an ISR?

I've been doing things all wrong the past five years or so, in half a dozen production AVR sleeping apps, 'cause I have a sleep_disable() in the wakeup ISRs in case the wakeup condition occurs (e.g., a button press) while I'm preparing to go to sleep? Yes, there is indeed an absolute bullet-proof sequence that may or may not be directly used by the tooolchain-provided fragments. It just makes more sense to me to put the sleep_disable() in the wakeup ISRs so that you won't sleep with the fishes forever if the wakeup condition occurs during a race when preparing for sleep.

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I've already explained why i'm using a m64... i tried writing the 9 bytes i need to eeprom a few days ago and i couldn't without the battery. I will spend more time on this and find 'the number' of bytes i can write.

in regards to this sleep issue:

Quote:
What are your wakeup sources for that mode? Like, any interrupt? How often are you getting an interrupt? Like, every second? And then your code is sending it back to sleep?

i misunderstood when reading the datasheet and sleep.h and thought the mcu would wake up when the SE bit was cleared -- MCUCR = (0<<SE); --. I can now put it to sleep using the code below:

	set_sleep_mode(0);	// 0 - iddle mode
	
	while(1)
    {	
		sleep_mode();
		USART_TX(69);	
    }
return 0;
}

ISR(TIMER0_OVF_vect){}	

thank you, and i'll report back with the eeprom number as soon as i can
- Eric

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

theusch wrote:
Also, why wouldn't you put a sleep_disable() inside an ISR?
ISRs should be as short as possible.

1) Studio 4.18 build 716 (SP3)
2) WinAvr 20100110
3) PN, all on Doze XP... For Now
A) Avr Dragon ver. 1
B) Avr MKII ISP, 2009 model
C) MKII JTAGICE ver. 1

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
ISRs should be as short as possible.

Is a bit like saying "split infinitives are wrong", or "never use a goto". It's easy to trot this stuff out as though it were gospel, to the extent that we stop thinking about why.

It is probably good advice for beginners, but there are situations where ISRs do not need to be as short as possible. Don't ask me for examples, I've just been interrupted, and it might be some time before I get back to you.

Quebracho seems to be the hardest wood.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

theusch wrote:
Also, why wouldn't you put a sleep_disable() inside an ISR?
ISRs should be as short as possible.

What does that have to do with the reasoning/purpose I listed?

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
I've just been interrupted, and it might be some time before I get back to you.

ha! :)

why "never use a goto"?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I don't really care if you do or you don't use a goto. I was quoting it as an example of oft-repeated mantras.
But, if you're really interested, you might want to read this:
http://en.wikipedia.org/wiki/Structured_programming

In fact I might read it myself, later. First I have to go to the woods and walk the dog.

Quebracho seems to be the hardest wood.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
What does that have to do with the reasoning/purpose I listed?
Nothing, I was just answering your question.

1) Studio 4.18 build 716 (SP3)
2) WinAvr 20100110
3) PN, all on Doze XP... For Now
A) Avr Dragon ver. 1
B) Avr MKII ISP, 2009 model
C) MKII JTAGICE ver. 1

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

quick question! i followed Lee's recommendation and i'm racing eeprom at power down - No need to put the m64 to sleep to save power and keep those important values. i have a 3300uF capacitor and when Vin is detected to be low, 9 bytes are written to eeprom- When power is back again, i can confirm those values were saved successfully.

The problem is that when power is back, the m64 doesn't restart. it's like frozen and only if i RESET it the m64 initializes and then i can confirm those values were saved.

How should i fix this? maybe a RESET command in the software (in main, before the while(1) loop?) (??) ..

thank you!
- Eric

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

any thoughts? thank you!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

any thoughts? thank you!

My guess(es):
1. You don't have the BOD set. and
2. You aren't committing yourself to losing power.
3. And the above matters 'cause you didn't allow enough time for the app to die-dead. (Try it--turn it off an leave it off for long enough for Vcc to be 0V. Ensure no external devices are providing parasitic power. Turn it on. It will start up.)

RE 1. -- no BOD is dangerous in any AVR app, but particularly those that use EEPROM.

Here is how I do it. YMMV.

A. Early power loss detection, as has been discussed above.
B. Once you "trip" at say 70% of typical raw supply voltage, you "commit" to powerdown.
C. You save your critical parameters as has been discussed.
D. Remember you care committed. One of two things now happens:
D1. The power drops completely and you get a brown-out (or power-down) reset.
D2. Power is restored to an acceptable state. There was a glitch or short turn off. Remember we are committed to dying. When power is restored, force a reset by spinning in place until the watchdog causes a reset.

Summary: Once you "trip", the next useful thing is an AVR reset.

Here is some code fragments from an app. Note the "old code" block--in this app noise/power spikes were a problem so more averaging was done, but one wants to trip ASAP to keep "the number" high. One size does not fit all apps.

// ADC interrupt service routine
interrupt [ADC_INT] void adc_isr(void)
{

// Read the AD conversion result
	adc_raw = ADCW;

// ======== OLD CODE ==============
#if 0
	1/2 averaging kicks out on a noise spike.
// Do whatever needs to be done for averaging.  Let's try a 2 sample average
	adc_total += adc_raw;
	adc_total /= 2;
	ad_value = adc_total;
#endif

// Rev. "k"  Try a much less sensitive average -- 1/16
	adc_total -= adc_total / 16;		// keep 15/16
	adc_total += adc_raw;				// and add in 1/16 from the new sample
	ad_value = adc_total / 16;			// and use composite rolling average

// Flag a power-fail event

// Nominal 24VDC - diode drop = ~23.2V
//	Nominal 2.56VRef ==> ~840 A/D counts
//	Nominal trip @16VDC ==> ~600 A/D counts
//	Min of raw 23VDC & VRef of 2.7 ==> ~750 A/D counts
//	Max of raw 24VDC & VRef of 2.3 ==> ~890 A/D counts
//#define POWERFAIL_COUNTS	600
	flg_powerfail = (ad_value < POWERFAIL_COUNTS) ? 1 : 0;
...
// **************************************************************************
// *	P O W E R   F A I L
// **************************************************************************
//
//
//	Power Fail Detection and Response
//	=================================
//
//	The A/D ISR sets flg_powerfail.
//
//	-- Turn off the backlight to save power
//	-- Signal to the slave modules that there is an event
//	-- Save the cycle counter
//
//
	if (flg_powerfail && !latch_powerfail)
		{
		OUT_ALERT = ALERT_ON;
		LCD_BACKLIGHT = BACKLIGHT_OFF;

		ticks_power_good = 0;

		ee_cycle_counter = cycle_counter;	// save the cycle counter
		ee_latch_breakaway = latch_breakaway;	// save the breakaway latch
		ee_position = position;

		latch_powerfail = 1;				// used in the MODE_HOLD

		motion = MOTION_NONE;	// note that jogging still needs to be done
		cancel_timers();
		mode_actuator = ACT_NONE;
		mode_close_actuator = ACT_NONE;
		mode = MODE_HOLD;
		mode_return = MODE_HOLD;
		mode_source = MODE_HOLD;
		}

...the above fragment recognizes the condition and goes to a "minimal"
...mode with a message on the LCD and power still being monitored
...
// Loss of Power
			if (latch_powerfail)
				{
				// A power fail event has been recognized
				if (flg_powerfail)
					{
					// ... and the condition still exists
					hold_reason = HOLD_POWER;
					ticks_power_good = 0;
					break;
					}
				else
					{
					// Good power is restored.  Force a reset.
					while (1)
						{
						scratch++; // do nothing
						}
					}
				}
..

Now, depending on the app and how much fuss you want to go through, you can attempt a "soft" restart when good power is restored.

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thank you Lee, i have not been using the ADC interrupt as shown in the code below, nor the watchdog - BOD is set, and i do wait enough to set the power back on. However, unless i press the RESET button, the avr doesn't start up.

if (latch_powerfail) 
            { 
            // A power fail event has been recognized 
            if (flg_powerfail) 
               { 
               // ... and the condition still exists 
               hold_reason = HOLD_POWER; 
               ticks_power_good = 0; 
               break; 
               } 

the value of latch_powerfail would necessarily be saved in eeprom, correct? and isn't this piece of code designed to be running while power is out?

what i've been doing is:

/****** EEPROM ******/
// read state of powerOut flag - should be 0 if not initialized
	powerOut = eeprom_read_byte(&eepowerOut);
	Ew = eeprom_read_word(&eeEtotw);

	if (powerOut != false || powerOut != true)	// 1st time the chip runs
	{
		powerOut = false;
	}
	
// status LED & XBEE sleep pin
// PE6 high, PE7 low. Power to LED & xbee pin 9 --> low
	DDRE = 0b01000000;
	PORTE = 0x40;

	while(1)
    {	
// should check it every cycle to know as soon as power is out
		Vcheck = 0;
		Vcheck = Vin(); // [V] time between readings? 

		if (Vcheck <= 9500)		// --> [mV]!!!! power out
		{
			powerOut = true;	// before sending to sleep (ISR condition)
			
								// PE6 low LED. PE7 high sends xbee to sleep.
			PORTE = 0x00;		// 0b10000000
			
			if (written == false)
			{
				// WRITE
				cli();
				eeprom_write_byte(&eepowerOut, powerOut);
				eeprom_write_word(&eeEtotw, (unsigned int)Ew);			// Ew is declared double
				eeprom_write_block((const void*)&Ew_month, (void*)&eeEw_month, sizeof(double));
				sei(); // enough time to write ething?

				written = true;	
			}
		}
		else if (Vcheck > 9500 && powerOut == true)	// there was outage - back with power
		{
			// DO A RESET HERE!! HOW?

			PORTE = 0x40;		// 0b01000000 - turning power LED & xbee back on		

			powerOut = false;	
			written = false;	// already written to eeprom

			// READ to restablish values prior to outage
			Ew = 0;		
			Ew_month = 0;	

			cli();
			Ew = eeprom_read_word(&eeEtotw);
			eeprom_read_block((void*)&Ew_month,(const void*)&eeEw_month, sizeof(double));
			sei();
		}
		else		// power is ok
		{
// NORMAL CODE HERE
}
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

any other possibilities of why the avr wouldn't startup after a power down, unless it's reseted?!
OCDEN, JTAGEN & BODEN fuses enabled - BODlevel 2.7V

what if the m64 loses power while writing to eeprom? would that be a problem?!