Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix multiple timing errors in example sketch #6

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

edgar-bonet
Copy link

This pull request fixes many errors in SimpleEMGFilters.ino that made its timing unreliable.

Use unsigned long to get correct arithmetic on timings

micros() returns an unsigned 32-bit number (unsigned long). Its value rolls over roughly every 71.6 minutes. When this happens, timeStamp is close to 232, while micros() is close to zero. If computed as unsigned long, the difference

timeElapsed = micros() - timeStamp;

wraps modulo 232 to the correct result. If computed as unsigned long long, however, the difference wraps modulo 264 and ends up being too large by 0xffffffff00000000. This ends up causing a delay that is way too large.

The comment “micros() will overflow [...]” has been removed, as it becomes irrelevant once the timing arithmetics are done with the correct type.

Update the timestamp with += interval in order to avoid drift

The sketch currently tries to control the sampling rate by having loop() execute in exactly 1 ms. However, this is unreliable, as there are a few instruction for which the execution time is not accounted for, including returning from loop() and calling it again. This causes the timing to slowly drift, and the average sampling rate to be slightly lower than intended.

This is fixed by changing the meaning of timeStamp: it is now the time when a sample ought to be taken. The actual sampling can happen a few instructions later but, as timeStamp is always updated by adding interval, these timing errors are non-cumulative, and the average sampling period is exactly 1 ms (non counting for the inaccuracy in the physical oscillator).

Avoid printing more that what can be sent between samples

At 115200 b/s, printing the string "Squared Data: " takes about 1.215 ms, which is more than the intended sampling period. It is thus impossible to sample at the intended frequency while printing this message for each sample.

In debug mode, do not count the cost of printing to the serial port

Again, because of the speed of the serial link, if _DEBUG is defined, it is impossible to keep up with the intended sampling rate. Thus, we don't even try, and instead we attempt to give an accurate estimate of the time cost of the filter. This requires flushing the output buffer in order to not count the time cost of the serial communication.

Use delayMicroseconds() for better resolution

The required delay is always less than a millisecond. The delay() function is thus not appropriate, as its resolution is one millisecond.

Only delay if there is some time left

If the program ever gets a bit late for a sample, interval - timeElapsed wraps modulo 232 to a very large number, which causes a delay of more than 70 minutes. Avoid this by delaying only if we do have some time to kill.

SimpleEMGFilters.ino had many errors that made its timing unreliable.
Fix them:

- use `unsigned long' to get correct arithmetic on timings
- update the timestamp with `+= interval' in order to avoid drift
- avoid printing more that what can be sent between samples
- in debug mode, do not count the cost of printing to the serial port
- use `delayMicroseconds()' for better resolution
- only delay if there is some time left
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant