Skip to content

Commit cb31c0a

Browse files
committed
esp32: Add support for board-named pins and the Pin.board dict.
This adds named-pins support to the esp32 port, following other ports. Since the name of esp32 CPU pins is just GPIOx, where x is an integer, the Pin.cpu dict is not supported and CPU pins are just retrieved via their existing integer "name" (the cost of adding Pin.cpu is about 800 bytes, mostly due to the additional qstrs). What this commit supports is the Pin.board dict and constructing a pin by names given by a board. These names are defined in a pins.csv file at the board level. If no such file exists then Pin.board exists but is empty. As part of this commit, pin and pin IRQ objects are optimised to reduce their size in flash (by removing their gpio_num_t entry). The net change in firmware size for this commit is about -132 bytes. Signed-off-by: Damien George <[email protected]>
1 parent 51c2d26 commit cb31c0a

File tree

5 files changed

+462
-369
lines changed

5 files changed

+462
-369
lines changed

ports/esp32/boards/make-pins.py

Lines changed: 185 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,185 @@
1+
#!/usr/bin/env python
2+
3+
import argparse
4+
import sys
5+
import csv
6+
import re
7+
8+
MAX_CPU_PINS = 49
9+
10+
11+
def parse_pin(name_str):
12+
"""Parses a string and returns a pin number."""
13+
if len(name_str) < 2:
14+
raise ValueError("Expecting pin name to be at least 2 characters.")
15+
if not name_str.startswith("GPIO"):
16+
raise ValueError("Expecting pin name to start with GPIO")
17+
return int(re.findall(r"\d+$", name_str)[0])
18+
19+
20+
class Pin:
21+
def __init__(self, pin):
22+
self.pin = pin
23+
self.is_board = False
24+
25+
def cpu_pin_name(self):
26+
return "GPIO{:d}".format(self.pin)
27+
28+
def is_board_pin(self):
29+
return self.is_board
30+
31+
def set_is_board_pin(self):
32+
self.is_board = True
33+
34+
35+
class NamedPin:
36+
def __init__(self, name, pin):
37+
self._name = name
38+
self._pin = pin
39+
40+
def pin(self):
41+
return self._pin
42+
43+
def name(self):
44+
return self._name
45+
46+
47+
class Pins:
48+
def __init__(self):
49+
self.cpu_pins = [] # list of NamedPin objects
50+
self.board_pins = [] # list of NamedPin objects
51+
52+
def find_pin(self, pin_name):
53+
for pin in self.cpu_pins:
54+
if pin.name() == pin_name:
55+
return pin.pin()
56+
57+
def create_pins(self):
58+
for pin_num in range(MAX_CPU_PINS):
59+
pin = Pin(pin_num)
60+
self.cpu_pins.append(NamedPin(pin.cpu_pin_name(), pin))
61+
62+
def parse_board_file(self, filename):
63+
with open(filename, "r") as csvfile:
64+
rows = csv.reader(csvfile)
65+
for row in rows:
66+
if len(row) == 0 or row[0].startswith("#"):
67+
# Skip empty lines, and lines starting with "#"
68+
continue
69+
if len(row) != 2:
70+
raise ValueError("Expecting two entries in a row")
71+
72+
cpu_pin_name = row[1]
73+
parse_pin(cpu_pin_name)
74+
pin = self.find_pin(cpu_pin_name)
75+
if not pin:
76+
raise ValueError("Unknown pin {}".format(cpu_pin_name))
77+
pin.set_is_board_pin()
78+
if row[0]: # Only add board pins that have a name
79+
self.board_pins.append(NamedPin(row[0], pin))
80+
81+
def print_table(self, label, named_pins, out_source):
82+
print("", file=out_source)
83+
print(
84+
"const machine_{}_obj_t machine_{}_obj_table[GPIO_NUM_MAX] = {{".format(label, label),
85+
file=out_source,
86+
)
87+
for pin in named_pins:
88+
print(" #if MICROPY_HW_ENABLE_{}".format(pin.name()), file=out_source)
89+
print(
90+
" [GPIO_NUM_{}] = {{ .base = {{ .type = &machine_{}_type }} }},".format(
91+
pin.pin().pin, label
92+
),
93+
file=out_source,
94+
)
95+
print(" #endif", file=out_source)
96+
print("};", file=out_source)
97+
98+
def print_named(self, label, named_pins, out_source):
99+
print("", file=out_source)
100+
print(
101+
"STATIC const mp_rom_map_elem_t machine_pin_{:s}_pins_locals_dict_table[] = {{".format(
102+
label
103+
),
104+
file=out_source,
105+
)
106+
for named_pin in named_pins:
107+
pin = named_pin.pin()
108+
print(
109+
" {{ MP_ROM_QSTR(MP_QSTR_{:s}), MP_ROM_PTR(&pin_{:s}) }},".format(
110+
named_pin.name(), pin.cpu_pin_name()
111+
),
112+
file=out_source,
113+
)
114+
115+
print("};", file=out_source)
116+
print(
117+
"MP_DEFINE_CONST_DICT(machine_pin_{:s}_pins_locals_dict, machine_pin_{:s}_pins_locals_dict_table);".format(
118+
label, label
119+
),
120+
file=out_source,
121+
)
122+
123+
def print_tables(self, out_source):
124+
self.print_table("pin", self.cpu_pins, out_source)
125+
self.print_table("pin_irq", self.cpu_pins, out_source)
126+
self.print_named("board", self.board_pins, out_source)
127+
128+
def print_header(self, out_header):
129+
# Provide #defines for each cpu pin.
130+
for named_pin in self.cpu_pins:
131+
pin = named_pin.pin()
132+
n = pin.cpu_pin_name()
133+
print("#if MICROPY_HW_ENABLE_{}".format(n), file=out_header)
134+
print(
135+
"#define pin_{:s} (machine_pin_obj_table[{}])".format(n, pin.pin),
136+
file=out_header,
137+
)
138+
print("#endif", file=out_header)
139+
140+
# Provide #define's mapping board to cpu name.
141+
for named_pin in self.board_pins:
142+
if named_pin.pin().is_board_pin():
143+
print(
144+
"#define pin_{:s} pin_{:s}".format(
145+
named_pin.name(), named_pin.pin().cpu_pin_name()
146+
),
147+
file=out_header,
148+
)
149+
150+
151+
def main():
152+
parser = argparse.ArgumentParser(description="Generate board specific pin file")
153+
parser.add_argument("--board-csv")
154+
parser.add_argument("--prefix")
155+
parser.add_argument("--output-source")
156+
parser.add_argument("--output-header")
157+
args = parser.parse_args(sys.argv[1:])
158+
159+
pins = Pins()
160+
pins.create_pins()
161+
162+
if args.board_csv:
163+
pins.parse_board_file(args.board_csv)
164+
165+
with open(args.output_source, "w") as out_source:
166+
print("// This file was automatically generated by make-pins.py", file=out_source)
167+
print("//", file=out_source)
168+
169+
if args.board_csv:
170+
print("// --board-csv {:s}".format(args.board_csv), file=out_source)
171+
172+
if args.prefix:
173+
print("// --prefix {:s}".format(args.prefix), file=out_source)
174+
print("", file=out_source)
175+
with open(args.prefix, "r") as prefix_file:
176+
print(prefix_file.read(), end="", file=out_source)
177+
178+
pins.print_tables(out_source)
179+
180+
with open(args.output_header, "w") as out_header:
181+
pins.print_header(out_header)
182+
183+
184+
if __name__ == "__main__":
185+
main()

