-
Notifications
You must be signed in to change notification settings - Fork 88
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
delayMicroseconds() #18
Comments
I think the best solution for LGT MCUs is if we use a NOP between SBIW and BRNE. |
Edit: I found this code not precise because the compiler using only the whole part of F_CPU/3000000L. The corrected code is in a a later omment. If you don't want to delay zero time and every timing are constans (not variable), this most compact and precise LGT8Fx specific code is for you. (Must be in Arduino.h) Link time optimization (LTO) does not matter.
|
Would this work for any selected speed? I'm asking because of the |
Yes I think. I did some compilation with different selected speeds and
code disassembling. Timing values seems correct, but I can't measure.
Tested on 16 MHz with DS16B20 temperature sensor.
|
When I write timing are constans, I mean compiler calculate ( F_CPU/3000000L * microseconds) like this example at 16 MHz:
If you call delayMicroseconds() macro with variables, MCU will do necessary calculations. It cause more delay than load two registers, so delay would be not precise. Don't use my macro like this:
|
Allright, thank you for the explanation! Really appreciate it. :) |
Now this code really precise.
|
Ill add the new delayMicroseconds version you posted first on the next version. Thanks for that! |
I forgot about this one in the last release. |
( if anyone read my comment I just deleted - it's just too hot and I did a mistake ^^ ) |
If you want to try on 32 MHz, you must use my delayMicroseconds code.
|
@LaZsolt , i used the macro version, but accidently put it into wiring.c instead Arduino.h. |
When using macro version of delayMicroseconds() with higher values, the compiler multiplication overflow 32 bit number, so the timing will not correct. I have an idea how to solve this problem, but I need to sleep now. |
I made several compilations on new code. No 32 bit overflow within parameter limitations.
Macro parameter limitations:
Timing in microsec at 1, 2, 4 MHz, when parameter is:
|
@dbuezas, |
with #51 merged, this can be closed, right? |
Not yet. I would like to comment here my ideas for a while. |
ciao, well done for your job!! |
@XGIACOMO Anyway, delayMicroseconds() is not modified in the release v1.0.6. The actual version of these branch of delayMicroseconds() will be in the next release. If you want to use my better delayMicroseconds() now, you need to copy this two files https://github.com/dbuezas/lgt8fx/blob/master/lgt8f/cores/lgt8f/Arduino.h to your hard drive directory:
|
Be aware digitalWrite() takes 2 to 5 microseconds. |
If you want to get as efficient, precise, and fast as possible at having something happening at regular intervals, there is a trick you can do using counters. It is the same as using interrupts but you just busy-wait for the counter to reach its target instead of consuming the 50+ cycles of the whole interrupt prelude, return & stuff. So let's count clock cycles on run time: // setting up timer 1
// secPerSample means "seconds per sample"
// this will work up to a max wait of 2ms (i.e secPerSample=0.002)
void startCPUCounter(float secPerSample) {
TCCR1A = 0;
TCCR1B = (1 << WGM13) | (1 << WGM12) // CTC mode, counts to ICR1
| (1 << CS10); // prescaler set to 1
ICR1 = secPerSample * F_CPU - 1;
TCNT1 = 0;
setBit(TIFR1, OCF1A); // clear overflow bit
}
__attribute__((always_inline)) inline void myDelay(){
loop_until_bit_is_set(TIFR1, OCF1A); // this can be off by at most 3 clock cycles, but error won't accumulate because the timer will keep counting
TIFR1 = 255; // setBit(TIFR1, OCF1A); is actually enough, but clearing all flags at once is quicker and I'm not using the other timer flags anyway.
} And then you busy-wait for a very precise timing that doesn't accumulate error: void setup(){
startCPUCounter(1.0/1000000); // 1us cycle
}
void loop(){
noInterrupts(); // if you don't do this, it will be a bit off some times, but error won't accumulate.
for (int i = 0; i< 10000;i++){
doTheThingThatNeedsToHappenAtVeryPreciseAndShortIntervals();
myDelay();
}
interrupts();
} It is the trick I ended up using in the oscilloscope project to get the oscilloscope here to go very fast even while handling multiple channels and checking for triggering conditions. Only there I'm using Timer3 and fiddle with prescalers to get to higher waiting intervals when necessary. Obvious in hindsight I did feel really clever about this. The good thing about all this nonsense, is that the counter will keep track of time while you are doing something else, so error never accumulates. |
hy dbuezas, thank you for your answer!! |
great job @LaZsolt!!!!!! much better than before ;-) |
It's about time we make a new release including all these improvements from @LaZsolt et al. |
@XGIACOMO |
@dbuezas |
@LaZsolt that's awesome! |
@dbuezas only few days. |
@LaZsolt : |
I may can create a source for the case of runtime variable clock speeds, but the delay count calculations became more complex, so short timing will be more inaccurate. Better idea is, when caller will calculate before calling |
More sources in the coming days. |
Just finished, but not tested yet: https://github.com/LaZsolt/delayMicroseconds/tree/master/for_LGT8F |
Watch my new readme. https://github.com/LaZsolt/delayMicroseconds/tree/master/for_LGT8F |
@LaZsolt : I don't know if it it could be useful to you, but if you want to protect some of your functions from compiler optimization, you can encapsulate them this way : #pragma GCC push_options
#pragma GCC optimize ("keep-static-functions")
static void foo( int a )
{
// code i want to protect from compiler optimization
}
#pragma GCC pop_options You can also specify a level of optimization More info here : |
Finished, tested. |
An interesting trick: This code will wait x*4 - 1 clocks cycle as we know.
This little trick, with same code size, can make a bit readabe delay calculations inside delayMicroseconds_v(). |
Yes, I found a solution for Other thing is, the delay calculations and the delaying cycle all written in assembly language, so it will avoid compiler or linker optimizations. |
@LaZsolt : sounds great ! |
When I tested, the compiler handled the different speeds.
But after I put the final source into the core (without namespace) I getting redefinition errors in every namespaces. |
Oh ! I've just noticed I misread your message in my first answer that i've just deleted.
So the namespace trick works if the delayMicroseconds() function is stored into a separate header. If that's jsut a matter of copy/pasting, I don't think it's a problem. Your namespace trick is more elegant than what I proposed in the answer I deleted. Thanks for the idea ! |
A very new delayMicroseconds() are finished and tested again.
You may use it with different clock frequencies in one source. This example shows how to use it on the menu selected and the other frequencies together:
The source is here: https://github.com/LaZsolt/delayMicroseconds/tree/master/for_LGT8F
|
@LaZsolt sorry to hijack this issue. I am trying to port waiting functions from the AVR Transistortester (in
|
@DurandA : according to chinese datasheet, rcall needs 1 cycle, and ret 2 cycles. See page 252 : https://raw.githubusercontent.com/dbuezas/lgt8fx/master/docs/LGT8FX8P_databook_v1.0.4.ch.pdf |
@SuperUserNameMan Thank you very much. I missed it in the translated datasheet. |
In wiring.c delayMicroseconds() function using SBIW and BNRE instructions for timing.
In AVR MCUs it takes usually 4 clock cycles while in LGT MCUs takes usually 3 clock cycles.
Therefore this function delay less than expected.
I found a better version in a chinese site. The author corrected only 16 and 32 MHz cases.
https://www.geek-workshop.com/thread-38486-1-1.html
The text was updated successfully, but these errors were encountered: