[En-Nut-Discussion] RFA_4: Nut/OS GPIO API

Ulrich Prinz ulrich.prinz at googlemail.com
Wed Oct 24 23:08:10 CEST 2012


Ok,

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)
{
	NUTASSERT(PORT, PORT_IS_A_PORT);
	NUTASSERT(PIN, IS_A_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 
functions.
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 
servo control...

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 
multiple comparison:

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.

Ulrich

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).
>
> Bye
>


More information about the En-Nut-Discussion mailing list