Closed daniel-mohr closed 10 months ago
Maybe it's a miscalculation proble.
My 1st thought was "overhead", but overhead should be usually the same, so it should be cancelled by previous one.
Maybe rounding or similar, I'll take a look.
As I have one of this boards I can test it by my own....
Checked and it works correctly. When using 500 us it deviates 1~5 us, but it's understandable because Serial takes its time, and at 500 us rate it really floods Serial.
Few thoughts about your sketch:
I rewrote the test this way:
#include "Arduino.h"
#include "uTimerLib.h"
volatile unsigned long int prevMillis = 0;
volatile unsigned long int actMillis = 0;
void timed_function() {
SerialUSB.println(actMillis - prevMillis);
prevMillis = actMillis;
}
void setup() {
SerialUSB.begin(57600);
TimerLib.setInterval_us(timed_function, 500);
prevMillis = micros();
}
void loop() {
actMillis = micros();
}
Also, take in mind it's 48MHz CPU, so it's not rounded to us:
Name Prescaler Freq Base Delay Overflow delay
GCLK_TC 1 48MHz 0,020833333us 1365,333333333us; 1,365333333333ms
GCLK_TC/2 2 24MHz 0,041666667us 2730,666666667us; 2,730666666667ms
GCLK_TC/4 4 12MHz 0,083333333us 5461,333333333us; 5,461333333333ms
GCLK_TC/8 8 6MHz 0,166666667us 10922,666666667us; 10,922666666667ms
GCLK_TC/16 16 3MHz 0,333333333us 21845,333333333us; 21,845333333333ms
GCLK_TC/64 64 750KHz 1,333333333us 87381,333311488us; 87,381333311488ms
GCLK_TC/256 256 187,5KHz 5,333333333us 349525,333311488us; 349,525333311488ms
GCLK_TC/1024 1024 46.875Hz 21,333333333us 1398101,333333333us; 1398,101333333333ms; 1,398101333333333s
Few thoughts about your sketch:
* Never use milis / micros inside an interrupt
I know, it is not perfect. But it shows an easy possibility, which can everyone do without any special equipment (e. g. without an oscilloscope).
* Do interrupt as small as possible, specially when using so small timing.
Yes, you are right. But for 10 us it is still small enough.
void timed_function() { SerialUSB.println(actMillis - prevMillis); prevMillis = actMillis; }
I do not think SerialUSB.println
is better than milis / micros. Especially if we go down to 10 us.
But anyway the result of your test script is something like:
502
503
504
501
504
This does not look like the expected 500
, did it?
Also, take in mind it's 48MHz CPU, so it's not rounded to us:
If we think at 10 us and use the prescaler 16 then the resulting frequency is 3 MHz (as you already stated). This means we have 10e-6 / (1/3e6) = 10e-6 * 3e6 = 30
(precisely!) periods for 10 us. There is no need to round here, is it?
The output from my script above for your library uTimerLib
would be something like:
mtime: 5154 SystemCoreClock: 48000000 microstime_delta: 13
mtime: 6154 SystemCoreClock: 48000000 microstime_delta: 13
mtime: 7154 SystemCoreClock: 48000000 microstime_delta: 12
mtime: 8155 SystemCoreClock: 48000000 microstime_delta: 13
mtime: 9155 SystemCoreClock: 48000000 microstime_delta: 13
As you can see this is not precise.
Therefore I did a measurement with an oscilloscope. As I a already wrote:
A more precise measurement with an oscilloscope shows there is an additional time of about 2.5 us (= 2.5e-6 s). So the handler function is called every 12.5 us instead of every 10 us.
The same is true for longer periods. Also for TimerLib.setInterval_us(handler, 100); I get about 102.5 us instead of 100 us.
As you can see in fast_samd21_tc tested using fast_blink_led_tc3.ino with fast_samd21_tc it is possible to do much more precise, e. g.:
set interval | expected T | mean T | min. T | max. T | std T |
---|---|---|---|---|---|
2 | 4 | 4.68 | 4.65 | 4.85 | 0.060 |
4 | 8 | 8.67 | 8.65 | 9.02 | 0.097 |
8 | 16 | 16.66 | 16.66 | 16.57 | 0.003 |
16 | 32 | 32.63 | 32.01 | 32.91 | 0.165 |
I did the same with your library and get that there is an additional 2.5 us.
The example measure_timing.ino from fast_samd21_tc shows that using micros
works in an interrupt.
I adapted this for your library:
#include "uTimerLib.h"
/* serial interface */
#define SERIAL_BAUD_RATE 115200 // baud = bits per second
#define SERIAL_TIMEOUT 1000 // timeout in 1e-6 seconds
unsigned long start_microstime = 0;
unsigned long stop_microstime = 0;
volatile uint8_t it = 0;
volatile unsigned long duration = 0;
void handler (void) {
if (it++ == 0) {
stop_microstime = micros();
duration = stop_microstime - start_microstime;
start_microstime = stop_microstime;
}
}
void setup() {
// set serial communication:
Serial.begin(SERIAL_BAUD_RATE);
Serial.setTimeout(SERIAL_TIMEOUT);
while (!Serial);
TimerLib.setInterval_us(handler, 500);
}
void loop() {
delay(3);
static unsigned long mtime = millis();
Serial.print(" mtime: ");
Serial.print(mtime);
Serial.print(" microstime_delta: ");
Serial.print(((double) duration) / 255);
Serial.println(" us");
}
This leads with your library uTimerLib
to something like mtime: 1823 microstime_delta: 12.71 us
Whereas fast_samd21_tc leads to a much better result: mtime: 104481 microstime_delta: 10.04 us
.
You can also run this with an interval of 500. You will get with your library uTimerLib
something like mtime: 1783 microstime_delta: 504.65 us
, whereas fast_samd21_tc
leads to mtime: 10573 microstime_delta: 501.98 us
.
So, it is not the hardware. It is the software. And therefore I think your library has a bug!
If you do not believe the simple tests with micros
in the interrupt, please believe the measurements with an oscilloscope.
Wow, very in-deep analysys, thanks!
I'll recheck time-divissions; maybe use smaller periods. That whould add very little overhead but improve accuracy.
On an Arduino Zero (SAMD21) using this simple sketch shows 12 us or 13 us instead of 10 us:
A more precise measurement with an oscilloscope shows there is an additional time of about 2.5 us (= 2.5e-6 s). So the handler function is called every 12.5 us instead of every 10 us.
The same is true for longer periods. Also for
TimerLib.setInterval_us(handler, 100);
I get about 102.5 us instead of 100 us.Unfortunately I have to say that this is not a hardware problem. With my own trigger implementation I get the setting as measurement.
And further it is not clear for my why
uTimerLib
shows this behavior. Maybe you have an idea?