#!/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", "FLEXPWM", "TMR"} MAX_AF = 10 # AF0 .. AF9 ADC_COL = 11 regexes = [ r"IOMUXC_(?PGPIO_SD_B\d_\d\d)_(?P\w+) (?P\w+), (?P\w+), (?P\w+), (?P\w+), (?P\w+)", r"IOMUXC_(?PGPIO_AD_B\d_\d\d)_(?P\w+) (?P\w+), (?P\w+), (?P\w+), (?P\w+), (?P\w+)", r"IOMUXC_(?PGPIO_EMC_\d\d)_(?P\w+) (?P\w+), (?P\w+), (?P\w+), (?P\w+), (?P\w+)", r"IOMUXC_(?PGPIO_B\d_\d\d)_(?P\w+) (?P\w+), (?P\w+), (?P\w+), (?P\w+), (?P\w+)", r"IOMUXC_(?PGPIO_\d\d)_(?P\w+) (?P\w+), (?P\w+), (?P\w+), (?P\w+), (?P\w+)", r"IOMUXC_(?PGPIO_AD_\d\d)_(?P\w+) (?P\w+), (?P\w+), (?P\w+), (?P\w+), (?P\w+)", r"IOMUXC_(?PGPIO_SD_\d\d)_(?P\w+) (?P\w+), (?P\w+), (?P\w+), (?P\w+), (?P\w+)", r"IOMUXC_(?PGPIO_EMC_B\d_\d\d)_(?P\w+) (?P\w+), (?P\w+), (?P\w+), (?P\w+), (?P\w+)", r"IOMUXC_(?PGPIO_DISP_B\d_\d\d)_(?P\w+) (?P\w+), (?P\w+), (?P\w+), (?P\w+), (?P\w+)", r"IOMUXC_(?PGPIO_LPSR_\d\d)_(?P\w+) (?P\w+), (?P\w+), (?P\w+), (?P\w+), (?P\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\d*)_IN(?P\d*)" lpadc_regex = r"ADC(?P\d*)_CH(?P\d*)" # LPADC for MIMXRT11xx chips 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")) ) matches = re.finditer(lpadc_regex, adc_str, re.MULTILINE) for match in matches: self.adc_fns.append( AdcFunction( peripheral="LPADC", 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() print( "const machine_pin_obj_t pin_{0} = {1}({0}, {2}, {3}, pin_{0}_af, {4}, {5});\n".format( self.name, "PIN_LPSR" if "LPSR" in self.name else "PIN", self.gpio, int(self.pin), len(self.adc_fns), "pin_{}_adc".format(self.name) if self.adc_fns else "NULL", ) ) 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, peripheral="ADC"): self.peripheral = peripheral self.instance = instance self.channel = channel def print(self): """Prints the C representation of this AF.""" print(f" PIN_ADC({self.peripheral}{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): 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) # Extract indexes from header row pad_col = header.index("Pad") adc_col = header.index("ADC") # 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) if any(s in pad for s in ("SNVS", "WAKEUP")): continue # Parse alternate functions af_idx = 0 for af_idx, af in enumerate(row[(pad_col + 1) : adc_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") module_instance_factory(self.cpu_pins, hdr_file, "USDHC") module_instance_factory(self.cpu_pins, hdr_file, "FLEXPWM") module_instance_factory(self.cpu_pins, hdr_file, "TMR") def module_instance_factory(pins, output_file, name): module_pin = filter(lambda p: any([af for af in p.alt_fn if name in af.af_str]), pins) module_instances = dict() for pin in module_pin: for idx, alt_fn in enumerate(pin.alt_fn): if name in alt_fn.instance: format_string = "#define {0}_{1} &pin_{0}, {2}" if alt_fn.instance not in module_instances: module_instances[alt_fn.instance] = [ format_string.format(pin.name, alt_fn.af_str, idx) ] else: module_instances[alt_fn.instance].append( format_string.format(pin.name, alt_fn.af_str, idx) ) for k, v in module_instances.items(): output_file.write(f"// {k}\n") output_file.write(f"#define {k}_AVAIL (1)\n") if name == "FLEXPWM": output_file.write(f"#define {k} {k[-4:]}\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_iomuxc.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) 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()