ports/esp32/boards/pins_prefix.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
#include "py/obj.h"
2+
#include "machine_pin.h"
3+
#include "modmachine.h"
4+
#include "genhdr/pins.h"

ports/esp32/esp32_common.cmake

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ list(APPEND MICROPY_SOURCE_PORT
9090
modespnow.c
9191
)
9292
list(TRANSFORM MICROPY_SOURCE_PORT PREPEND ${MICROPY_PORT_DIR}/)
93+
list(APPEND MICROPY_SOURCE_PORT ${CMAKE_BINARY_DIR}/pins.c)
9394

9495
list(APPEND MICROPY_SOURCE_QSTR
9596
${MICROPY_SOURCE_PY}
@@ -198,3 +199,30 @@ endforeach()
198199

199200
# Include the main MicroPython cmake rules.
200201
include(${MICROPY_DIR}/py/mkrules.cmake)
202+
203+
# Generate source files for named pins (requires mkrules.cmake for MICROPY_GENHDR_DIR).
204+
205+
set(GEN_PINS_PREFIX "${MICROPY_PORT_DIR}/boards/pins_prefix.c")
206+
set(GEN_PINS_MKPINS "${MICROPY_PORT_DIR}/boards/make-pins.py")
207+
set(GEN_PINS_SRC "${CMAKE_BINARY_DIR}/pins.c")
208+
set(GEN_PINS_HDR "${MICROPY_GENHDR_DIR}/pins.h")
209+
210+
if(EXISTS "${MICROPY_BOARD_DIR}/pins.csv")
211+
set(GEN_PINS_BOARD_CSV "${MICROPY_BOARD_DIR}/pins.csv")
212+
set(GEN_PINS_BOARD_CSV_ARG --board-csv "${GEN_PINS_BOARD_CSV}")
213+
endif()
214+
215+
target_sources(${MICROPY_TARGET} PRIVATE ${GEN_PINS_HDR})
216+
217+
add_custom_command(
218+
OUTPUT ${GEN_PINS_SRC} ${GEN_PINS_HDR}
219+
COMMAND ${Python3_EXECUTABLE} ${GEN_PINS_MKPINS} ${GEN_PINS_BOARD_CSV_ARG}
220+
--prefix ${GEN_PINS_PREFIX} --output-source ${GEN_PINS_SRC} --output-header ${GEN_PINS_HDR}
221+
DEPENDS
222+
${MICROPY_MPVERSION}
223+
${GEN_PINS_MKPINS}
224+
${GEN_PINS_BOARD_CSV}
225+
${GEN_PINS_PREFIX}
226+
VERBATIM
227+
COMMAND_EXPAND_LISTS
228+
)

0 commit comments

Comments
 (0)