Go Down

Topic: Problem with modulo (%) and reset (Read 14 times) previous topic - next topic

robtillaart

#30
Jan 02, 2011, 12:31 pm Last Edit: Jan 02, 2011, 12:41 pm by robtillaart Reason: 1
@vesal: Found another strange thing (original code): can you confirm this?

When I press the reset when the LED is [glow]on[/glow] the strange behavior appears.
When I press the reset when the LED is [glow]off[/glow] it acts normal...


tested 10+ times (not scientifically but still)
Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

robtillaart

#31
Jan 02, 2011, 12:39 pm Last Edit: Jan 02, 2011, 12:49 pm by robtillaart Reason: 1
Not a contest but even this smaller code hangs.
Code: [Select]
unsigned [glow]long [/glow]n1000 = 0;

void setup() {
}

void loop() {
 n1000++;
 n1000 %= 1000;  // This hangs Arduino while pressing reset
}


update

while this seems unhangable

Code: [Select]
unsigned [glow]int [/glow]n1000 = 0;

void setup() {
}

void loop() {
 n1000++;
 n1000 %= 1000;
}
Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

vesal

Quote
When I press the reset when the LED is on the strange behavior appears.
When I press the reset when the LED is off it acts normal.


I think I get the behavior in both cases.  You can changes the 500000L
to something longer to get more time in each case. F.ex to  2500000L.
Then you must also change the  n1000 %= 5000000L; to get 5 sec round trip.

But I do not see reason why it behaves differently in different state.

robtillaart

#33
Jan 02, 2011, 12:57 pm Last Edit: Jan 02, 2011, 01:30 pm by robtillaart Reason: 1
Testing the ldiv() assumption; I am not able to hang this minimal code , "so ldiv is clean" (update: not so, see below)
Code: [Select]

#include <stdlib.h>

void setup() {
}

void loop() {
 unsigned long a, b;
 a= 12345;
 b = 1000;
ldiv_t d = ldiv(a, b);
}


Quote
But I do not see reason why it behaves differently in different state.

Energy consumption? speed in which a (reset) capacitor loads/empties? (all assumptions)
Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

vesal

I can get this one to hang:
Code: [Select]
ldiv_t n1000;
unsigned long m = 0;

void setup() {
}

void loop() {
 n1000 = ldiv(m++,1000000L);  // This hangs Arduino while pressing reset
}


You code may not hang because if nothing is changing, the compiler may optimize something away.  The same was also problem for "my minimal code with modulo" when nothing was changing.

robtillaart

The unsigned keyword is not relevant, this one hangs too after a few tries.
Code: [Select]
long n1000 = 0;

void setup() {
}

void loop() {
 n1000++;
 n1000 %= 1000;  // This hangs Arduino while pressing reset
}
Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

robtillaart

Code: [Select]
void loop() {
 n1000 = ldiv(m++,1000000L);  // This hangs Arduino while pressing reset
}

Confirmed;
Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

westfw

Code: [Select]
void loop() {
 n1000 = ldiv(m++,1000000L);  // This hangs Arduino while pressing reset
}

By "hang" you mean that it goes into some sort of bootloader loop where you get the initial flashes, repeating approximately every second, but the sketch itself never seems to start?

I can get this to happen with an m168 containing optiboot, using 0022 from a Mac.  Not every time, though.

This is really strange.  It's not really hung, or it wouldn't be running the bootloader enough to flash the LEDs.  Or to recover on a new upload.  The ldiv function really doesn't do anything suspicious that I can see...

westfw

Code: [Select]
unsigned long n1000 = 0;

void setup() {
}

void loop() {
 n1000++;
 n1000 %= 1000;  // This hangs Arduino while pressing reset
}

This is a simpler sketch, based on the code actually produced.  A signed divide does sign correction and calls the unsigned divide, and the use of ldiv_t results in some substantial structure-passing code...

westfw

ah hah!  This had all the signs of a watchdog problem, except that those are supposed to be all fixed on Uno.  And looking at the code, it does look like they should indeed be fixed.

Except...

The C compiler uses register 1 (R1) as a "known zero" in most places.  Functions that use it for something else are supposed to save and restore it, so any particular C function, like main(), knows it can assume that R1 contains a zero.  R1 is initialized in the startup code that happens before main() happens (which is before setup() or loop() as well.)

The optiboot bootloader suppresses the normal startup code.  R1 does not get set to zero.

The first thing done in the bootloader is to reset the watchdog timer "MCUSR = 0;", which compiles to "out 0x34, R1" - it assumes that R1 contains a zero!

RESET does not set register contents to zero.

If a reset occurs while R1 contains certain values, (bit 1 set), the bootloader will not restart the sketch.

The divide library function uses R1 as a loop counter.

The following sketch shows the same behavior:
Code: [Select]
void setup() {
 asm("ldi r30, 2\n"
 "mov r1, r30\n");
 while (1);
}

void loop() {
}  

This is actually a bug in the bootloader.  I don't see any way to fix it in the main Arduino code...


Coding Badly


robtillaart

#42
Jan 03, 2011, 05:04 pm Last Edit: Jan 03, 2011, 05:47 pm by robtillaart Reason: 1
Thanks westfw for this analysis. My knowledge of the arduino is insuffcient to confirm this one but it explains all.

Update: Is there an asm statement that can patch this at the begin of setup()?  r1 = 0; ??
Or can it only be patched with a new bootloader?
Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

davekw7x

#43
Jan 07, 2011, 08:25 am Last Edit: Jan 07, 2011, 08:49 am by davekw7x Reason: 1
@westfw:
Quote
This is actually a bug in the bootloader.
I can't say how happy I am that you found it! I (probably) never would have figured out that r1 is zeroed out on power-up but not by a hardware reset.  (I feel that it must be documented somewhere, but I haven't seen any Atmel AVR chip references other than doc8271.)

Anyhow, here's what I did:

I downloaded the optiboot source from http://code.google.com/p/optiboot/.  At the very beginning of main() in optiboot.c there are these lines:
Code: [Select]

 // After the zero init loop, this is the first code to run.
 //
 // This code makes the following assumptions:
 //  No interrupts will execute
 //  SP points to RAMEND
 //  r1 contains zero
 //
 // If not, uncomment the following instructions:
 // cli();

#ifdef __AVR_ATmega8__
 SP=RAMEND;  // This is done by hardware reset
#endif

 // asm volatile ("clr __zero_reg__");


I uncommented the cli() line and the asm line.  Since cli() is defined in the avr interrupt.h header, I added the following right after the #include <avr/pgmspace.h> line:
Code: [Select]

#include <avr/interrupt.h>


Did "make atmega328" and burned the loader into UNO and other boards.

Now I observe that none of the "UNO breaker" programs in this thread seen ti be causing problems.  (Whew.)

Tested with UNO as well as with Duemilanove and other FTDI-interface '328P boards on Centos 5.5 Linux and Windows XP workstations.


Regards,

Dave

Footnote:
Get the source tree from http://code.google.com/p/optiboot/source/checkout, not the zip file. This is important!

Then...

With avr-gcc Version 4.3.4, the code size was too large until I modified the LDFLAGS line in the Makefile as follows:
Code: [Select]

# Original LDFLAGs resulted in code size greater than 512 bytes
# with avr-gcc version 4.3.4
# Added -nostdlib to make it fit
#   davekw7x
#override LDFLAGS       = -Wl,$(LDSECTION) -Wl,--relax -nostartfiles -Wl,--gc-sections
override LDFLAGS       = -Wl,$(LDSECTION) -Wl,--relax -nostartfiles -Wl,--gc-sections -nostdlib

Go Up