Pages: 1 2 [3]   Go Down
Author Topic: Problem with modulo (%) and reset  (Read 12667 times)
0 Members and 1 Guest are viewing this topic.
Global Moderator
Netherlands
Offline Offline
Shannon Member
*****
Karma: 212
Posts: 13531
In theory there is no difference between theory and practice, however in practice there are many...
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

@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)
« Last Edit: January 02, 2011, 06:41:25 am by robtillaart » Logged

Rob Tillaart

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

Global Moderator
Netherlands
Offline Offline
Shannon Member
*****
Karma: 212
Posts: 13531
In theory there is no difference between theory and practice, however in practice there are many...
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Not a contest but even this smaller code hangs.
Code:
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:
unsigned [glow]int [/glow]n1000 = 0;

void setup() {
}

void loop() {
  n1000++;
  n1000 %= 1000;
}
« Last Edit: January 02, 2011, 06:49:24 am by robtillaart » Logged

Rob Tillaart

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

0
Offline Offline
Newbie
*
Karma: 0
Posts: 23
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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.
Logged

Global Moderator
Netherlands
Offline Offline
Shannon Member
*****
Karma: 212
Posts: 13531
In theory there is no difference between theory and practice, however in practice there are many...
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Testing the ldiv() assumption; I am not able to hang this minimal code , "so ldiv is clean" (update: not so, see below)
Code:
#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)
« Last Edit: January 02, 2011, 07:30:39 am by robtillaart » Logged

Rob Tillaart

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

0
Offline Offline
Newbie
*
Karma: 0
Posts: 23
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I can get this one to hang:
Code:
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.
Logged

Global Moderator
Netherlands
Offline Offline
Shannon Member
*****
Karma: 212
Posts: 13531
In theory there is no difference between theory and practice, however in practice there are many...
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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

void setup() {
}

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

Rob Tillaart

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

Global Moderator
Netherlands
Offline Offline
Shannon Member
*****
Karma: 212
Posts: 13531
In theory there is no difference between theory and practice, however in practice there are many...
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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

Rob Tillaart

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

SF Bay Area (USA)
Offline Offline
Tesla Member
***
Karma: 124
Posts: 6645
Strongly opinionated, but not official!
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Code:
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...
Logged

SF Bay Area (USA)
Offline Offline
Tesla Member
***
Karma: 124
Posts: 6645
Strongly opinionated, but not official!
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Code:
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...
Logged

SF Bay Area (USA)
Offline Offline
Tesla Member
***
Karma: 124
Posts: 6645
Strongly opinionated, but not official!
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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:
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...
Logged

SF Bay Area (USA)
Offline Offline
Tesla Member
***
Karma: 124
Posts: 6645
Strongly opinionated, but not official!
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

http://code.google.com/p/arduino/issues/detail?id=446&start=200
http://code.google.com/p/optiboot/issues/detail?id=26
Logged

Global Moderator
Dallas
Offline Offline
Shannon Member
*****
Karma: 198
Posts: 12750
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset


Nice analysis westfw!
Logged

Global Moderator
Netherlands
Offline Offline
Shannon Member
*****
Karma: 212
Posts: 13531
In theory there is no difference between theory and practice, however in practice there are many...
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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?
« Last Edit: January 03, 2011, 11:47:39 am by robtillaart » Logged

Rob Tillaart

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

Left Coast, USA
Offline Offline
Sr. Member
****
Karma: 5
Posts: 499
Sometimes I just can't help myself.
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

@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:
 // 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:
#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:
# 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
« Last Edit: January 07, 2011, 02:49:58 am by davekw7x » Logged

Pages: 1 2 [3]   Go Up
Jump to: