Forum Menu




 


Log in Problems?
New User? Sign Up!
AVR Freaks Forum Index

Post new topic   Reply to topic
View previous topic Printable version Log in to check your private messages View next topic
Author Message
ZECTBynmo
PostPosted: Apr 05, 2010 - 01:44 AM
Newbie


Joined: Apr 05, 2010
Posts: 3


Hi guys, I'm working on a team developing a data logger using an AtMega168. It accepts an RS-232 serial stream and writes it to an SD card as a .csv file. The firmware was originally created for an Arduino board using the Arduino C++ tool, but it is now on a custom circuit.

The problem is that the microprocessor keeps resetting. A new file is created on the card every time the processor powers up, and over a 24 hour period it will create 30-100 files. Strangely, it will collect only one or two lines of data during the first 45 minutes, during which time it will do the majority of its resetting, and then will log data perfectly for many hours. Also curiously, while the microprocessor is resetting, lines of data can be transmitted incompletely, but the one big file always has perfect data in it.

This behavior is very puzzling to me, and I'm not really sure where to go with debugging. One theory is that too much current is coming through the RS-232 connection, another is that it's a firmware issue. Here's an image of the schematic and a copy of my code. If anyone is willing to take the time and help out, It'd really be appreciated.

[img]http://5832613776636000249-a-1802744773732722657-s-sites.googlegroups.com/site/falasolarsignworksite/documents/newcircuit2.png?attachauth=ANoY7cp52rymfQnpkQy9D1zcK2LpwNgJa5vu13046X2OWFwjMXO6q2RrUehVEhhXkE71WiLHtEHP-Tkzb1YGunwJbpxsidLB4mmKku5vIkwiFBjlCJA7A4v_xusgP0pxTd-HjwGcL4bDkLKq0YRrwV-tWhuKcVQE9wYwMD2TsX4IjdoY5mN_07eX1JXmd8fLItGS7fBY3TtPBK4XWwHk-rd8bn37uJxLrSZQttedrpyCvqjQu6z3uO0%3D&attredirects=0[/img]
 
 View user's profile Send private message  
Reply with quote Back to top
theusch
PostPosted: Apr 05, 2010 - 02:36 AM
10k+ Postman


Joined: Feb 19, 2001
Posts: 25902
Location: Wisconsin USA

