[En-Nut-Discussion] Nut/OS GPIO API Initial Design and Current Status

Ulrich Prinz ulrich.prinz at googlemail.com
Sun Oct 14 23:46:35 CEST 2012

Am 14.10.2012 20:03, schrieb Harald Kipp:
> Hi Ulrich,
> On 14.10.2012 18:55, Ulrich Prinz wrote:
>> 1) Q) Why general function set for GPIO access, not a special one
>> for high-level and low-level programming?
>> A) For STM32 there is no need to use separate APIs for GPIO as the
>> API functions are already the fastest way to access GPIO. So there
>> is only one function set available.
> Which is getting more and more complicated, because other chips do
> not provide GPIO_CFG_SPEED_FAST and STM32 doesn't provide
> GPIO_CFG_SLEWCTRL and the next platform will demand GPIO_CFG_SLEWCTRL
> only if GPIO_CFG_SPEED_FAST is not set...and so on...
Wow... careful, I never argued that the use of the API gets you rid of
reading the manual! There are certain modes that require certain
presets, that is true. If you are a driver programmer you should take
care of these things and try to automate them. But you always can only
give a leading hand. The user has to walk for himself.

And I said that you should define those options on a per chip base. So a
AVR code should never provide GPIO_CFG_SLEWCTRL.
>> 2) Q) Why do I feel that a separate GPIO access is obsolete?
>> A) If you are porting a new chip, you might think that you need
>> comfortable and easy access GPIO functions and you know that the
>> AVR example is the easiest one to understand. But then, with the
>> first RS485 driver, where you have to switch bus direction using
>> your own GPIO access functions, you learn that GPIO access times
>> might be relevant to system performance. So you do the work, you
>> should have done at the beginning, just a little bit later.
> Sorry, I cannot follow. What I understood was, that by convention
> something like
> port1.outreg |= 1 << 0;
> is used for many ARM targets to set bit 0 of an output port to 1. If
> you need target specific functions, one would use
> port1.special &= ~(1 << 0);
> to clear bit 0 in the special function register. What kind of
> _portable_ API would help here? You need to check the datasheet
> anyway.

this is a non atomic access (read modify write) of the register and I
would have checked datasheet to see that it could be done like this:

Let's say PORT0..PORTx is #defined as the address of the register sets. 
Then your port access for ARM is mostly like this:

#define NutGpioPinSet(p, b) p->BSR = (1<<b)
#define NutGpioPinClr(p, b) p->BSRR = (1<<b)

Ups... it is already the portable API...

The cortex is even niftier, as he can write a value to a special bitbend 
area. Any value not zero will set a bit, else clear it.

>> And at the end you ask yourself, why should I use a fast method to
>> switch and control GPIOs in my low-level drivers, but only provide
>> a complicated slow code to the API users?
> IMHO, a portable Gpio API can never serve as a full replacement for
> accessing I/O registers directly. Platforms are too different.

Didn't see any reason for now. Didn't see one while porting STM32.

>> 3) Q) Why should I try to provide access to all features a chips
>> component has?
>> A1) Because I could. A2) Because there is always one person needing
>> exactly that thing that you thought of as obsolete. A3) It doesn't
>> hurt, as here the same things apply that apply for the GPIO access
>> functions. Normally small chips just have little features for their
>> GPIOs (and their other peripherals too). So a small value is enough
>> for their features. I.e. for AVR a size_t or uint8_t should be fine
>> and all options could be addressed. In one case NUTGPIO_PULLUP is
>> 0x02, in the other case it is 0x00020030 or even ((1<<PUE) |
>> (1<<XEN) | (2<<PURES))
> Please correct me, if I'm wrong: You demand to press all functions
> of all targets into a single, portable API, which will provide the
> optimal code on all platforms.
> May be you can, but I have my doubts, that anyone will maintain such
> a beast or port it easily to a new platform. It will be a PITS,
> which indeed hurts. ;-)
> Ulrich, you are mainly explaining advantages of having an API for
> GPIO, which I did not put into question. My objection is, that this
> needs to be done in a portable API, available on all targets.

Ok, I agree that we cannot write a two-step, gpio.c and gpio.h that 
matches all and everything. That I never wanted to have. Even I daub 
that this will ever work.

But you could write a gpio API that works per chip and you can write it 
in a way following rules.

Lets think about a compromise like this:
1) Every architecture provides these functions as a minimum
void NutGpioPortSet( p, v)
size_t NutGpioPortGet( p)
void NutGpioPortCfg( p, m, v)
void NutGpioPinSet( p, b)
size_t NutGpioPinGet( p, b)
void NutGpioPinCfg( p, b, v)

Then every feature that can be configured follow the naming convention 
of NUTGPIOCFG_blabla.
We provide a minimum support set that works on all chips.


For safety reasons, OUTPUT should always be Open-Drain, only if a user 
really knows what he does he should add PUSHPULL.

If you now know, that your ARM requires
NUTGPIO_PULLUPENA | NUTGPIO_PULL24K to enable a pullup that is round 
about the usual 20k of the good old AVR pullup, then you define all 
these extra bits and use them to assemble the above term:


So a API user can use the code he knows from AVR.

That all I had discussed with Thiago about 2 years ago I think. There 
are to many features to cover them all with modern CPUs. But there is no 
reason not to break them down to some usable and standardized collection 
of options.

And yes, if you are in a hurry and only implement some features, it is 
ok. There eill be someone else who adds the ones he missed and needed. 
So the collection will grow.

And to be honest, I do not think that we have a problem with the GPIO 
API... I feel that it will be much more difficult to write a usable API 
for modern timers, PWM stages and ADCs. There you'll find true horror if 
you like to unify it.


More information about the En-Nut-Discussion mailing list