Pages: 1 ... 4 5 [6]   Go Down
Author Topic: Millis Accuracy Again  (Read 4305 times)
0 Members and 1 Guest are viewing this topic.
Global Moderator
Dallas
Offline Offline
Shannon Member
*****
Karma: 178
Posts: 12288
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Note that the version of the code posted above uses exttimer_millis()

...which...

1. Is flawed.
2. Will be no more or less accurate than millis.

Stop using it.
Logged

0
Offline Offline
Full Member
***
Karma: 2
Posts: 156
It was all digital
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi orly_andico

I think it's a software related problem. You are doing some strange things with millis()...

I guess this is your loop:
Code:
void loop() {  
  long tstart = exttimer_millis();

  handler_called++;

  if ((handler_called % THINKPERIOD) != 0) {
    do_autoguider();
  }
  else {
    handler();
  }

  long tcnv = (exttimer_millis() - tstart) + 1;

  if (tcnv < PERIODMILLIS) {
    delay(PERIODMILLIS - tcnv);
  }
}

a delay in main loop and an incremente to keep track of when to do things. That is not how I would have done it.

Code:
void exttimer_init() {
  Timer1.initialize(10000);    // 10 milliseconds
  Timer1.attachInterrupt(exttimer_callback);
}

void exttimer_callback() {
  _mymillis += 10;
}

The exttimer has a resolution of 10 ms. That is alot considering you wanna do tcnv average here:
Code:
void read_encoder(long &A, long &B, long &tcnv) {
  int reading;
  int i;

  long t0, t1;

  t0 = exttimer_millis();

  // this should finish in 5ms or less @ 32ksps
  for (i = 0; i < OVERSAMPLING; i++) {
    reading = read_adc(1);
    A += reading;

    reading = read_adc(2);
    B += reading;
  }

  A = A / OVERSAMPLING;
  B = B / OVERSAMPLING;

  t1 = exttimer_millis();
  
  // tcnv should be in milliseconds
  tcnv = (t0 + t1) / 2;
}

Byt the way. You average calculation is a disaster just waiting to happpen. What happens if you forget to set the variables that &A and &B is refering to to not 0 prior to calling the routine..... strange average .....
Edit: This is happening in the calibrate() where encoderA and encoderB is set to 0 outside the while loop.

Btw, can you pleast explane how the calibrate() routine works. It seemes like a strange way to get the mean values from the encoders and keep the outliers out. It dos not follow dixon's test for outliers.

edit,edit: I have been thinking a but more about that calibration. I think you need to rethink it. You are oversampling from the encoders 64 times and then returning the average as reading value. If this value is an outlire then numerious of the 64 readings must be outliers. You should test for outliers among the crude values returned from the encoders.

-Fletcher
« Last Edit: April 19, 2013, 07:22:11 am by Fletcher Chr » Logged

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

Hi all,

An update.

1) I changed the encoder reading to an interquartile mean (following the  STMicro Application Note 3964 "How to design a simple temperature measurement application using the STM32L-DISCOVERY")

2) I got rid of the delay() in the main loop and replaced it with a do-nothing loop

Code:
  tcnv = 0;
  while (tcnv < PERIODMILLIS) {
    tcnv = (micros() - tstart) / 1000UL;
  }

The 2nd part seems to have made all the timing drift problems go away!

This is really strange, because in Unix-land where I come from, sleep() is good - and spinning the CPU is bad.  But it seems in Arduino-land the opposite is true.
Logged

UK
Offline Offline
Shannon Member
****
Karma: 184
Posts: 11197
-
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

2) I got rid of the delay() in the main loop and replaced it with a do-nothing loop
The 2nd part seems to have made all the timing drift problems go away!

I'm glad that you have solved the problem.

I agree it is strange that the change cured it. However, since you never did post a test case that demonstrated the problem, I've never been able to reproduce it and have no way to investigate it myself, so I'm afraid you're on your own.
Logged

I only provide help via the forum - please do not contact me for private consultancy.

Pittsburgh, PA, USA
Offline Offline
Faraday Member
**
Karma: 58
Posts: 4036
I learn a bit every time I visit the forum.
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

In Unix-land you have a multi-tasking OS. With Arduino you write your own tasking.

Nice to see you finally dumped the code-blocking delay that was screwing your results up.
How many times was that suggested in how many ways?

Logged

Examples can be found in your IDE.

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

GoForSmoke,

True, getting rid of delay() was suggested several times.   It was just very counter-intuitive.

