circuitpython/ports/mimxrt/boards/make-pins.py

382 lines
13 KiB
Python
Raw Normal View History

#!/usr/bin/env python
"""Creates the pin file for the MIMXRT10xx."""
from __future__ import print_function
import argparse
import sys
import csv
import re
SUPPORTED_AFS = {"GPIO", "USDHC", "SEMC"}
MAX_AF = 10 # AF0 .. AF9
ADC_COL = 11
regexes = [
r"IOMUXC_(?P<pin>GPIO_SD_B\d_\d\d)_(?P<function>\w+) (?P<muxRegister>\w+), (?P<muxMode>\w+), (?P<inputRegister>\w+), (?P<inputDaisy>\w+), (?P<configRegister>\w+)",
r"IOMUXC_(?P<pin>GPIO_AD_B\d_\d\d)_(?P<function>\w+) (?P<muxRegister>\w+), (?P<muxMode>\w+), (?P<inputRegister>\w+), (?P<inputDaisy>\w+), (?P<configRegister>\w+)",
r"IOMUXC_(?P<pin>GPIO_EMC_\d\d)_(?P<function>\w+) (?P<muxRegister>\w+), (?P<muxMode>\w+), (?P<inputRegister>\w+), (?P<inputDaisy>\w+), (?P<configRegister>\w+)",
r"IOMUXC_(?P<pin>GPIO_B\d_\d\d)_(?P<function>\w+) (?P<muxRegister>\w+), (?P<muxMode>\w+), (?P<inputRegister>\w+), (?P<inputDaisy>\w+), (?P<configRegister>\w+)",
r"IOMUXC_(?P<pin>GPIO_\d\d)_(?P<function>\w+) (?P<muxRegister>\w+), (?P<muxMode>\w+), (?P<inputRegister>\w+), (?P<inputDaisy>\w+), (?P<configRegister>\w+)",
r"IOMUXC_(?P<pin>GPIO_AD_\d\d)_(?P<function>\w+) (?P<muxRegister>\w+), (?P<muxMode>\w+), (?P<inputRegister>\w+), (?P<inputDaisy>\w+), (?P<configRegister>\w+)",
r"IOMUXC_(?P<pin>GPIO_SD_\d\d)_(?P<function>\w+) (?P<muxRegister>\w+), (?P<muxMode>\w+), (?P<inputRegister>\w+), (?P<inputDaisy>\w+), (?P<configRegister>\w+)",
]
def parse_pad(pad_str):
"""Parses a string and returns a (port, gpio_bit) tuple."""
if len(pad_str) < 4:
raise ValueError("Expecting pad name to be at least 4 characters")
if pad_str[:4] != "GPIO":
raise ValueError("Expecting pad name to start with GPIO")
return pad_str
def af_supported(af_str):
for supported_af in SUPPORTED_AFS:
if af_str.startswith(supported_af):
return True
else:
return False
class Pin(object):
"""Holds the information associated with a pin."""
def __init__(self, pad, gpio, pin, idx=0):
self.idx = idx
self.name = pad
self.pad = pad
self.gpio = gpio
self.pin = pin
self.alt_fn = []
self.adc_fns = []
self.board_pin = False
def set_is_board_pin(self):
self.board_pin = True
def is_board_pin(self):
return self.board_pin
def parse_adc(self, adc_str):
adc_regex = r"ADC(?P<instance>\d*)_IN(?P<channel>\d*)"
matches = re.finditer(adc_regex, adc_str, re.MULTILINE)
for match in matches:
self.adc_fns.append(
AdcFunction(instance=match.group("instance"), channel=match.group("channel"))
)
def parse_af(self, af_idx, af_strs_in):
pass
def add_af(self, af):
self.alt_fn.append(af)
def print_pin_af(self):
if self.alt_fn:
print(
"static const machine_pin_af_obj_t pin_{0}_af[{1}] = {{".format(
self.name, len(self.alt_fn)
)
)
for af in self.alt_fn:
af.print()
print("};")
else:
raise ValueError("Pin '{}' has no alternative functions".format(self.name))
def print_pin_adc(self):
if self.adc_fns:
print(
"static const machine_pin_adc_obj_t pin_{0}_adc[{1}] = {{".format(
self.name, len(self.adc_fns)
)
)
for adc_fn in self.adc_fns:
adc_fn.print()
print("};")
def print(self):
if self.alt_fn:
self.print_pin_af()
self.print_pin_adc()
if self.adc_fns:
print(
"const machine_pin_obj_t pin_{0} = PIN({0}, {1}, {2}, pin_{0}_af, {3}, pin_{0}_adc);\n".format(
self.name, self.gpio, int(self.pin), len(self.adc_fns)
)
)
else:
print(
"const machine_pin_obj_t pin_{0} = PIN({0}, {1}, {2}, pin_{0}_af, {3}, NULL);\n".format(
self.name, self.gpio, int(self.pin), len(self.adc_fns)
)
)
else:
raise ValueError("Pin '{}' has no alternative functions".format(self.name))
def print_header(self, hdr_file):
pass
class AdcFunction(object):
"""Holds the information associated with a pins ADC function."""
def __init__(self, instance, channel):
self.instance = instance
self.channel = channel
def print(self):
"""Prints the C representation of this AF."""
print(f" PIN_ADC(ADC{self.instance}, {self.channel}),")
class AlternateFunction(object):
"""Holds the information associated with a pins alternate function."""
def __init__(self, idx, input_reg, input_daisy, af_str):
self.idx = idx
self.af_str = af_str
self.input_reg = input_reg
self.input_daisy = input_daisy
self.instance = self.af_str.split("_")[0]
def print(self):
"""Prints the C representation of this AF."""
print(
" PIN_AF({0}, PIN_AF_MODE_ALT{1}, {2}, {3}, {4}, {5}),".format(
self.af_str, self.idx, self.input_daisy, self.instance, self.input_reg, "0x10B0U"
)
)
class NamedPin(object):
def __init__(self, name, pad, idx):
self.name = name
self.pad = pad
self.idx = idx
class Pins(object):
def __init__(self):
self.cpu_pins = []
self.board_pins = []
def find_pin_by_num(self, pin_num):
for pin in self.cpu_pins:
if pin.pin_num == pin_num:
return pin
def find_pin_by_name(self, pad):
for pin in self.cpu_pins:
if pin.pad == pad:
return pin
def parse_board_file(self, filename):
with open(filename, "r") as csvfile:
rows = csv.reader(csvfile)
for row in rows:
if len(row) == 0 or row[0].startswith("#"):
# Skip empty lines, and lines starting with "#"
continue
if len(row) != 2:
raise ValueError("Expecting two entries in a row")
pin = self.find_pin_by_name(row[1])
if pin and row[0]: # Only add board pins that have a name
self.board_pins.append(NamedPin(row[0], pin.pad, pin.idx))
def parse_af_file(self, filename, iomux_filename, pad_col, af_start_col):
af_end_col = af_start_col + MAX_AF
iomux_pin_config = dict()
with open(iomux_filename, "r") as ipt:
input_str = ipt.read()
for regex in regexes:
matches = re.finditer(regex, input_str, re.MULTILINE)
for match in matches:
if match.group("pin") not in iomux_pin_config:
iomux_pin_config[match.group("pin")] = {
int((match.groupdict()["muxMode"].strip("U")), 16): match.groupdict()
}
else:
iomux_pin_config[match.group("pin")][
int((match.groupdict()["muxMode"].strip("U")), 16)
] = match.groupdict()
with open(filename, "r") as csvfile:
rows = csv.reader(csvfile)
header = next(rows)
for idx, row in enumerate(rows):
pad = row[pad_col]
gpio, pin = row[6].split("_")
pin_number = pin.lstrip("IO")
pin = Pin(pad, gpio, pin_number, idx=idx)
# Parse alternate functions
af_idx = 0
for af_idx, af in enumerate(row[af_start_col:af_end_col]):
if af and af_supported(af):
pin.add_af(
AlternateFunction(
af_idx,
iomux_pin_config[pin.name][af_idx]["inputRegister"].strip("U"),
int(
iomux_pin_config[pin.name][af_idx]["inputDaisy"].strip("U"), 16
),
af,
)
)
pin.parse_adc(row[ADC_COL])
self.cpu_pins.append(pin)
@staticmethod
def print_named(label, pins):
print("")
print(
"STATIC const mp_rom_map_elem_t pin_{:s}_pins_locals_dict_table[] = {{".format(label)
)
for pin in pins:
print(
" {{ MP_ROM_QSTR(MP_QSTR_{}), MP_ROM_PTR(&pin_{}) }},".format(pin.name, pin.pad)
)
print("};")
print(
"MP_DEFINE_CONST_DICT(machine_pin_{:s}_pins_locals_dict, pin_{:s}_pins_locals_dict_table);".format(
label, label
)
)
def print(self):
# Print Pin Object declarations
for pin in self.cpu_pins:
pin.print()
print("")
print("const machine_pin_obj_t* machine_pin_board_pins [] = {")
for pin in self.board_pins:
print(" &pin_{},".format(pin.pad))
print("};")
print("const uint32_t num_board_pins = {:d};".format(len(self.board_pins)))
# Print Pin mapping dictionaries
self.print_named("cpu", self.cpu_pins)
self.print_named("board", self.board_pins)
print("")
def print_header(self, hdr_filename):
with open(hdr_filename, "w") as hdr_file:
for pin in self.cpu_pins:
hdr_file.write("extern const machine_pin_obj_t pin_{};\n".format(pin.name))
hdr_file.write("extern const machine_pin_obj_t* machine_pin_board_pins[];\n")
hdr_file.write("extern const uint32_t num_board_pins;\n")
hdr_file.write("extern const mp_obj_dict_t machine_pin_cpu_pins_locals_dict;\n")
hdr_file.write("extern const mp_obj_dict_t machine_pin_board_pins_locals_dict;\n")
hdr_file.write("\n// Defines\n")
usdhc_instance_factory(self.cpu_pins, hdr_file)
def usdhc_instance_factory(pins, output_file):
usdhc_pins = filter(lambda p: any([af for af in p.alt_fn if "USDHC" in af.af_str]), pins)
usdhc_instances = dict()
for pin in usdhc_pins:
for idx, alt_fn in enumerate(pin.alt_fn):
if "USDHC" in alt_fn.instance:
format_string = "#define {0}_{1} &pin_{0}, {2}"
if alt_fn.instance not in usdhc_instances:
usdhc_instances[alt_fn.instance] = [
format_string.format(pin.name, alt_fn.af_str, idx)
]
else:
usdhc_instances[alt_fn.instance].append(
format_string.format(pin.name, alt_fn.af_str, idx)
)
for k, v in usdhc_instances.items():
output_file.write(f"// {k}\n")
output_file.write(f"#define {k}_AVAIL (1)\n")
for i in v:
output_file.write(i + "\n")
def main():
parser = argparse.ArgumentParser(
prog="make-pins.py",
usage="%(prog)s [options] [command]",
description="Generate board specific pin file",
)
parser.add_argument(
"-a",
"--af",
dest="af_filename",
help="Specifies the alternate function file for the chip",
default="mimxrt1021_af.csv",
)
parser.add_argument(
"-i",
"--iomux",
dest="iomux_filename",
help="Specifies the fsl_iomux.h file for the chip",
default="fsl_iomuxc.h",
)
parser.add_argument(
"-b",
"--board",
dest="board_filename",
help="Specifies the board file",
default="MIMXRT1020_EVK/pins.csv",
)
parser.add_argument(
"-p",
"--prefix",
dest="prefix_filename",
help="Specifies beginning portion of generated pins file",
default="mimxrt_prefix.c",
)
parser.add_argument(
"-r",
"--hdr",
dest="hdr_filename",
help="Specifies name of generated pin header file",
default="build/pins.h",
)
pins = Pins()
# test code
args = parser.parse_args()
#
if args.af_filename:
print("// --af {:s}".format(args.af_filename))
pins.parse_af_file(args.af_filename, args.iomux_filename, 0, 1)
if args.board_filename:
print("// --board {:s}".format(args.board_filename))
pins.parse_board_file(args.board_filename)
if args.hdr_filename:
print("// --hdr {:s}".format(args.hdr_filename))
if args.prefix_filename:
print("// --prefix {:s}".format(args.prefix_filename))
with open(args.prefix_filename, "r") as prefix_file:
print(prefix_file.read())
pins.print()
pins.print_header(args.hdr_filename)
if __name__ == "__main__":
main()