Problem with modulo (%) and reset

Pardon me for coming late to the party.

Vesal: Are you by any chance using Linux? There are some known problems with the UNO Boot loader and /dev/ttyACM0 on Linux systems. (If you are not using Linux, then: Never Mind.)

Here's what I did:
I took your original program without the superfluous and confusing (to us mere humans) stuff:

I added a delay of 1 millisecond in the loop. Here's the code:

const int dummyPort = 13; // I use pin 13 since it already has an LED

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

unsigned long n1000 = 0;
int dOn = 0;

void loop()
{
    n1000 = micros() % 1000000;
    if ( !dOn && n1000 >= 500000 ) {
        digitalWrite(dummyPort, 1);
        dOn = 1;
    }  

    if ( dOn && n1000 < 500000 ) {
        digitalWrite(dummyPort, 0);
        dOn = 0;
    }
    delay(1);
}

When I do this, I see the three-blink bootloader sequence and then the LED blinks on and off with a period of about a second, which, I perceive, was your intent. I can reset by opening a terminal and I can reset by pressing button. All is Good on my Centos 5.5 system with Arduino version 0022 , avr-gcc version 4.3.4 built from source and with the latest version of the Optiboot boot loader from Google Code Archive - Long-term storage for Google Code Project Hosting.

However, if I delete the delay() statement, it repeatedly does the bootloader three-blink thing on the LED on pin 13 whenever I hit the button or when I open a terminal, and never gets to the code in the sketch.

If you are using Windows, then never mind (but I already said that). Maybe some of the other helpers can come up with something.

The code itself works just swell on Duemilanove boards as well as the UNO with my Linux system, although I might have written it a little differently. With the Duemilanove boards it doesn't need the delay() statement.

The problem is that something weird is with division.

I can state unequivocally (and I am unanimous in that) that it has nothing do do with division.

Regards,

Dave

I can state unequivocally (and I am unanimous in that) that it has nothing do do with division.

But that's what he is saying, division is do do. :wink:

Lefty

Hmmm... I was just testing whether the forum's swear filter would let me say "do do" on the Internet. (That's my story and I'm sticking with it.)

I mean, it does its damndest to keep us from saying "damn," right? Really.

Regards,

Dave

Footnote:
If you hadn't been so fast on the trigger, I might have caught it and done a sneaky, silent edit to change it. I really wish I hadn't had to lay off my proofreader and editor. Oh, well...

Footnote:
If you hadn't been so fast on the trigger, I might have caught it and done a sneaky, silent edit to change it. I really wish I hadn't had to lay off my proofreader and editor. Oh, well...

Somehow I think you will get over it. :wink:

Lefty

Thanks to try my code.

...Linux...

No, I'm using Windows 7 64 bit. But this is not the bootloader problem, because the code works if it happens to reset correctly.

I added a delay of 1 millisecond in the loop. Here's the code:

I tried that also and forget to tell. I thought that it helped, but if you are passioned enough to press the reset button, then the problem comes anyway.

And why? Because the 1 ms loop takes the most of the time from the main loop, so the certainty to press the reset while in division goes minimal.

That it the thing it took me so long to find that division is the problem. Originally I had so much larger main loop and the problem game very seldom, I even ignored it at the beginning.

And my real concern is that if everybody that has division in his code has the same problem. Normally people do not press the the reset button all the time, but I think also interrupt in the same case hangs the Arduino. And that is the main concern.

Windows 7 64 bit

Generally speaking, I think it's really important for posters to tell us exactly what system they are using. Sometimes it makes a difference to people who would like to help.

One final question, and then I am done for this thread: Does the symptom persist if you unplug the UNO's USB connection and power it externally?

Anyhow...

I'm sorry to have wasted the board's bandwidth on something that couldn't help you. But: See Footnote.

Regards,

Dave

Footnote:
Putting in the delay() that keeps away from micros() is, at best, a Band-Aid that masks the real problem: A system bug that causes the Bad Thing to happen.

What I forgot to mention is that the UNO was absolutely unusable on my Linux system until I updated the firmware in the USB interface chip. That made it "almost good enough" for casual testing, but it still has problems that I simply can't reproduce with the FTDI interface on Duemilanove boards or other designs that use the FT232 chip for the USB interface.

For Linux users, I still think it's a matter of interaction between the Bootloader and the Operating System's treatment of /dev/ttyACM0. Whether it can be fixed with a new load of the bootloader or updating firmware in the ATmega8U2 USB chip on the UNO or a change in the Operating System's handling of USB with /dev/ttyACM0 is still awaiting discovery and fix.

I'm sorry to have wasted the board's bandwidth on something that couldn't help.

You did not waste the band. You was the only one who really tried the code and showed to me that the problem can be repeated elsewhere than in my environment. So lot of thanks and Happy New Year :smiley:

Does not matter, because && has stronger precedence than >=.
In case of clarity this would of course be better.

no. >= is evaluated first then &&
At least according to Kernighan and Ritchie

so,

( (!dOn && n1000) >= 500 ) != (!dOn && n1000 >= 500)

EDIT: also, (!dOn && n1000) >= 500 doesn't make a lot of sense because it is always false ( (!dOn && n1000) evaluates to either 0 or 1, which is always strictly smaller than 500)

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
}