Skip to content

Commit de5c3ca

Browse files
committed
INCOMPLETE: use "friendly" names for GPIO ports
Starting with Zephyr 3.2.0, the `label` property of DT nodes was made obsolete, which means that is no longer possible to write: ``` pin = Pin(("GPIO_1", 21), Pin.IN) ``` Instead, a much less friendly format must be used: ``` pin = Pin(("gpio@842500", 21), Pin.IN) ``` This commit adds a new script (`gen_dt_node_names.py`) which is heavily based on [this script](https://github.com/zephyrproject-rtos/zephyr/blob/main/scripts/dts/gen_dts_cmake.py) and attempts to generate and map friendly names for DT nodes. For example, a node defined like this: ``` gpio0: gpio@842500 { ... } ``` will generate a mapping like this: ``` struct dt_node_name_map { const char *const gen_name; const char *const actual_name; }; static const struct dt_node_name_map dt_node_map[] = { {"GPIO_0", "gpio@842500"} ... } ``` The code then checks this mapping if the node name supplied by the user does not exist and uses the actual DT name instead.
1 parent 0c4f14e commit de5c3ca

File tree

3 files changed

+83
-0
lines changed

3 files changed

+83
-0
lines changed

ports/zephyr/CMakeLists.txt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
2828
project(micropython)
2929

3030
set(MICROPY_PORT_DIR ${CMAKE_CURRENT_SOURCE_DIR})
31+
set(MICROPY_BUILD_DIR ${MICROPY_PORT_DIR}/build)
3132
set(MICROPY_DIR ${MICROPY_PORT_DIR}/../..)
3233
set(MICROPY_TARGET micropython)
3334

@@ -74,7 +75,12 @@ set(MICROPY_SOURCE_LIB
7475
)
7576
list(TRANSFORM MICROPY_SOURCE_LIB PREPEND ${MICROPY_DIR}/lib/)
7677

78+
add_custom_command(OUTPUT ${MICROPY_BUILD_DIR}/gen_dt_node_names.h
79+
DEPENDS ${MICROPY_BUILD_DIR}/zephyr/edt.pickle ${MICROPY_PORT_DIR}/gen_dt_node_names.py
80+
COMMAND ${Python3_EXECUTABLE} ${MICROPY_PORT_DIR}/gen_dt_node_names.py -i ${MICROPY_BUILD_DIR}/zephyr/edt.pickle -o ${MICROPY_BUILD_DIR}/gen_dt_node_names.h)
81+
7782
set(MICROPY_SOURCE_QSTR
83+
${MICROPY_BUILD_DIR}/gen_dt_node_names.h
7884
${MICROPY_SOURCE_PY}
7985
${MICROPY_SOURCE_EXTMOD}
8086
${MICROPY_SOURCE_SHARED}

ports/zephyr/gen_dt_node_names.py

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
#!/usr/bin/env python3
2+
3+
import argparse
4+
import os
5+
import sys
6+
import pickle
7+
import re
8+
9+
# This is needed by the "pickle.load" call below
10+
zephyr_base = os.environ["ZEPHYR_BASE"]
11+
sys.path.insert(0, os.path.join(zephyr_base, "scripts", "dts", "python-devicetree", "src"))
12+
13+
# The prefixes to look for in the device tree
14+
prefixes = ("gpio", "spi", "i2c", "uart")
15+
16+
# Prefix for the generated header
17+
header_prefix = """#ifndef MICROPY_INCLUDED_ZEPHYR_GEN_DT_NODE_NAMES_H
18+
#define MICROPY_INCLUDED_ZEPHYR_GEN_DT_NODE_NAMES_H
19+
20+
struct dt_node_name_map {
21+
const char *const gen_name;
22+
const char *const actual_name;
23+
};
24+
25+
static const struct dt_node_name_map dt_node_map[] = {
26+
"""
27+
# Suffix for the generated header
28+
header_sufix = """};
29+
30+
#endif
31+
"""
32+
33+
def main():
34+
parser = argparse.ArgumentParser(description="Generate friendly names for Zephyr DT nodess")
35+
parser.add_argument("-i", "--input", required=True, help="path to edt.pickle")
36+
parser.add_argument("-o", "--output", required=True, help="path to the output file")
37+
args = parser.parse_args()
38+
39+
# Load the representation of the device tree generated by Zephyr
40+
with open(args.input, 'rb') as f:
41+
edt = pickle.load(f)
42+
43+
# Create regular expressions for all prefix that we need to check
44+
all_re = re.compile(fr'^({"|".join(prefixes)})(\d+)$')
45+
46+
# Look in the device tree for all nodes with labels
47+
name_map = {}
48+
for n in edt.nodes:
49+
if n.status == "okay": # consider only nodes that are enabled
50+
# Check prefixes for all labels
51+
for l in n.labels:
52+
found = all_re.match(l)
53+
if found != None:
54+
# Transform name (from "gpio0" to "GPIO_0" and so on)
55+
new_name = found.group(1).upper() + "_" + found.group(2)
56+
name_map[new_name] = n.name
57+
break
58+
59+
# Write data to output file
60+
with open(args.output, "wt") as f:
61+
f.write(header_prefix)
62+
for n in name_map:
63+
f.write(f' {{"{n}", "{name_map[n]}"}},\n')
64+
f.write(" {NULL, NULL}\n")
65+
f.write(header_sufix)
66+
67+
if __name__ == "__main__":
68+
main()

ports/zephyr/machine_pin.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
#include "py/mphal.h"
3838
#include "shared/runtime/mpirq.h"
3939
#include "modmachine.h"
40+
#include "gen_dt_node_names.h"
4041

4142
#if MICROPY_PY_MACHINE
4243

@@ -133,6 +134,14 @@ mp_obj_t mp_pin_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw,
133134
const char *drv_name = mp_obj_str_get_str(items[0]);
134135
int wanted_pin = mp_obj_get_int(items[1]);
135136
const struct device *wanted_port = device_get_binding(drv_name);
137+
if (!wanted_port) {
138+
for (const struct dt_node_name_map *m = &dt_node_map[0]; m->gen_name != NULL; m ++) {
139+
if (!strcmp(m->gen_name, drv_name)) {
140+
wanted_port = device_get_binding(m->actual_name);
141+
break;
142+
}
143+
}
144+
}
136145
if (!wanted_port) {
137146
mp_raise_ValueError(MP_ERROR_TEXT("invalid port"));
138147
}

0 commit comments

Comments
 (0)