-
Notifications
You must be signed in to change notification settings - Fork 2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
periph/gpio: enable API usage for expanders #9690
Comments
Okay. Lets see how the API proposal in #9582 does and then we can better populate our TODO list. |
Just to inform, I have used the GPIO extension API with two real expanders PCF8575 and PCF8574A. |
Thank you for your kind words @gschorcht ! |
@kYc0o Sorry, I missed that this tracking issue is explicity for GPIO when I was extending references with the PRs for ADC, DAC and PWM extension. Should we rename it to perhiph/* to track all types of peripheral extensions or should we open tracking issues for each type of extension API? |
Hi @gschorcht ! No worries, as long as it's manageable to track from here I have nothing against the renaming. |
I'd like to take another look at the redirection method. I haven't taken an in-depth look at the API changes other than for gpio, so this applies mostly to gpio. The reason why we want to change all the API's in the first place is that we need to support multiple "providers" of the functionality (I2C gpio extenders, bitbanging soft bus implementations, UART-over-USB, external ADC/DAC, ..). Ideally we manage to do that while
If I understand the current method correctly:
So far, so good.
I propose the following:
I think this way it might be possible to save quite a lot of the redirection code. It would remove the necessity for (MCU specific) "GPIO_EXT_THRESH". It would allow creation of portable GPIO_PIN(GPIO_EXT_A, pin-nr) macros. It would remove the need for a pin->driver mapping. @ZetaR60 @gschorcht what do you think? Another slightly more complicated option would be to have an MCU specific "gpio_is_ext(gpio_t)" function and use that instead of "driver==NULL" to do the redirection. That way gpio_*_cpu could make use of the driver field. Another idea, if we introduce "gpio_ext", would be to go all the way and introduce "gpio_port_*", exposing whole ports even for the MCU internal gpio ports. |
@kaspar030 Looks like your summary of the work and the considerations involved is pretty spot-on. If we are going the path of passing around pointers or structs to identify devices rather than ID numbers, then there are some big advantages that a more general transition would offer if we do some thinking about forward compatibility now. The extension interfaces would offer a limited trial of this method that could gradually be integrated more widely if it works out well. Not only could multiple providers of the same API be offered, but devices that currently have a different API for each type of underlying hardware could be unified into general APIs that only care about the broad details of how data is moved using the API. An example use case was brought up in our discussions last year about xtimer and ztimer, and how it might be better to implement stacks of timers rather than a monolithic timer system like xtimer. Currently we have Some other examples that come to mind:
I don't propose any kind of decision on whether to transition, but rather I propose that if this is a potentially valuable transition and we are starting to pass around more complex identification information anyway, that we plan ahead and make the extension interface a trial of these methods in anticipation of the possibility of more general API transitions in the future. I suggest that most APIs could pass around pointers to a struct containing the following information (with slight variations per-API):
Passing all of this using a pointer would also have the advantage of making the API not care where the information actually came from (rather than retrieving it from an array), so it would facilitate dynamic loading of new devices. |
? 😉 |
Some comments from me.
I would really like a concept that integrates expanders seamlessly and completely invisible for users. From the users point of view an ideal integration would allow to access CPU as well expander pins using the GPIO_PIN(x, y) macro without the necessity to distinguish between CPU and expander pins by using either GPIO_PIN or GPIO_EXT_PIN.
This would be really great.
It might be difficult to initialize these data structures for all CPU and expander pins without having tables of these structures for all pins that are initialized during the initialization of the CPU/expander. Such tables would require additional memory. |
@ZetaR60 The question is how do we continue. Would you start a new try or should we discuss it a bit more. Code could be a good mean for further discussion. |
Hm, I didn't escape properly. The difference is |
Yes, me too. Let's assume that in the application's periph_conf.h (or however we're organizing configuration in the future) there's a defined expander struct, and it has been given a speaking name like I think with the current gpio implementations that might be difficult, as the
Do they have to be initialized? I'd assume an expander to have:
IMO gpio_t should only serve as reference (not contain state information), as it might be copied around into e.g., a driver's param struct. It should be left to the expander's internal implementation how to save state. |
Let's not try to find "one API to rule them all(tm)". It is impossible to get minimal code size, ram requirements, runtime performance and full flexibility at the same time. The timer's are a nice example. I think it is totally valid to have a slim-as-possible abstraction on the (hardware)-timers (what periph/timer is now, plus rtc/rtc) and then create something like xtimer (and soon ztimer) on top. It is not like when periph was designed, we didn't think about making the API C-object-oriented as discussed here. Mostly code size and massively reduced optimization when using pointers lead to what we have now. Now the tradeoffs are biting because it is not (easily) possible to have extenders or software implementations in addition to the hardware ones. But it is possible to write a reasonably fast and portable bit-banging I2C using the current gpio interface. With full OO and pointer-to-ops-struct, that wouldn't be. |
Maybe I missed something. As I understood, the GPIO_PIN macro should lead to the struct
that is used for the API functions |
Ah, I see. Yes. Maybe in the beginning sth like this could work:
We'd have two defines, but this should keep current code still working. If we can transition all gpio_cpu_* to use the gpio_t field for port and pin, at some point, we can turn the two into one. |
As long as nothing has been changed, it should be easy as to
I would do it in the first step since it will become difficult to use |
I like the ideas discussed so far. I am starting work on a v3 PR. I suggest using the following definition:
instead of the proposed:
because it will cause trouble with the syntax for pin usage changing depending on whether the extension interface is enabled or not. It will require changing |
Great. I'm curious about it. I like the @kaspar030's ideas too. |
@ZetaR60 Is everything OK with you and how is going with v3? 😉 I'm really curious. |
There are some difficulties with changing gpio_t into a structure. The main difficulty is that C does not allow the equality operator to be used for structs. I really wish C did something like "two structs are equal if all of their members are equal", which would make the transition much easier. I see two potential solutions for the struct issue:
I think both can probably be made to produce the same compiled binary when the extension interface is disabled as before the API change. A function based equality check has the advantage of being the more "correct" way of doing things, but there are a lot of instances of equality checks to change and there is a potential for a mistake to make a regression with each change. A cast based method would allow all of the existing code to remain the same, but would require some care to prevent padding and such from interfering with its operation. I think the cast method is more favorable as the exact mechanics can be hidden within Thoughts? |
@ZetaR60 Are you still working on the API? After having almost no time the last 6 months, I will have some time in next weeks. If you don't have time, I could make a try. |
@kaspar030 I would like to make some progress with the extension API for two reasons. First, it would be a great improvement of RIOT to have a concept for expanders. And second, I have already written a number of expander drivers that do not depend on the extension APIs but are already ready to work with extension APIs PR #10430, #10688, #10556, #10518. Since @ZetaR60 does not seem to have much time at the moment, I tried the concept you suggested a little bit. I really like the idea of seamless integration that always uses the macro However, there are a number of problems:
Shouldn't we better follow @ZetaR60's approach of redirection and driver list #9860 and #9958? Also with the @ZetaR60 approach, we could implement a generic macro |
@kaspar030 After spending some time in recent weeks changing a lot of code to try your suggested approach, I am at a point where I would be very grateful for your help 😎 Maybe you have an idea how to solve the problem or get around it. What we have are CPU specific or default GPIO definitions that usually look like:
In a first step, I renamed all According to your proposed approach and the work of @ZetaR60 ZetaR60, I then defined the GPIO extension API as follows:
where
The goal was to use GPIOs of CPU and extenders in same way in board configurations, e.g., for LED pins:
or driver configurations. The problem is the
While it works perfectly for constant
it doesn't work for constant structures with
because the compiler complains that the initializer isn't a constant. However, we have a lot of driver configuration structures with Changing the code in all Do you have any idea? |
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. If you want me to ignore this issue, please mark it with the "State: don't stale" label. Thank you for your contributions. |
This issue aims to track the progress on the definitions for the GPIO API extensions, and its implementations on the corresponding CPUs.
The text was updated successfully, but these errors were encountered: