I did have a problem with a TC74 sensor when I optimized I2C bit-bang. This sensor is limited to 100 kHz I2C.
Still it is hard to believe that a factor of thirty in execution speed of basic I/O functions will not cause problems. That is why I designed my optimized functions to get a compile time error rather than revert to the slow functions.
It isn't that faster library code can't potentially cause problems. It is that it only causes problems for code that is taking advantage of and depending on certain timing that is not guaranteed to be anything and can change from release to release since the API does not claim to offer any timing maximums or minimums.
In some situations that may acceptable or even required, but in those cases, the code may not be able to properly function on a newer release of the tools.
A better way to write portable library code that "just works". is to write any timing critical sections in assembly to avoid any potential timing issues. In the absence of that, then write C code that is known to generate a fixed sequence of known instructions with guaranteed timing.
(which is what happens when you can get CBI/SBI instructions).
Then, for cases where specific timing minimums and hardware setup times must be ensured, use cycle delays to ensure that those hardware setup times are met.
Like in your case, you need to ensure that the signals don't toggle any faster than 100khz. There are portable ways to do this in C code that will work on any AVR at any clock rate. The latest GLCD library code that I wrote does exactly this.
This allows the library code to not only run on any AVR at any clock rate, but also get faster should the compiler or tools generate better code.
In the case of the GLCD library code, it steps WAY outside the arduino digital pin API routines to get the speed it needs. Now had the arduino libraries been written differently (same API just a different way), the GLCD library would have been able to use arduino supplied API functions rather than having to jump through hoops to avoid the arduino digital pin i/o library routines to get the needed i/o speed.
I guess my experience in embedded control systems where predictable api execution time is important doesn't apply to the Arduino.
Sure there are many times when predictable api execution times are mandatory for something to function properly. In those cases the API functions should offer, define, and honor such timing. In the absence of that, it is very foolish for the developer to write his code assuming any timing for a particular API function will remain a constant as tools and libraries are updated across releases.
In the larger picture, I don't believe that Arduino is any different when it comes to real-time timing needs from any other embedded environment.
i.e. eventually you may want to talk to hardware and that hardware may have critical signal timing that has to be met or not violated.
The difference is in Arduino there really are 2 types of needs for API capabilities:
- 1 for the Arduino application writers who are less technical
- 1 for the Arduino library writers that have real-time requirements
and write a library to be called by the less technical users.
The two needs are quite different.
If Paul is correct then there should be only one digitalWrite and not several under bar variations.
For the most part, and in general, I agree with this.
However, there are times in a library where you have to have specific timing and even the newer much faster high level digital i/o functions like what paul is now using in his teensy libraries that replace the arduino digital pin i/o routines, may still not be quite good enough.
And that is where the additional (underbar) functions can really make the difference.
Also, keep in mind that to implement what paul is talking about,
(which is the same thing that I've been talking about - and paul and I have collaborated at times), function layering is required.
You have to have different layers of function calls (which have to have different names) that can be called depending on the type of argument (constant vs variable and direct i/o vs the additional handholding).
The function layer to eventually call is determined at compile time.
So whether you openly advertise the names of the sub functions that get called under the hood for doing the high level functions of handling timers, pwm, and direction bits, or the low level CBI/SBI instructions, you still have to have these subfunctions.
What I've been saying all along is that since you have to have these layered function calls anyway, go ahead and advertise them and each layers behavior.
Then use a common naming convention like tacking on additional (underbar) so that those that want or need the absolute fastest bit setting/clearing capability can use them and avoid any additional overhead.
This would allow those that want the existing API with all its handholding to get it, to get a performance boost for using constants over the klunky existing ditital i/o routines.
And those that need the absolute fastest single instruction SBI/CBI code to set/clear bits have a known and documented way to do that for their real-time library needs.