-
Notifications
You must be signed in to change notification settings - Fork 22
Device Tree Support #15
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
Changes from all commits
3bca48e
0b7f377
1139afb
85bfbde
0104c33
09b58d1
206bfe7
129332a
a0ae726
70ed3b7
ed06d97
ba60ed2
f6b5e89
b1fe3ea
2dce5d5
08ee474
bf03633
ec45675
cf0d2b9
64f0eb6
d10c418
949b03e
19ad114
37e5502
64864c6
1b02946
89958c3
f655285
6943226
fe2cc40
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
# Description of how to augment the devicetree for Rust. | ||
# | ||
# Each entry describes an augmentation that will be added to matching nodes in the device tree. | ||
# The full syntax is described (indirectly) in `zephyr-build/src/devicetree/config.rs`. | ||
|
||
# Gpio controllers match for every node that has a `gpio-controller` property. This is one of the | ||
# few instances were we can actually just match on a property. | ||
- name: gpio-controller | ||
rules: | ||
- type: has_prop | ||
value: gpio-controller | ||
actions: | ||
- type: instance | ||
value: | ||
raw: | ||
type: myself | ||
device: crate::device::gpio::Gpio | ||
|
||
# The gpio-leds node will have #children nodes describing each led. We'll match on the parent | ||
# having this compatible property. The nodes themselves are built out of the properties associated | ||
# with each gpio. | ||
- name: gpio-leds | ||
rules: | ||
- type: compatible | ||
value: | ||
names: | ||
- gpio-leds | ||
level: 1 | ||
actions: | ||
- type: instance | ||
value: | ||
raw: | ||
type: phandle | ||
value: gpios | ||
device: crate::device::gpio::GpioPin | ||
|
||
# Flash controllers don't have any particular property to identify them, so we need a list of | ||
# compatible values that should match. | ||
- name: flash-controller | ||
rules: | ||
- type: compatible | ||
value: | ||
names: | ||
- "nordic,nrf52-flash-controller" | ||
- "nordic,nrf51-flash-controller" | ||
- "raspberrypi,pico-flash-controller" | ||
level: 0 | ||
actions: | ||
- type: instance | ||
value: | ||
raw: | ||
type: myself | ||
device: crate::device::flash::FlashController | ||
|
||
# Flash partitions exist as children of a node compatible with "soc-nv-flash" that itself is a child | ||
# of the controller itself. | ||
# TODO: Get the write and erase property from the DT if present. | ||
- name: flash-partition | ||
rules: | ||
- type: compatible | ||
value: | ||
names: | ||
- "fixed-partitions" | ||
level: 1 | ||
- type: compatible | ||
value: | ||
names: | ||
- "soc-nv-flash" | ||
level: 2 | ||
actions: | ||
- type: instance | ||
value: | ||
raw: | ||
type: parent | ||
value: | ||
level: 3 | ||
args: | ||
- type: reg | ||
device: "crate::device::flash::FlashPartition" | ||
|
||
# Generate a pseudo node that matches all of the labels across the tree with their nodes. | ||
- name: labels | ||
rules: | ||
- type: root | ||
actions: | ||
- type: labels | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,3 @@ | ||
-p mps2/an385 | ||
-p mps2/an521/cpu0 | ||
-p qemu_cortex_m0 | ||
-p qemu_cortex_m3 | ||
-p qemu_riscv32 | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
# SPDX-License-Identifier: Apache-2.0 OR MIT | ||
|
||
cmake_minimum_required(VERSION 3.20.0) | ||
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) | ||
project(blinky) | ||
|
||
rust_cargo_application() |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
# Copyright (c) 2024 Linaro LTD | ||
# SPDX-License-Identifier: Apache-2.0 | ||
|
||
[package] | ||
# This must be rustapp for now. | ||
name = "rustapp" | ||
version = "0.1.0" | ||
edition = "2021" | ||
description = "Blink an LED forever using the GPIO API" | ||
license = "Apache-2.0 OR MIT" | ||
|
||
[lib] | ||
crate-type = ["staticlib"] | ||
|
||
[dependencies] | ||
zephyr = "0.1.0" | ||
log = "0.4.22" | ||
|
||
[build-dependencies] | ||
zephyr-build = "0.1.0" |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,97 @@ | ||
.. zephyr:code-sample:: blinky | ||
:name: Blinky | ||
:relevant-api: gpio_interface | ||
|
||
Blink an LED forever using the GPIO API. | ||
|
||
Overview | ||
******** | ||
|
||
The Blinky sample blinks an LED forever using the :ref:`GPIO API <gpio_api>`. | ||
|
||
The source code shows how to: | ||
|
||
#. Get a pin specification from the :ref:`devicetree <dt-guide>` as a | ||
:c:struct:`gpio_dt_spec` | ||
#. Configure the GPIO pin as an output | ||
#. Toggle the pin forever | ||
|
||
See :zephyr:code-sample:`pwm-blinky` for a similar sample that uses the PWM API instead. | ||
|
||
.. _blinky-sample-requirements: | ||
|
||
Requirements | ||
************ | ||
|
||
Your board must: | ||
|
||
#. Have an LED connected via a GPIO pin (these are called "User LEDs" on many of | ||
Zephyr's :ref:`boards`). | ||
#. Have the LED configured using the ``led0`` devicetree alias. | ||
|
||
Building and Running | ||
******************** | ||
|
||
Build and flash Blinky as follows, changing ``reel_board`` for your board: | ||
|
||
.. zephyr-app-commands:: | ||
:zephyr-app: samples/basic/blinky | ||
:board: reel_board | ||
:goals: build flash | ||
:compact: | ||
|
||
After flashing, the LED starts to blink and messages with the current LED state | ||
are printed on the console. If a runtime error occurs, the sample exits without | ||
printing to the console. | ||
|
||
Build errors | ||
************ | ||
|
||
You will see a build error at the source code line defining the ``struct | ||
gpio_dt_spec led`` variable if you try to build Blinky for an unsupported | ||
board. | ||
|
||
On GCC-based toolchains, the error looks like this: | ||
|
||
.. code-block:: none | ||
|
||
error: '__device_dts_ord_DT_N_ALIAS_led_P_gpios_IDX_0_PH_ORD' undeclared here (not in a function) | ||
|
||
Adding board support | ||
******************** | ||
|
||
To add support for your board, add something like this to your devicetree: | ||
|
||
.. code-block:: DTS | ||
|
||
/ { | ||
aliases { | ||
led0 = &myled0; | ||
}; | ||
|
||
leds { | ||
compatible = "gpio-leds"; | ||
myled0: led_0 { | ||
gpios = <&gpio0 13 GPIO_ACTIVE_LOW>; | ||
}; | ||
}; | ||
}; | ||
Comment on lines
+67
to
+78
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There is mixed tab and spaces indentation here, I assume by accident There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hmm, that is rather weird, and I'm not sure what the right thing to do is. In Zephyr, DTS files are indented with tabs, and this is a snippet of that. I think this will cause the tabs to show up in the output. RTS is a little weird about it. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. github's render looks to have correct spacing. |
||
|
||
The above sets your board's ``led0`` alias to use pin 13 on GPIO controller | ||
``gpio0``. The pin flags :c:macro:`GPIO_ACTIVE_HIGH` mean the LED is on when | ||
the pin is set to its high state, and off when the pin is in its low state. | ||
|
||
Tips: | ||
|
||
- See :dtcompatible:`gpio-leds` for more information on defining GPIO-based LEDs | ||
in devicetree. | ||
|
||
- If you're not sure what to do, check the devicetrees for supported boards which | ||
use the same SoC as your target. See :ref:`get-devicetree-outputs` for details. | ||
|
||
- See :zephyr_file:`include/zephyr/dt-bindings/gpio/gpio.h` for the flags you can use | ||
in devicetree. | ||
|
||
- If the LED is built in to your board hardware, the alias should be defined in | ||
your :ref:`BOARD.dts file <devicetree-in-out-files>`. Otherwise, you can | ||
define one in a :ref:`devicetree overlay <set-devicetree-overlays>`. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
fn main() { | ||
// This call will make make config entries available in the code for every device tree node, to | ||
// allow conditional compilation based on whether it is present in the device tree. | ||
// For example, it will be possible to have: | ||
// ```rust | ||
// #[cfg(dt = "aliases::led0")] | ||
// ``` | ||
zephyr_build::dt_cfgs(); | ||
d3zd3z marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
CONFIG_GPIO=y | ||
|
||
CONFIG_RUST=y | ||
CONFIG_RUST_ALLOC=y | ||
|
||
CONFIG_DEBUG=y | ||
CONFIG_MAIN_STACK_SIZE=8192 | ||
|
||
# Verify that userspace builds work. | ||
# CONFIG_USERSPACE=y |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
# See doc/develop/test/twister.rst for what is here. | ||
sample: | ||
d3zd3z marked this conversation as resolved.
Show resolved
Hide resolved
|
||
name: Blinky Sample | ||
tests: | ||
sample.basic.blinky: | ||
tags: | ||
- LED | ||
- gpio | ||
filter: dt_enabled_alias_with_parent_compat("led0", "gpio-leds") | ||
depends_on: gpio | ||
harness: led | ||
integration_platforms: | ||
- frdm_k64f |
Original file line number | Diff line number | Diff line change | ||||||
---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,52 @@ | ||||||||
// Copyright (c) 2024 Linaro LTD | ||||||||
// SPDX-License-Identifier: Apache-2.0 | ||||||||
|
||||||||
#![no_std] | ||||||||
|
||||||||
// Sigh. The check config system requires that the compiler be told what possible config values | ||||||||
// there might be. This is completely impossible with both Kconfig and the DT configs, since the | ||||||||
// whole point is that we likely need to check for configs that aren't otherwise present in the | ||||||||
// build. So, this is just always necessary. | ||||||||
#![allow(unexpected_cfgs)] | ||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You can put the expected There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This isn't possible, as we don't know the set of possible cfgs. This is actually kind of something broken about the way Rust is doing it. Other than scanning the entire Zephyr Kconfig tree for possible configs, we have no way of knowing what things the user's code might want to be able to config on. Now, admittedly an app could add their own, and maybe we should do that? Is that what you are suggesting? |
||||||||
|
||||||||
use log::warn; | ||||||||
|
||||||||
use zephyr::raw::GPIO_OUTPUT_ACTIVE; | ||||||||
use zephyr::time::{ Duration, sleep }; | ||||||||
|
||||||||
#[no_mangle] | ||||||||
extern "C" fn rust_main() { | ||||||||
unsafe { zephyr::set_logger().unwrap(); } | ||||||||
|
||||||||
warn!("Starting blinky"); | ||||||||
|
||||||||
do_blink(); | ||||||||
} | ||||||||
|
||||||||
#[cfg(dt = "aliases::led0")] | ||||||||
fn do_blink() { | ||||||||
warn!("Inside of blinky"); | ||||||||
|
||||||||
let mut led0 = zephyr::devicetree::aliases::led0::get_instance().unwrap(); | ||||||||
let mut gpio_token = unsafe { zephyr::device::gpio::GpioToken::get_instance().unwrap() }; | ||||||||
|
||||||||
if !led0.is_ready() { | ||||||||
warn!("LED is not ready"); | ||||||||
loop { | ||||||||
} | ||||||||
Comment on lines
+35
to
+36
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This should get fixed when I do a rustfmt cleanup. |
||||||||
} | ||||||||
|
||||||||
unsafe { led0.configure(&mut gpio_token, GPIO_OUTPUT_ACTIVE); } | ||||||||
let duration = Duration::millis_at_least(500); | ||||||||
loop { | ||||||||
unsafe { led0.toggle_pin(&mut gpio_token); } | ||||||||
sleep(duration); | ||||||||
} | ||||||||
} | ||||||||
|
||||||||
#[cfg(not(dt = "aliases::led0"))] | ||||||||
fn do_blink() { | ||||||||
warn!("No leds configured"); | ||||||||
loop { | ||||||||
} | ||||||||
Comment on lines
+50
to
+51
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'll let this get fixed when I do the big rustfmt/clippy fixes after this merges. |
||||||||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this the error rustc will spit out? I kinda doubt it...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well, the linker specifically. That's the lovely names in the generated C code that we reference in the
get_instance
.