Skip to content

Commit

Permalink
Enable GPIO Pin Interrupts (#1922)
Browse files Browse the repository at this point in the history
Add interrupt-related API calls to the LPC55 `gpio_driver`.

Also:
Fix app/gimletlet/app-mgmt.toml stack size which was found while
building all targets.

---

A task on an LPC55 can now configue and use GPIO interrupts.

app.toml example shows Pin Interrupt configuration:

[tasks.foo]
...
interrupts = { "pint.irq0" = "button-irq" }
...
task-slots = ["gpio_driver", ...]

[tasks.foo.config]
pins = [
{ name="BUTTON', pin={ port=1, pin=9}, alt=0, pint=0, direction="input",
opendrain="normal" }
]

---------

Co-authored-by: Eliza Weisman <[email protected]>
  • Loading branch information
lzrd and hawkw authored Feb 10, 2025
1 parent 729ef60 commit add2d0a
Show file tree
Hide file tree
Showing 18 changed files with 571 additions and 62 deletions.
5 changes: 5 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion app/lpc55xpresso/app-sprot.toml
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ task-slots = ["jefe"]
name = "drv-lpc55-gpio"
priority = 3
max-sizes = {flash = 8192, ram = 2048}
uses = ["gpio", "iocon"]
uses = ["gpio", "iocon", "pint", "inputmux"]
start = true
stacksize = 1000
task-slots = ["syscon_driver"]
Expand Down
2 changes: 1 addition & 1 deletion app/lpc55xpresso/app.toml
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ task-slots = ["jefe"]
name = "drv-lpc55-gpio"
priority = 3
max-sizes = {flash = 8192, ram = 2048}
uses = ["gpio", "iocon"]
uses = ["gpio", "iocon", "pint", "inputmux"]
start = true
stacksize = 1000
task-slots = ["syscon_driver"]
Expand Down
2 changes: 1 addition & 1 deletion app/oxide-rot-1/app-dev.toml
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ task-slots = ["jefe"]
name = "drv-lpc55-gpio"
priority = 3
max-sizes = {flash = 8192, ram = 2048}
uses = ["gpio", "iocon"]
uses = ["gpio", "iocon", "pint", "inputmux"]
start = true
task-slots = ["syscon_driver"]

Expand Down
2 changes: 1 addition & 1 deletion app/oxide-rot-1/app.toml
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ task-slots = ["jefe"]
name = "drv-lpc55-gpio"
priority = 3
max-sizes = {flash = 8192, ram = 2048}
uses = ["gpio", "iocon"]
uses = ["gpio", "iocon", "pint", "inputmux"]
start = true
task-slots = ["syscon_driver"]

Expand Down
4 changes: 2 additions & 2 deletions app/rot-carrier/app.toml
Original file line number Diff line number Diff line change
Expand Up @@ -67,15 +67,15 @@ task-slots = ["jefe"]
name = "drv-lpc55-gpio"
priority = 3
max-sizes = {flash = 8192, ram = 2048}
uses = ["gpio", "iocon"]
uses = ["gpio", "iocon", "pint", "inputmux"]
start = true
task-slots = ["syscon_driver"]

[tasks.user_leds]
name = "drv-user-leds"
features = ["lpc55"]
priority = 6
max-sizes = {flash = 8192, ram = 1056}
max-sizes = {flash = 8192, ram = 1120}
start = true
task-slots = ["gpio_driver"]
notifications = ["timer"]
Expand Down
1 change: 1 addition & 0 deletions build/lpc55pins/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ serde = { workspace = true }
syn = { workspace = true }

build-util = { path = "../util" }
call_rustfmt = { path = "../call_rustfmt"}

[lints]
workspace = true
77 changes: 77 additions & 0 deletions build/lpc55pins/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
# LPC55 GPIO Pin configuration in `app.toml` files

Configuring LPC55 GPIO pins may require referencing the NXP UM11126 document and board schematics.

Some tasks, like `user_leds`, program the GPIO pins directly, but most
will use the API defined in `idl/lpc55-pins.idl`.

Tasks that use GPIO pins need to include a `[tasks.TASKNAME.config]` section.

For example, a `button` task in `app/lpc55xpresso/app-button.toml`
might use the red, green, and blue LEDs on the `LPCxpresso` board as well as the
user button. The LEDs would be attached to GPIOs configured as outputs while
the "user" button would be configured as an input with an interrupt.

The LPC55 GPIO Pin INTerrupts index is selected from the range `pint.irq0`
to `pint.irq7` and cannot be used more than once in the `app.toml`.
The task stanza's `interrupts` and the pin configuration information need to agree on the `PINT` index.

```toml
[tasks.button]
# ...
interrupts = { "pint.irq0" = "button-irq" }
# ...

[tasks.button.config]
pins = [
{ name = "BUTTON", pin = { port = 1, pin = 9}, alt = 0, pint = 0, direction = "input", opendrain = "normal" },
{ name = "RED_LED", pin = { port = 1, pin = 6}, alt = 0, direction = "output", value = true },
{ name = "GREEN_LED", pin = { port = 1, pin = 7}, alt = 0, direction = "output", value = true },
{ name = "BLUE_LED", pin = { port = 1, pin = 4}, alt = 0, direction = "output", value = true },
]
```

A notification bit corresponding to the above "button-irq" will be
generated and called `notification::BUTTON_IRQ_MASK`.

The task's `build.rs` generates GPIO support code:
```rust
let task_config = build_util::task_config::<TaskConfig>()?;
build_lpc55pins::codegen(task_config.pins)`
```

The `port`, `pin`, `alt`, `mode`, `slew`, `invert`, `digimode`, and
`opendrain` tags all represent values found in UM111126.

## Named pins

The `name` field is optional. Giving pins symbolic names in the `app.toml`
can make a task a bit more portable. Naming a pin will generate a
`pub const NAME: Pin` definition that can be used with the `lpc55-pins`
API instead referring to it as `Pin::PIOx_y`.

Naming a pin also generates a separate `setup_pinname` function that
is called by `setup_pins` unless `setup = false` is part of the pin
configuration.

Using `setup = false` and `name` allows there to be multiple
configurations for the same physical pin that can be used at different
times.

As an example, the action taken on detection of a change on an input
signal can be to change that pin to an output and drive the pin. When
the signal has been handled, the pin can be reverted to an input until
the next event.

```toml
[tasks.example.config]
pins = [
{ name = "SP_RESET_IN", pin = { port = 0, pin = 13 }, alt = 0, direction = "input", pint = 0 },
{ name = "SP_RESET_OUT", pin = { port = 0, pin = 13 }, alt = 0, direction = "output", setup = false },
]
```

In the above case, `setup_pins()` will call `setup_reset_in()`
but not `setup_reset_out()`. The notification handler for
`notification::SP_RESET_IRQ_MASK` will call `setup_reset_out()` and then
`setup_reset_in()` before returning.
Loading

0 comments on commit add2d0a

Please sign in to comment.