The first thing to do is to trap MCUSR and look at the reset causes. (Don't forget to clear after trapping/logging.)

The results of that exercise will help to establish a direction for further exploration.
 
 View user's profile Send private message  
Reply with quote Back to top
ka7ehk
PostPosted: Apr 05, 2010 - 02:36 AM
10k+ Postman


Joined: Nov 22, 2002
Posts: 12044
Location: Tangent, OR, USA

There are several common causes of reset, and several less common ones.

The big one is use of the watchdog, and not resetting it when needed. Another is use the brownout detector and experience power "sags" or "drops".

Other causes include improperly initialized stack, a stack that "runs away", over-writing other data, It can also be caused by exceeding array bounds. These causes do NOT create a normal "reset" event, I don't believe.

You can check the contents of the MCUSR, though it is tricky in C because of code initialization; there have been descriptions about how to do it.

Jim

_________________
Jim Wagner
Oregon Research Electronics, Consulting Div.
Tangent, OR, USA

"The only thing standing between us and victory is defeat" P.G.Wodhouse in Wooster & Jeeves series
 
 View user's profile Send private message  
Reply with quote Back to top
theusch
PostPosted: Apr 05, 2010 - 03:24 AM
10k+ Postman


Joined: Feb 19, 2001
Posts: 25902
Location: Wisconsin USA

Quote:

though it is tricky in C because of code initialization;

Huh? Perhaps with your infinite-value toolchain. You know the one: It's good; for nothing.

But mine happily "serves" up the value and will generate a code fragment if you ask the Wizard nicely.

[OK, Jim, I'll bite: Which toolchain wipes out I/O register contents at startup before app code gets a crack at them?]

Lee
 
 View user's profile Send private message  
Reply with quote Back to top
ka7ehk
PostPosted: Apr 05, 2010 - 03:54 AM
10k+ Postman


Joined: Nov 22, 2002
Posts: 12044
Location: Tangent, OR, USA

Well, I know that gcc pundits recommend a special "pre-initialization" code block to read MCUSR (and retain its value) though c-initialization. Yes, I know, its the one that's good (generally) for nothing (free).

Jim

_________________
Jim Wagner
Oregon Research Electronics, Consulting Div.
Tangent, OR, USA

"The only thing standing between us and victory is defeat" P.G.Wodhouse in Wooster & Jeeves series
 
 View user's profile Send private message  
Reply with quote Back to top
Mike B
PostPosted: Apr 05, 2010 - 05:25 AM
Raving lunatic


Joined: Jun 22, 2004
Posts: 3849
Location: South West Utah, USA

If MCUSR indicates a EXTRF reset, then read about the AVR reset pin here (the internal pull up isn't always good enough):

AVR042: AVR Hardware Design Considerations
http://www.atmel.com/dyn/resources/prod ... oc2521.pdf
 
 View user's profile Send private message  
Reply with quote Back to top
ZECTBynmo
PostPosted: Apr 05, 2010 - 06:08 AM
Newbie


Joined: Apr 05, 2010
Posts: 3


I'm not finding much documentation on how to access the MCUSR. Would one of you be kind enough to point me in the direction of a tutorial or something?

We have tried tying the reset pin to VCC (active low), so that shouldn't be the problem.
 
 View user's profile Send private message  
Reply with quote Back to top
JohanEkdahl
PostPosted: Apr 05, 2010 - 08:09 AM
10k+ Postman


Joined: Mar 27, 2002
Posts: 18545
Location: Lund, Sweden

Quote:

I'm not finding much documentation on how to access the MCUSR. Would one of you be kind enough to point me in the direction of a tutorial or something?

Access it just like any other I/O register?

Code:
uint8_t theRegisterContents = MCUSR;

(not tested)
 
 View user's profile Send private message Visit poster's website 
Reply with quote Back to top
ZECTBynmo
PostPosted: Apr 05, 2010 - 01:12 PM
Newbie


Joined: Apr 05, 2010
Posts: 3


Yea I guess my problem is that the firmware is written using the Arduino's higher level language. I'm not sure how to directly access these registers with arduino code. I guess I may have to dive into the libraries and figure it out, but is there anything else I can be doing in the mean time that might be productive?
 
 View user's profile Send private message  
Reply with quote Back to top
clawson
PostPosted: Apr 05, 2010 - 05:31 PM
10k+ Postman


Joined: Jul 18, 2005
Posts: 62281
Location: (using avr-gcc in) Finchingfield, Essex, England

Quote:

I'm not sure how to directly access these registers with arduino code.

EXACTLY as show by Johan. Arduino sketches ARE C programs (well, OK, C++ programs). It's just as valid in Arudino code to do direct register access such as:
Code:
DDRB |= (1<<PB3);
PORTB |= (1<<PB3);

to set pin 11 as it is to use Arduino library functions:
Code:
pinMode( 11, OUTPUT );
digitalWrite( 11, HIGH );

Both those pieces of code achieve the same (the former much quicker and in less space than the latter of course).

You may want to visit www.smileymicros.com and read Joe's Arduino articles 9 and 10 from Nuts & Volts magazine which explain how to make the switch to "real C". You may want to consider Joe's new book about programming Arduino which covers all this.
Quote:

Well, I know that gcc pundits recommend a special "pre-initialization" code block to read MCUSR (and retain its value) though c-initialization.

I've read that several times. While there are reasons to preempt the C preamble by coercing routines into the .init3 memory section to do things like enablingthe ext-mem interface before it is accessed by the C preamble I've never followed the logic of folks saying this is needed for MCUSR. They presumably have never looked at GCC's preamble - the only SFR registers it accesses are the SP? ones. As such there's nothing wrong with a C program starting:
Code:
int main(void) {
 uint8_t copyCR = MCUCR;

or an Arduino sketch starting:
Code:
uint8_t copyCR;

setup() {
 copyCR = MCUCR;
}

I just made the var global here in case it needs to be used within loop()

_________________
 
 View user's profile Send private message  
Reply with quote Back to top
curtvm
PostPosted: Apr 05, 2010 - 06:39 PM
Raving lunatic


Joined: Sep 21, 2005
Posts: 2297


The only need for 'special' considerations in saving reset status is when you are 'worried' that your initialization code may take longer than the default 15ms timeout of the watchdog. This is assuming you have an 'enhanced watchdog' (I assume all avr's used by Arduino variants have the enhanced watchdog- 168/328/etc).

Unless you run on a slow clock, I suspect 99% of the time this does not need to be anything to worry about.

You will notice that the datasheet recommends disabling the watchdog in your app on startup (whether you use it or not), so simply read the reset status register (if needed), clear the register, then disable the watchdog.
Code:

//...
#include <avr/wdt.h>
int main(){
//do this first
uint8_t temp_mcusr = MCUSR;
MCUSR = 0;
wdt_disable();
//reset cause now in temp_mcusr
//...
 
 View user's profile Send private message  
Reply with quote Back to top
theusch
PostPosted: Apr 05, 2010 - 06:52 PM
10k+ Postman


Joined: Feb 19, 2001
Posts: 25902
Location: Wisconsin USA

Quote:

when you are 'worried' that your initialization code may take longer than the default 15ms timeout of the watchdog.

Quote:

GCC's preamble - the only SFR registers it accesses are the SP? ones.

And IMO that's why the CodeVision's preambles do touch on some other "important" registers. One is to WDR and then disable the watchdog (yeah, yeah, it can be WDTON). An excerpt for a Mega640:

Code:
                 __RESET:
000feb 94f8         CLI
000fec 27ee         CLR  R30
000fed bbef         OUT  EECR,R30
                 
                 ;INTERRUPT VECTORS ARE PLACED
                 ;AT THE START OF FLASH
000fee e0f1         LDI  R31,1
000fef bff5         OUT  MCUCR,R31
000ff0 bfe5         OUT  MCUCR,R30
000ff1 93e0 0074    STS  XMCRA,R30
000ff3 93e0 0075    STS  XMCRB,R30
                 
                 ;DISABLE WATCHDOG
000ff5 e1f8         LDI  R31,0x18
000ff6 95a8         WDR
000ff7 b7a4         IN   R26,MCUSR
000ff8 7fa7         CBR  R26,8
000ff9 bfa4         OUT  MCUSR,R26
000ffa 93f0 0060    STS  WDTCSR,R31
000ffc 93e0 0060    STS  WDTCSR,R30

But of course I hear nyah-nyah 'cause the null program is n words shorter.

Thanks, but I'll take a "standard" preamble that does the things a competent microcontroller programmer would address.

But that's why we have entertaining Compiler Wars.

(and I don't know of any toolchains that touch BORF or those other bits with interesting names--Arduino unknown)
 
 View user's profile Send private message  
Reply with quote Back to top
curtvm
PostPosted: Apr 05, 2010 - 07:23 PM
Raving lunatic


Joined: Sep 21, 2005
Posts: 2297


Quote:
Thanks, but I'll take a "standard" preamble that does the things a competent microcontroller programmer would address.
...except in your case, (if I read correctly) you will never be able to 'see' if a watchdog reset occurred. I'm sure you have an alternate plan if that was needed.

I think the gcc/libc startup code could simply throw a 'wdr' in the data/bss init code, which would take care of any case- even if you had the watchdog fused on. But nothing prevents me from doing that if I wanted it that way. I wouldn't need it, though.

In any case, its good to know what your compiler does or does not do in the startup code.
 
 View user's profile Send private message  
Reply with quote Back to top
clawson
PostPosted: Apr 05, 2010 - 07:27 PM
10k+ Postman


Joined: Jul 18, 2005
Posts: 62281
Location: (using avr-gcc in) Finchingfield, Essex, England

Quote:

Thanks, but I'll take a "standard" preamble that does the things a competent microcontroller programmer would address.

As long as the C run time author makes provision for the programmer to replace or change the preamble then those who aren't happy with what's been provided can modify it as they like. Especially to allow code to be "injected" BEFORE the potentially long LPM (.data) and .bss wipe routines. But I don't see why everyone should pay the WDT price when not everyone's using it?

In GCC one merely needs:
Code:
void early(void) __attribute__((section(".init3"), naked));
void early(void) {
  // this happens before .data and .bss loops
  // could be asm("...") if you like
  // such as...
  wdt_reset();
  MCUSR &= ~(1<<WDRF);
  WDTCSR |= (1<<WDCE) | (1<<WDE);
  WDTCSR = 0;
}

_________________
 
 View user's profile Send private message  
Reply with quote Back to top
theusch
PostPosted: Apr 05, 2010 - 07:58 PM
10k+ Postman


Joined: Feb 19, 2001
Posts: 25902
Location: Wisconsin USA

Quote:
But I don't see why everyone should pay the WDT price when not everyone's using it?

Quote:
...a competent microcontroller programmer ...
Twisted Evil

Consider one of your million set-top boxes, and for the sake of discussion the WDT or other feature addressed in my snippet isn't used.

Now you start getting calls that after a lightning storm it ain't coming up right. And investigation reveals that the WDT inadvertently got enabled...
 
 View user's profile Send private message  
Reply with quote Back to top
skeeve
PostPosted: Apr 05, 2010 - 08:18 PM
Raving lunatic


Joined: Oct 29, 2006
Posts: 2648


Clawson's code doesn't allow usefully checking the MCUSR in main.
clawson wrote:
As long as the C run time author makes provision for the programmer to replace or change the preamble then those who aren't happy with what's been provided can modify it as they like. Especially to allow code to be "injected" BEFORE the potentially long LPM (.data) and .bss wipe routines. But I don't see why everyone should pay the WDT price when not everyone's using it?

In GCC one merely needs:
Code:
// The lines that mention MCUSR_mirror are Michael Hennebry's
// The rest, except this one are Clawson's
unsigned char MCUSR_mirror __attribute__((section(".noinit")));
void early(void) __attribute__((section(".init3"), naked));
void early(void) {
  // this happens before .data and .bss loops
  // could be asm("...") if you like
  // such as...
  wdt_reset();
  MCUSR_mirror=MCUSR;
  MCUSR &= ~(1<<WDRF);
  WDTCSR |= (1<<WDCE) | (1<<WDE);
  WDTCSR = 0;
}
Now main can check and clear MCUSR_mirror at its leisure.
It's nice to know that a reset was a reset and
not an unhandled interrupt or something.

_________________
Michael Hennebry
Iluvatar is the better part of Valar.
 
 View user's profile Send private message  
Reply with quote Back to top
kscharf
PostPosted: Apr 05, 2010 - 10:59 PM
Posting Freak


Joined: Aug 04, 2004
Posts: 1822
Location: Davie, FL

The possible causes of a 'restart' are (at least)
power on reset (power fail and restore), brownout (power dip and restore), watch dog, reset pin toggle, and jump/call to zero. BUT note that the MCUSR will have nothing to say about the last case as it isn't really a restart of the processor, just your code. The latter is probably a stack over/under flow or a pointer programing error.
 
 View user's profile Send private message  
Reply with quote Back to top
theusch
PostPosted: Apr 05, 2010 - 11:14 PM
10k+ Postman


Joined: Feb 19, 2001
Posts: 25902
Location: Wisconsin USA

Just a note on the last: It might not be explicit. If your code runs amok in the vast wasteland of unused flash it will end up back there.

You also need to be aware of what your toolchain might do with an uncaught interrupt vector.

I think when applicable JTRF or something like that for JTAG. But interesting, nothing corresponding for debugWire.
 
 View user's profile Send private message  
Reply with quote Back to top
Display posts from previous:     
Jump to:  
All times are GMT + 1 Hour
Post new topic   Reply to topic
View previous topic Printable version Log in to check your private messages View next topic
Powered by PNphpBB2 © 2003-2006 The PNphpBB Group
Credits