Skip to content
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

Runtime pin configuration #11918

Closed
dhalbert opened this issue Dec 6, 2018 · 14 comments
Closed

Runtime pin configuration #11918

dhalbert opened this issue Dec 6, 2018 · 14 comments
Assignees

Comments

@dhalbert
Copy link

dhalbert commented Dec 6, 2018

We're looking at porting CircuitPython to Zephyr. We currently support SAMD21, SAMD51, ESP8266, and nRF52832 and nrf52840. The nRF ports are in progress.

One feature we need (and most other language interpreters need as well) is dynamic pin configuration. The user's Python program can choose to use any pins for any purpose, within the limitations of the microcontroller. The pins are assigned at runtime in Python code and may even be changed during the life of the program. For instance, two pins might be used as GPIO or UART and then assigned to an I2C device drive.

My understanding is that Zephyr uses the device tree to assign pin functionality at build and startup time. I see a few issues about more flexibility: #8849, #9607, and maybe #9198. But I think these issues are about initial flexibility in assignment that is then not changed during the lifetime of the application.

Is there something in Zephyr now that would allow us to do dynamic pin configuration/assignment? Could we not provide a fixed device tree and use lower-level routines? Or is this a feature that would need to be added? I don't know Zephyr well enough to understand the issues, but would be grateful for suggestions and guidance. Thanks.

@aurel32
Copy link
Collaborator

aurel32 commented Dec 6, 2018

@dhalbert, I think you are looking for the pinmux driver, which allows to (re)configure pins at runtime. The interface is described there: https://docs.zephyrproject.org/latest/api/io_interfaces.html#pinmux-interface . You might also want to look at the code there: https://github.com/zephyrproject-rtos/zephyr/tree/master/drivers/pinmux/dev

Unfortunately it is currently only supported on a limited amount of SoCs: Atmel SAM3X, STM32 and ARM V2M Beetle.

@galak galak added the question label Dec 8, 2018
@galak
Copy link
Collaborator

galak commented Dec 8, 2018

This might be better asked on the zephyr devel list [email protected]

@carlescufi
Copy link
Member

I am reopening this since it's a legitimate use case, different from #20012 and that is not covered elsewhere.

@carlescufi carlescufi reopened this Feb 28, 2020
@carlescufi carlescufi added area: Devicetree area: Drivers Enhancement Changes/Updates/Additions to existing features area: GPIO area: API Changes to public APIs and removed question labels Feb 28, 2020
@carlescufi carlescufi changed the title Dynamic pin configuration Runtime pin configuration Feb 28, 2020
@tannewt
Copy link

tannewt commented Mar 3, 2020

@carlescufi Please post any planned discussion times around this issue (like the API meeting) so we can be sure to attend. Thanks!

@carlescufi
Copy link
Member

@carlescufi Please post any planned discussion times around this issue (like the API meeting) so we can be sure to attend. Thanks!

Yes, of course. Right now this feature will probably be discussed as part of #22748, pending whether @erwango thinks this is indeed a good idea.

@erwango
Copy link
Member

erwango commented Mar 4, 2020

@carlescufi, @tannewt, @dhalbert I think it's a good idea. Though I don't know what are the dependencies with #22748 yet.
Maybe the first question we need to answer is what type of high level service are we talking about. To avoid dependencies to external projects, I guess the problematic could be rephrased as "how to set my peripheral pins at run time within an application?". What about thinking of a shell module?
User should have access to some helper functions as follows

 $ pin set uart1 tx pa2
 $ pin set uart1 rx pa3
 $ pin unset uart1 tx
 $ pin unset uart1 rx

Second option:

 $ pin set uart1 pa2 pa3
 $ pin unset uart1

Second option is slightly more complex as user need to be instructed what is the expected order of the pin functions.
First option needs another instructions to say "I'm done with pin configuration for this device, launch the driver configuration".