Back to Unix-land, using sleep() allow other processes to run (or lets the CPU go into low-power mode, if there are no runnable processes), but using a do-nothing loop spins the CPU which keeps power consumption up.

While the Arduino is single-tasking, I would have thought that allowing it to power-down when doing nothing was good.  Or maybe delay() isn't smart enough for that.. or the AVR CPU doesn't have that capability.  The STM32 CPU's do have the capability to clock down to 4MHz and even go into deep sleep, then wake up on interrupt.

(incidentally I will probably port this code to an STM32 going forward, the boards are laughably cheap and the processors significantly more powerful)
Logged

Offline Offline
Edison Member
*
Karma: 17
Posts: 1041
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

GoForSmoke,

True, getting rid of delay() was suggested several times.   It was just very counter-intuitive.

Back to Unix-land, using sleep() allow other processes to run (or lets the CPU go into low-power mode, if there are no runnable processes), but using a do-nothing loop spins the CPU which keeps power consumption up.

While the Arduino is single-tasking, I would have thought that allowing it to power-down when doing nothing was good.  Or maybe delay() isn't smart enough for that.. or the AVR CPU doesn't have that capability.  The STM32 CPU's do have the capability to clock down to 4MHz and even go into deep sleep, then wake up on interrupt.

(incidentally I will probably port this code to an STM32 going forward, the boards are laughably cheap and the processors significantly more powerful)
Strange how things change when you have 2 million times less RAM...
Logged

Pittsburgh, PA, USA
Offline Offline
Faraday Member
**
Karma: 58
Posts: 4036
I learn a bit every time I visit the forum.
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

GoForSmoke,

True, getting rid of delay() was suggested several times.   It was just very counter-intuitive.

Back to Unix-land, using sleep() allow other processes to run (or lets the CPU go into low-power mode, if there are no runnable processes), but using a do-nothing loop spins the CPU which keeps power consumption up.

While the Arduino is single-tasking, I would have thought that allowing it to power-down when doing nothing was good.  Or maybe delay() isn't smart enough for that.. or the AVR CPU doesn't have that capability.  The STM32 CPU's do have the capability to clock down to 4MHz and even go into deep sleep, then wake up on interrupt.

(incidentally I will probably port this code to an STM32 going forward, the boards are laughably cheap and the processors significantly more powerful)

That is true but whether powered down or using blocking code like delay, the Arduino cannot also be watching the I/O pins or sensors. A multitasking system can if the watching is done with a different task.

I look at the ability to watch and time as the 'attention' of the computer and write my state machines with that as a budget. I know that the attention budget of an UNO or MEGA is far more than enough to do the job you set -if- nothing else is grabbing too many cycles in between, like may be or have been happening with the print load you also have.

I am just up from 'can't sleep' and not remembering details but will you be running the project while connected to a PC? If so then all the math and verbose output can be done on the PC using the free PC language that Arduino is based on, Processing. If you have both worlds then you might as well have the best of both worlds. I even wonder if there's a way to get an accurate timing signal from the PC, possibly through the parallel port using Linux.
 
Logged

Examples can be found in your IDE.

UK
Offline Offline
Shannon Member
****
Karma: 184
Posts: 11197
-
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Nice to see you finally dumped the code-blocking delay that was screwing your results up.

... by replacing it with a home-made equivalent which is also blocking. The only reason I can see for this to 'correct' the problem is that the code relies on the actual elapsed time being exactly what was specified - which would be exactly the sort of bug we'd be looking for to explain these symptoms. IF we'd got a simple test case that demonstrated the problem, we might have been able to point the bug out. Since we don't, the only conclusion I can come to is that it's a bug somewhere in the sketch.
Logged

I only provide help via the forum - please do not contact me for private consultancy.

U.K
Offline Offline
Jr. Member
**
Karma: 1
Posts: 70
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

of course, even up to version 1.5.2 beta of the code.  millis() can sometime miss a timer0count rollover.

the micros() call handles the missed counter ISR trigger, but millis() does not.

a call exists on the arduino bug tracker,  but as its been so long, its refering to older IDE versions, where both micros() & millis() could lose counts.

http://code.google.com/p/arduino/issues/detail?id=187

although this call is old,  and newer IDE versions dont need the fix doing for micros(),  i've modified my code to allow me to have it correct millis() depending on what board I compile my own code for.

Darryl
Logged

--
 Darryl

Pages: 1 ... 4 5 [6]   Go Up
Jump to: