Go Down

### Topic: Millis Accuracy Again (Read 25812 times)previous topic - next topic

#75
##### Apr 19, 2013, 05:04 am
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.

#### Fletcher_Chr

#76
##### Apr 19, 2013, 11:17 amLast Edit: Apr 19, 2013, 02:22 pm by Fletcher Chr Reason: 1
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: [Select]
`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: [Select]
`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: [Select]
`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

#### orly_andico

#77
##### Apr 30, 2013, 07:38 pm
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: [Select]
`  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.

#### PeterH

#78
##### Apr 30, 2013, 11:14 pm

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.

#### GoForSmoke

#79
##### May 01, 2013, 02:55 am

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?

2) http://gammon.com.au/serial <-- techniques howto
3) http://gammon.com.au/interrupts
Your sketch can sense ongoing process events in time.
Your sketch can make events to control it over time.

#### orly_andico

#80
##### May 01, 2013, 05:53 am
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)

#### WizenedEE

#81
##### May 01, 2013, 06:19 am

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

#### GoForSmoke

#82
##### May 01, 2013, 09:19 am

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.

2) http://gammon.com.au/serial <-- techniques howto
3) http://gammon.com.au/interrupts
Your sketch can sense ongoing process events in time.
Your sketch can make events to control it over time.

#### PeterH

#83
##### May 01, 2013, 05:13 pm

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.

#### darrylp

#84
##### May 02, 2013, 12:20 am
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.