Once pin configuration is provided, we need to:

  1. check that the device is enabled (user could not configure usart_4 if usart_4 instance of usart peripheral is not available in the binary)
  2. check that requested function is available on a given pin (for STM32 this would be: pa2 could be used as usart1_tx, alternate function number is 5).
  3. optionally: check that there is no conflict on pa2 (not already in use on another device)
  4. optionally: check that this is device could be configured at runtime (should is be allowed to configure ethernet pins on a board with a builtin ethernet controller ? Should we have protected devices, like console?)
  • Today, we do have info on 1.
  • On some archs at least (we might rather count the archs that don't need it), point 2 will require to embed a pin muxing table providing the full function>pin>device>alternate mapping.
  • Point 3 requires to build a table at boot time with boot time pin configuration and be able to update it at run time

Now, about lower level impacts: I see two options:1. Implementation at device level2. Centralized implementation
If implemented at device level, each device could define its own pinmux_t structure that could be used in new "pin_set(struct dev *, pinmux_t pinmux)"/"pin_unset" api call.This answers easily 1 and 4. 2 and 3 requires access to common resources (provided by another device like pinmux/pinctrl device ?)
A centralized implementation would ease 1 and 4 check but would anyway require knowledge of pinmux configuration for each device (with mandatory and optional pins). and a way to trigger device pin reconfiguration, which gos back to implement some sort of pin_set/pin_uset api.

So either user access directly to device pin_set/pin_unset or via a a centralized service, this API would make sense. And, to link with #22748, this would only require, on each device a minimum overhead on top of a per device pinctrl.
For this run-time pin muxing feature, main work would lie in the centralized component, with the pinmux table and the ability to verify pin conflicts at run time.

@tannewt
Copy link

tannewt commented Mar 10, 2020

@carlescufi, @tannewt, @dhalbert I think it's a good idea. Though I don't know what are the dependencies with #22748 yet.
Maybe the first question we need to answer is what type of high level service are we talking about. To avoid dependencies to external projects, I guess the problematic could be rephrased as "how to set my peripheral pins at run time within an application?". What about thinking of a shell module?
...

Second option is slightly more complex as user need to be instructed what is the expected order of the pin functions.
First option needs another instructions to say "I'm done with pin configuration for this device, launch the driver configuration".

I don't think a shell module is what we're looking for. @dhalbert and I work on CircuitPython which already provides a user facing API for requesting that a set of pins perform a particular function. For example, our Python-level I2C class simply takes in two pin arguments. It doesn't take in a particular peripheral instance. We figure it out ourselves internally.

Once pin configuration is provided, we need to:

1. check that the device is enabled (user could not configure usart_4 if usart_4 instance of usart peripheral is not available in the binary)

2. check that requested function is available on a given pin (for STM32 this would be: pa2 could be used as usart1_tx, alternate function number is 5).

3. optionally: check that there is no conflict on pa2 (not already in use on another device)

4. optionally: check that this is device could be configured at runtime (should is be allowed to configure ethernet pins on a board with a builtin ethernet controller ? Should we have protected devices, like console?)

We do this in CircuitPython with the concept of "never_reset". A board_init function runs before user code and can claim resources. Marking something "never_reset" means that the resource will not be reset after user code finishes and therefore ensures it is always claimed when user code is running.

* Today, we do have info on 1.

* On some archs at least (we might rather count the archs that don't need it), point 2 will require to embed a pin muxing table providing the full function>pin>device>alternate mapping.

Each of the CircuitPython ports has the starts of this for our use. We have approaches to it. The first is pin-oriented structures of mux table such as: SAMD21, SAMD51, nRF. The other approach is peripheral oriented where a table will list all possible pins of a given function such as: STM32F4 and iMX RT. Note that the second approach still has some elements of the first by having per-pin objects with some state.

Getting an easy-to-process digital copy of this data from vendors would be an awesome first step. We are still finding issues in our oldest data structures that were copied out a data sheet by hand.

* Point 3 requires to build a table at boot time with boot time pin configuration and be able to update it at run time

We do this in CircuitPython by checking for the default pin state (no gpio on, no mux enabled or set) and assuming it is free in the default state. This only breaks down for pins with special defaults such as SWD and pins that the runtime uses in addition to allowing the user to use them.

Now, about lower level impacts: I see two options:1. Implementation at device level2. Centralized implementation
If implemented at device level, each device could define its own pinmux_t structure that could be used in new "pin_set(struct dev *, pinmux_t pinmux)"/"pin_unset" api call.This answers easily 1 and 4. 2 and 3 requires access to common resources (provided by another device like pinmux/pinctrl device ?)
A centralized implementation would ease 1 and 4 check but would anyway require knowledge of pinmux configuration for each device (with mandatory and optional pins). and a way to trigger device pin reconfiguration, which gos back to implement some sort of pin_set/pin_uset api.

So either user access directly to device pin_set/pin_unset or via a a centralized service, this API would make sense. And, to link with #22748, this would only require, on each device a minimum overhead on top of a per device pinctrl.
For this run-time pin muxing feature, main work would lie in the centralized component, with the pinmux table and the ability to verify pin conflicts at run time.

This centralized service sounds good to me.

One more thing to consider is peripheral level muxing. For example, on SAMDs the pin mux table may say SERCOMX[0] (meaning pad 0 of the sercom) can connect to pin FOO while the peripheral itself can mux UART RX singles to pads 0, 2, and 3 but not 1.

@erwango erwango self-assigned this Mar 26, 2020
@erwango
Copy link
Member

erwango commented Mar 26, 2020

@tannewt Thanks for this description of the behavior of Cirtcuitpython on that matter and feedback on the proposal. This is helping.
Though, one thing that needs to be considered is that CircuitPython would be one of the various customers of this feature.

Also, if it has to be developed in Zephyr, we need to be able to test it in zephyr tree, so we'd need to have a Zephyr client (sample, test, shell) for this. I'll try to come back with a proposal next week if doable.

@pabigot
Copy link
Collaborator

pabigot commented Jul 7, 2020

API 2020-07-07: Moved from triage to To-Do pending completion of a generic pinmux API which is likely to be needed to support this.

@NemesisXB
Copy link

Almost 3 years later. Any progress or ETA on this?

@gmarull
Copy link
Member

gmarull commented Oct 29, 2021

Note: The pinctrl API supports dynamic pinctrl, but with some limitations. Details here: https://docs.zephyrproject.org/latest/guides/pinctrl/index.html#dynamic-pin-control

@carlescufi
Copy link
Member

carlescufi commented Nov 2, 2021

@NemesisXB as @gmarull pointed out, the new pinctrl API provides the ability to switch pins, but several things need to happen for this to be useful for implementations like CircuitPython:

  • SoC families need to be updated to expose an implementation of the pinctrl API. Tracked here
  • Drivers need to start using the new pinctrl API
  • Support for deinitializing devices needs to be added. Tracked here

@carlescufi
Copy link
Member

Closing as done, even though #40385 has not been addressed yet.

@carlescufi
Copy link
Member

@dhalbert @tannewt FYI #84394

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

10 participants