[En-Nut-Discussion] RFA_4: Nut/OS GPIO API
ulrich.prinz at googlemail.com
Wed Oct 24 23:08:10 CEST 2012
slowly not again to mess up things.
If you need to keep a certain timing, it is important that simple
routines never alter their timing.
So if you think that your setpin() function is a
#define setpin( port, pin) 0xdeadbeef+0xaffe*port = pin
but as you enabled NUTDEBUG your function is
void setpin( port, pin)
0xdeadbeef+0xaffe*port = pin;
must not result in same timing behavior as it is now a function an may
slow down as function entry and function exit parts are added by the
compiler. Encapsulation loosens up register mapping, so the compiler may
decide to take this function call to free some registers to stack,
execute the function and pop back th registers.
But there is a chance that the compiler decides not to open up a stack
frame for a one-liner and it optimizes register use to just 'inline' the
It depends on the compiler version and the optimization -Ox setting.
If you now have a parallel 4-bit protocol emulation running with parts
of the lines on different buses or you do software PWM for motor or
In my case the worst thing that my happen is, that port is calculated
dynamically. So if port is a variable, my line will result in a
multiplication, followed by an addition and the real write cycle:
0xdeadbeef+0xaffe*_variable_ = pin
But the NUTASSERT( port, PORT_IS_A_PORT) will now be expanded to a real
if (port != 0xaffeaffe) && (port != 0xdeadbeef) && (port!= ...
if (pin < 0) |< (pin > 15) ...
0xdeadbeef+0xaffe*port = pin
And these multiple-if costing much time, each part of it a subtraction
or an addition followed by a jump or branch.
So as these things are complicated and deep down in the assembler,
newbies will stumble over it. It works with debug, but doesn't without
or the other way round. It works with -O2 but not with -Os...
So my suggestion was: Add the warning to the RFA, that enabling debug
may alter the timing of the GPIO functions. That doesn't cost anything
but they are warned.
Am 24.10.2012 13:30, schrieb Uwe Bonnes:
>>>>>> "Ulrich" == Ulrich Prinz <ulrich.prinz at googlemail.com> writes:
> Ulrich> I just wanted to warn, not extend the discussion. Just keep the
> Ulrich> warning in the RFA, that's all.
> Ulrich> In you rexample, asserts (<port is valid> && <pin_is_valid>)
> Ulrich> highly depends if both conditions can be decoded to conditions
> Ulrich> without variables in pass one by the compiler. So I would
> Ulrich> consider this as only 90% true.
> Ulrich> But normally users will write their code for a certain platform
> Ulrich> an will check that the pin is valid and the port is available.
> Ulrich> We additionally defined, that the port and pin can be detected
> Ulrich> for availability and support of a certain function by the
> Ulrich> appropriate setup functions. So we are on safe ground.
> Ulrich> There is only a slight chance that someone is going nuts while
> Ulrich> trying to figure out why his timing is going wrong, while
> Ulrich> seconds ago it perfectly worked...
> Appended code compiled on linux gives:
> main.c: In function ‘main’:
> main.c:30:5: error: call to ‘port_check’ declared with attribute error: assertion failure: 'IS_GPIO_ALL_PERIPH(6)' not true
> main.c:31:5: error: call to ‘pin_check’ declared with attribute error: assertion failure: 'PIN_IS_VALID(17)' not true
> I think something similar can be done for arm-xx-gcc and the GPIO API (on gcc).
More information about the En-Nut-Discussion