Pages: 1 [2]   Go Down
Author Topic: Broken millis(), broken PWM on pins 5 and 6  (Read 2271 times)
0 Members and 1 Guest are viewing this topic.
0
Offline Offline
Newbie
*
Karma: 0
Posts: 49
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I've noticed the PWM being broken on the project that I am currently working on.  Thanks for the tip! (pin, LOW) it is!

Chris
Logged

Forum Administrator
Cambridge, MA
Offline Offline
Faraday Member
*****
Karma: 12
Posts: 3538
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

I updated the timer 0 overflow and millis() with the basic strategy you suggested: updating the millis count inside interrupt handler, so it overflows nicely.  I didn't change the timer 0 prescale factor because I didn't want the PWM frequency on pins 5 and 6 to differ from those on the other PWM pins.  The new code is below.  There's still more to do on this, so suggestions are welcome.

Code:
volatile unsigned long timer0_clock_cycles = 0;
volatile unsigned long timer0_millis = 0;

SIGNAL(SIG_OVERFLOW0)
{
      // timer 0 prescale factor is 64 and the timer overflows at 256
      timer0_clock_cycles += 64UL * 256UL;
      while (timer0_clock_cycles > clockCyclesPerMicrosecond() * 1000UL) {
            timer0_clock_cycles -= clockCyclesPerMicrosecond() * 1000UL;
            timer0_millis++;
      }
}

unsigned long millis()
{
      unsigned long m;
      uint8_t oldSREG = SREG;
      
      cli();
      m = timer0_millis;
      SREG = oldSREG;
      
      return m;
}

Logged

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

Quote
I didn't change the timer 0 prescale factor because I didn't want the PWM frequency on pins 5 and 6 to differ from those on the other PWM pins.
I would suggest that a better solution would be to up the frequency on the other pins - otherwise you end up with a millis that can jump by 2ms in just over 1ms. But I don't see what problem you are trying to solve by keeping the frequencies of the PWM pins the same - off the top of my head I cannot think of a project that would need those frequencies to be the same.

Quote
volatile unsigned long timer0_clock_cycles = 0;
I think you can get away with an unsigned int here - doing so not only saves two bytes of memory, but it also makes the code smaller and run faster.
Logged

Forum Administrator
Cambridge, MA
Offline Offline
Faraday Member
*****
Karma: 12
Posts: 3538
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

I think that some motors (motor drivers?) have trouble with faster frequencies.  What's the problem with having millis() sometimes increment by two?
Logged

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

Quote
I think that some motors (motor drivers?) have trouble with faster frequencies.
A motor driver that runs at 1KHz? That sounds a bit fast for pretty much any physical process I can think of - except sound generation. But sound generation requires the frequency to be programmable - having just the duty cycle modifiable isn't any good for sound generation.

Quote
What's the problem with having millis() sometimes increment by two?
If you try and implement a delay of 2 milliseconds, you may end up pausing for only (just over) one millisecond. An attempt to delay by 3 milliseconds may be completed in just over 2 etc. I'm pretty sure there are peripherals which would have a problem with that.
Logged

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

I came accross this post while I was trying to figure out why millis() seemed to be busted.

I think that millis() should be part of a bigger strategy to implement a RTC as well as the basic foundation for a Real Time OS.

It does not matter if you get one or two ticks, as long as you maitain RTC integrity. Simplicity in processing and low overhead are desirable goals.

The system tic should be selected based on the best value and OS goals.  (i.e. will vary with developement over the years pending on hardware capability and application needs).  The system tic does not have to be one millisec.  The RTC function calls and the millis() function have to be accurate.  It is not possible to guarentee one millsec granularity with the overheads in a typical system.

I have not studied the internals very carefully, so I can not recommend a fix.

I am looking for a mini RTOS, that allows me to schedule tasks on a one second or greater time interval over several hours at least, preferably days.
Logged

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

Quote
I am looking for a mini RTOS, that allows me to schedule tasks on a one second or greater time interval over several hours at least, preferably days.

I believe my YAVRTOS http://www.chris.obyrne.com/yavrtos/index.html works on the Arduino.
Logged

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

Yes, YAVRTOS is worth looking at.  FreeRTOS is too big.

IMO it would be better to add RTC functionality, date, time and a wait functions to the processing/wiring framework.

People want to program at a high level and use one stop shopping.  Processing/wiring framework is close.  Look at some of the new features in the XMega.

Ardruino 0012 Alpha appears to fix the bug.
Logged

Austin, TX USA
Offline Offline
God Member
*****
Karma: 4
Posts: 997
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Studying this thread and pondering the famous rollover event, I decided to do an experiment.  Curious to see if I could catch the rollover in progress, I wrote the following simple program:

long int oldt, newt;

void setup()
{
  Serial.begin(9600);
  Serial.println("Hello, world!");
  oldt = millis();
}

void loop()
{
  newt = millis();
  
  // Filter out expected deltas of 0, 1, or 2 ms
  if (newt != oldt && newt != oldt + 1 && newt != oldt + 2)
  {
    Serial.print("Discontinuity event: Old time = ");
    Serial.print(oldt);
    Serial.print("ms, New time = ");
    Serial.print(newt);
    Serial.print(" ms, Delta = ");
    Serial.println(newt - oldt);
    
    if (newt < oldt)
      Serial.println("Rollover??!  New time is less than old time!");
  }

  oldt = millis();
}


The code simply loops repeatedly, comparing successive (and rapid) calls to millis().  Because I expected these successive calls to usually be the same, occasionally differing by 1 or perhaps 2 ms, the code flags any other delta to be a "rollover".  But when I run the program I get some results I don't understand too well.  Once in a while you get a largish jump of about 262ms, that I write off as some sort of bookkeeping interrupt(?)  But the interesting part is I find that occasionally the millis() clock seems to go backwards (well before the expected rollover).  I haven't studied the millis() implementation well enough to understand why this might be, but it's very reproducible, and I'm pretty sure there isn't any error in my simple test.  For example, here are the results of running the program above for about 10 minutes:

Hello, world!
Discontinuity event: Old time = 91487ms, New time = 91749 ms, Delta = 262
Discontinuity event: Old time = 182713ms, New time = 182975 ms, Delta = 262
Discontinuity event: Old time = 206044ms, New time = 205783 ms, Delta = -261
Rollover??!  New time is less than old time!
Discontinuity event: Old time = 315358ms, New time = 315097 ms, Delta = -261
Rollover??!  New time is less than old time!
Discontinuity event: Old time = 412089ms, New time = 412351 ms, Delta = 262
Discontinuity event: Old time = 550239ms, New time = 550501 ms, Delta = 262
Discontinuity event: Old time = 566492ms, New time = 566231 ms, Delta = -261
Rollover??!  New time is less than old time!
Discontinuity event: Old time = 599260ms, New time = 598999 ms, Delta = -261
Rollover??!  New time is less than old time!


I can understand and tolerate the jitter and accuracy issues mentioned below, but I'll bet that there are applications that depend on consecutive calls to millis() predictably increasing (until the rollover at least).  How can I better understand this behavior?

Mikal


Logged

Austin, TX USA
Offline Offline
God Member
*****
Karma: 4
Posts: 997
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Aha!  I have figured out what the problem is.  Millis() occasionally returns an incorrect value, and I understand why and how to fix it!  I will discuss this in a new thread, since it is sufficiently different from the original discussion.

Mikal
Logged

Pages: 1 [2]   Go Up
Jump to: