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

Ulrich Prinz ulrich.prinz at googlemail.com
Sun Oct 14 18:55:07 CEST 2012


Hi again,

Am 14.10.2012 13:50, schrieb Harald Kipp:
> Hi Ulrich,
>
> On 12.10.2012 22:20, Ulrich Prinz wrote:
>> I am still very deep in other things, far away from Nut/OS but I asked
>
> It's really nice to see, that many developers keep in touch, although
> there current focus is somewhere else.
>
Nut/OS is always fun, whatever you do actually.
>
>> 2) To assign numbers to things that obviously are not related to any
>> mathematical predictable rule always causes software overhead in sort of
>> tables, switch cases, if then else...
>
> An index? X1 = 5 * Y2? Where is the mathematical rule of indices 1 and 2?
>
No, what I had min mind was, that you often can address ports in ARM by 
just having a base address and add a fixed multiple of the port number 
to get the right address. Like 0x2006000 + (port * 0x2000).

On AVR and other smaller chips you may have ports A..D at 0x120 + (port 
* 0x04) but as the family grew bigger and the bit addressable area 
didn't grew too, PORTE...PORTH where thrown somewhere else around the 
memory.
>
>
>> Independent of any chip or CPU, NutGetPin/Port(NUT_GPIO_PORTx, bit) must
>> give the value of the bit at that port.
>
> That's the idea.
>
>> As you mentioned the extra features are a problem as different chips do
>> provide different optional features. I already proposed there something
>> but only Thiago ever tried to follow that thing. The idea was to make
>> some some commonly used options as a standard and to allow integrators
>> to add more.
>
> That's the point. Why do you want to add more features? Where is the
> advantage?
>
As speed rises, you'll be more and more in the need to debounce, set 
precise pull-ups or pull-downs and so on.

> If an MCU family provides specific features like debouncing or repeater
> mode, a native API tailored for this specific family would be sufficient.
>
> For AVR we have avr/io.h from avr-libc. For NXP we may create nxp-iolib
> with nxp/io.h. GpioXXX currently uses avr-libc to implement the required
> functions. When ported to NXP, GpioXXX could have used nxp-iolib likewise.
>
> If I write a driver specifically for the AVR, I'd _not_ use GpioXXX.
> Instead I'd use the non-portable avr-libc API, because my AVR specific
> driver doesn't need to be portable.
>
> And this is the point where I'm still missing an answer:
>
> Why the hell is the portable Gpio API used for drivers, which are not
> portable themselves?

Ok, that I forgot to answer precisely:

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.

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.
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?

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

What should be unified is the name of the option. And if you compile a 
project that uses a feature that your chip doesn't provide, it should 
result in an error as the features are defined per chip.
>
>
>> And if a board really doesn't support any kind of LED you could assign
>> the LED pins to some unused GPIOs, so it doesn't hurt the demo with lots
>> of #ifdef...#endif.
>
> I also see this requirement, but think, that this is related to Ole's
> topic about GPIO configuration.
>
No that is the point I am talking of:

You have the problem that making demo-code is difficult as the chips 
provide too much different options to do some basic things. And then, to 
top all that, the boards provide different peripherals connected to 
different pins too.

The solution is:
1) Handle as much as possible interfaces in drivers.
2) Make drivers for chips clients of drivers for busses.
3) Create a chips specific init, followed by a board specific init.
4) In your main loop only devices exist.

So:
1) I created a fast GPIO access function
2) I created a Key and LED device using 1)
3) In the board.c I configure a GPIO as output, what automatically 
enables clocks and things for the GPIO system. Then I register a LED 
connected to that GPIO by using my driver.
4) In demo main() I just set the behavior of the LED and it blinks.

As a low level programmer or someone who ports a chip, you have just to 
provide 1) and 3) and the demo code provided by 4) will work out of the box.

As a API user that uses a different board, you copy the board file, 
change the needed GPIO pins to the ones matching your board, and the 
code again runs.

GPIO is just an example. If you can register an I2C bus that provides 
the Nut/OS compliant acccess functions, you can always register an 
EEPROM on top of that bus and it will work.

So making demo code for EEPROM is as easy as let an LED blink.

Last one:
Never try to handle multiple boards with one board.c file. It will end 
in unreadable code that any new user will not understand.
This could be done in a project you develop for your company where 
anyone involved knows what you do. But it doesn't help anyone else.

Ulrich


More information about the En-Nut-Discussion mailing list