Pages: 1 [2] 3   Go Down
Author Topic: Problem with modulo (%) and reset  (Read 11066 times)
0 Members and 1 Guest are viewing this topic.
0
Offline Offline
Newbie
*
Karma: 0
Posts: 23
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
Why is stdio.h included?

It was just from the bigger program I tried to split to smallest one  where the error still exists and I forgot include there.  If I remove all includes, it still works same way wrong.

Quote
Software isn't my strong suit, but shouldn't it be:
 if ( (!dOn && n1000) >= 500 ) {

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

Still none of the above is the problem.  The problem is that something weird is with division.
Logged

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

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:

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 http://code.google.com/p/optiboot/

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.

Quote
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
« Last Edit: December 30, 2010, 06:39:01 pm by davekw7x » Logged

Left Coast, CA (USA)
Offline Offline
Brattain Member
*****
Karma: 331
Posts: 16525
Measurement changes behavior
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
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.  smiley-wink

Lefty
Logged

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

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...
« Last Edit: December 30, 2010, 06:53:11 pm by davekw7x » Logged

Left Coast, CA (USA)
Offline Offline
Brattain Member
*****
Karma: 331
Posts: 16525
Measurement changes behavior
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
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.  smiley-wink

Lefty
Logged

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

Thanks to try my code.

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

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

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

Quote
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.
« Last Edit: December 31, 2010, 09:25:15 am by davekw7x » Logged

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

Quote
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-grin
Logged

0
Offline Offline
Jr. Member
**
Karma: 0
Posts: 92
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
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,
Code:
( (!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)
« Last Edit: December 31, 2010, 09:32:42 pm by cnt » Logged

Left Coast, CA (USA)
Offline Offline
Brattain Member
*****
Karma: 331
Posts: 16525
Measurement changes behavior
View Profile
 Bigger Bigger  Smaller Smaller  Reset 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.  smiley-wink

Lefty
Logged

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

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
Code:
!dOn && ( n1000 >= 500000L ) == !dOn && n1000 >= 500000L
as it was in the original code.

Here is the code as whole with all the mods requested:
Code:
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  smiley-sad
« Last Edit: January 02, 2011, 05:15:23 am by vesal » Logged

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

n1000 = micros() % 1000000[glow]L[/glow]

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
Code:
 n1000 = micros();   n1000 %= 1000000UL;
still has the problem.

Diving into - http://www.nongnu.org/avr-libc/user-manual/stdlib_8h_source.html -  brings up :

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

« Last Edit: January 02, 2011, 06:09:57 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: 170
Posts: 12465
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 = 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?
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
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.

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

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

and comments the modulo line
Code:
// 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.
Logged

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

Minimal code that hangs Arduino:

Code:
unsigned long n1000 = 0;
unsigned long m = 0;

void setup() {
}

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

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