Problem with modulo (%) and reset

Ah Ha, I knew something was mangled in those if statements, but what do I know I'm just a hardware guy faking the programming stuff. :wink:

Lefty

Sorry. Of course >= is evaluated before &&. I just
get confused when retrolefty suggested parenthesis and
I just thought the original code was ok without (as it was)
and did not notice the false suggest.

So

!dOn && ( n1000 >= 500000L ) == !dOn && n1000 >= 500000L

as it was in the original code.

Here is the code as whole with all the mods requested:

const int dummyPort = 7;

void setup() {
  Serial.begin(115200); 
  Serial.println("Start Arduino");
  pinMode(dummyPort, OUTPUT);  
}

unsigned long n1000 = 0;
boolean dOn = false;

void loop() {

  //n1000 = micros();
  //while ( n1000 > 1000000L) n1000 -= 1000000L; // This works
  
  n1000 = micros() % 1000000L;  // This hangs Arduino while pressing reset
  if ( !dOn && ( n1000 >= 500000L ) ) {
    digitalWrite(dummyPort, 1);
    dOn = true;
  }  
  
  if ( dOn && ( n1000 < 500000L ) ) {
    digitalWrite(dummyPort, 0);
    dOn = false;
  } 

}

And the real problem still exist on that code: Reseting while in modulo hangs the Arduino :frowning:

n1000 = micros() % 1000000L

Think that one needs an L for long too. Otherwise still no clue


Update: I confirm that the code without the L does behave "strange" on my UNO too.

  • adding the L does not solve it
  • adding UL does not solve it
  n1000 = micros();   n1000 %= 1000000UL;

still has the problem.

Diving into - avr-libc: stdlib.h Source File - brings up :

00068 typedef struct {
00069         int quot;                   /**< The Quotient. */
00070         int rem;                    /**< The Remainder. */
00071 } div_t;
00072 
00073 /** Result type for function ldiv(). */
00074 typedef struct {
00075         long quot;                  /**< The Quotient. */
00076         long rem;                   /**< The Remainder. */
00077 } ldiv_t;
...
00153 /**
00154      The ldiv() function computes the value \c num/denom and returns
00155      the quotient and remainder in a structure named \c ldiv_t that
00156      contains two long integer members named \c quot and \c rem.
00157 */
00158 extern ldiv_t ldiv(long __num, long __denom) __asm__("__divmodsi4") __ATTR_CONST__;

Assuming that the compiler uses ldiv() for both % and / , it brings us to the same assembly call ; that "explains" why both % and / have same behavior. Still strange ...

void loop() {

  //n1000 = micros();
  //while ( n1000 > 1000000L) n1000 -= 1000000L; // This works
  
  // n1000 = micros() % 1000000UL;  // This hangs Arduino while pressing reset
  n1000 = micros();
  n1000 %= 1000000UL;  
  
  if ( !dOn && ( n1000 >= 500000L ) ) {
    digitalWrite(dummyPort, 1);
    dOn = true;
  }  
  
  if ( dOn && ( n1000 < 500000L ) ) {
    digitalWrite(dummyPort, 0);
    dOn = false;
  }
[glow]  delay(1);[/glow]
}

Adding shortest delay seems to make it more stable ... what does micro() do low level as that is also a constant factor in the code?

Adding shortest delay seems to make it more stable

Yes it helps, because then you minimize the change to hit reset during modulo (%). But still it is possible to hang if you are patient enough pressing the reset button. So this is not a way to replace this, one only hides the real problem.

... what does micros() do low level as that is also a constant factor in the code?

it gives the microseconds from the last restart. And notice that if one uncomments the two lines:

  n1000 = micros();
  while ( n1000 > 1000000L) n1000 -= 1000000L; // This works

and comments the modulo line

// n1000 = micros() % 1000000L;  // This hangs Arduino while pressing reset

then the code works just perfect and does the same thing. So the % is the only one (what I can see) that has effect. And as in earlier posts also division (/) has the same (not working) effect.

Minimal code that hangs Arduino:

unsigned long n1000 = 0;
unsigned long m = 0;

void setup() {
}

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

@vesal: Found another strange thing (original code): can you confirm this?

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


tested 10+ times (not scientifically but still)

Not a contest but even this smaller code hangs.

unsigned [glow]long [/glow]n1000 = 0;

void setup() {
}

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

update

while this seems unhangable

unsigned [glow]int [/glow]n1000 = 0;

void setup() {
}

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

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.

Testing the ldiv() assumption; I am not able to hang this minimal code , "so ldiv is clean" (update: not so, see below)

#include <stdlib.h>

void setup() {
}

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

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)

I can get this one to hang:

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.

The unsigned keyword is not relevant, this one hangs too after a few tries.

long n1000 = 0;

void setup() {
}

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

Confirmed;

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

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

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:

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

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

Nice analysis westfw!

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?

@westfw:

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 Google Code Archive - Long-term storage for Google Code Project Hosting.. At the very beginning of main() in optiboot.c there are these lines:

  // 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:

#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 Google Code Archive - Long-term storage for Google Code Project Hosting., 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:

# 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