@ -1,19 +1,15 @@
#!/usr/bin/env python
""" Creates the pin file for the MIMXRT10xx. """
from __future__ import print_function
import argparse
import sys
import csv
from collections import defaultdict
import os
import re
import sys
SUPPORTED_AFS = { " GPIO " , " USDHC " , " FLEXPWM " , " TMR " }
MAX_AF = 10 # AF0 .. AF9
ADC_COL = 11
sys . path . insert ( 0 , os . path . join ( os . path . dirname ( __file__ ) , " ../../../tools " ) )
import boardgen
regexes = [
IOMUX_REGEXS = [
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+) " ,
@ -30,387 +26,197 @@ regexes = [
r " IOMUXC_(?P<pin>GPIO_SNVS_ \ d \ d_DIG)_(?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*) "
lpadc_regex = r " ADC(?P<instance> \ d*)_CH(?P<channel> \ 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 " ) ,
SUPPORTED_AF_FNS = { " GPIO " , " USDHC " , " FLEXPWM " , " TMR " }
class MimxrtPin ( boardgen . Pin ) :
def __init__ ( self , cpu_pin_name ) :
super ( ) . __init__ ( cpu_pin_name )
self . _afs = [ ]
self . _adc_fns = [ ]
# Called for each AF defined in the csv file for this pin.
def add_af ( self , af_idx , af_name , af ) :
# mimxrt-specific: Any pin in the af.csv is implicitly part of the board
# pins.csv and will therefore be in the Pin.cpu dict. This is
# equivalent to adding `,CPUNAME` to the board.csv for every pin in the
# af.csv.
self . _available = True
if af_name == " ALT5 " :
m = re . match ( " GPIO([0-9]+)_IO([0-9]+) " , af )
self . _port = int ( m . group ( 1 ) )
self . _pin = int ( m . group ( 2 ) )
if af_name . startswith ( " ALT " ) :
instance = af . split ( " _ " ) [ 0 ]
fn = re . match ( " ^([A-Z][A-Z0-9]+[A-Z])[0-9]*$ " , instance ) . group ( 1 )
if fn not in SUPPORTED_AF_FNS :
return
iomux_config = self . _generator . _iomux_pin_config [ self . name ( ) ]
input_reg = iomux_config [ af_idx ] [ " inputRegister " ] . strip ( " U " )
input_daisy = int ( iomux_config [ af_idx ] [ " inputDaisy " ] . strip ( " U " ) , 16 )
self . _afs . append ( ( af_idx , input_reg , input_daisy , instance , fn , af ) )
elif af_name == " ADC " :
adc_regex = r " ADC(?P<instance> \ d*)_IN(?P<channel> \ d*) "
lpadc_regex = r " ADC(?P<instance> \ d*)_CH(?P<channel> \ d*) " # LPADC for MIMXRT11xx chips
matches = re . finditer ( adc_regex , af , re . MULTILINE )
for match in matches :
self . _adc_fns . append (
( int ( match . group ( " instance " ) ) , int ( match . group ( " channel " ) ) , " ADC " )
)
)
def parse_af ( self , af_idx , af_strs_in ) :
pass
def add_af ( self , af ) :
self . alt_fn . append ( af )
matches = re . finditer ( lpadc_regex , af , re . MULTILINE )
for match in matches :
self . _adc_fns . append (
( int ( match . group ( " instance " ) ) , int ( match . group ( " channel " ) ) , " LPADC " )
)
def print_pin_af ( self , out_source ) :
if self . alt_fn :
print (
" static const machine_pin_af_obj_t pin_ {0} _af[ {1} ] = {{ " . format (
self . name , len ( self . alt_fn )
) ,
file = out_source ,
)
for af in self . alt_fn :
af . print ( out_source )
print ( " }; " , file = out_source )
# Use the PIN() macro defined in samd_prefix.c for defining the pin
# objects.
def definition ( self ) :
if " _LPSR_ " in self . name ( ) :
macro = " PIN_LPSR "
elif (
" _SNVS_ " in self . name ( )
or self . name ( ) . startswith ( " PMIC_ " )
or self . name ( ) . startswith ( " WAKEUP " )
) :
macro = " PIN_SNVS "
else :
raise ValueError ( " Pin ' {} ' has no alternative functions " . format ( self . name ) )
macro = " PIN "
# PIN(_name, _gpio, _pin, _af_list, _adc_list_len, _adc_list)
return " {:s} ( {:s} , GPIO {:d} , {:d} , pin_ {:s} _af, {:d} , {:s} ) " . format (
macro ,
self . name ( ) ,
self . _port ,
self . _pin ,
self . name ( ) ,
len ( self . _adc_fns ) ,
" pin_ {:s} _adc " . format ( self . name ( ) ) if self . _adc_fns else " NULL " ,
)
def print_pin_adc ( self , out_source ) :
if self . adc_fns :
# This will be called at the start of the output (after the prefix) for
# each pin. Use it to emit the af and adc objects.
def print_source ( self , out_source ) :
print (
" static const machine_pin_af_obj_t pin_ {:s} _af[] = {{ " . format ( self . name ( ) ) ,
file = out_source ,
)
for af_idx , input_reg , input_daisy , instance , _fn , af in self . _afs :
print (
" static const machine_pin_adc_obj_t pin_ {0} _adc[ {1} ] = {{ " . format (
self . name , len ( self . adc_fns )
" PIN_AF( {:s} , PIN_AF_MODE_ALT {:d} , {:d} , {:s} , {:s} , {:s} ), " . format (
af , af_idx , input_daisy , instance , input_reg , " 0x10B0U "
) ,
file = out_source ,
)
for adc_fn in self . adc_fns :
adc_fn . print ( out_source )
print ( " }; " , file = out_source )
def print ( self , out_source ) :
if self . alt_fn :
self . print_pin_af ( out_source )
self . print_pin_adc ( out_source )
options = {
" GPIO_LPSR_00 " : " PIN_LPSR " ,
" GPIO_LPSR_01 " : " PIN_LPSR " ,
" GPIO_LPSR_02 " : " PIN_LPSR " ,
" GPIO_LPSR_03 " : " PIN_LPSR " ,
" GPIO_LPSR_04 " : " PIN_LPSR " ,
" GPIO_LPSR_05 " : " PIN_LPSR " ,
" GPIO_LPSR_06 " : " PIN_LPSR " ,
" GPIO_LPSR_07 " : " PIN_LPSR " ,
" GPIO_LPSR_08 " : " PIN_LPSR " ,
" GPIO_LPSR_09 " : " PIN_LPSR " ,
" GPIO_LPSR_10 " : " PIN_LPSR " ,
" GPIO_LPSR_11 " : " PIN_LPSR " ,
" GPIO_LPSR_12 " : " PIN_LPSR " ,
" GPIO_LPSR_13 " : " PIN_LPSR " ,
" GPIO_LPSR_14 " : " PIN_LPSR " ,
" GPIO_LPSR_15 " : " PIN_LPSR " ,
" GPIO_SNVS_00_DIG " : " PIN_SNVS " ,
" GPIO_SNVS_01_DIG " : " PIN_SNVS " ,
" GPIO_SNVS_02_DIG " : " PIN_SNVS " ,
" GPIO_SNVS_03_DIG " : " PIN_SNVS " ,
" GPIO_SNVS_04_DIG " : " PIN_SNVS " ,
" GPIO_SNVS_05_DIG " : " PIN_SNVS " ,
" GPIO_SNVS_06_DIG " : " PIN_SNVS " ,
" GPIO_SNVS_07_DIG " : " PIN_SNVS " ,
" GPIO_SNVS_08_DIG " : " PIN_SNVS " ,
" GPIO_SNVS_09_DIG " : " PIN_SNVS " ,
" WAKEUP " : " PIN_SNVS " ,
" WAKEUP_DIG " : " PIN_SNVS " ,
" PMIC_ON_REQ " : " PIN_SNVS " ,
" PMIC_ON_REQ_DIG " : " PIN_SNVS " ,
" PMIC_STBY_REQ " : " PIN_SNVS " ,
" PMIC_STBY_REQ_DIG " : " PIN_SNVS " ,
}
print ( " }; " , file = out_source )
print ( file = out_source )
if self . _adc_fns :
print (
" const machine_pin_obj_t pin_ {0} = {1} ( {0} , {2} , {3} , pin_ {0} _af, {4} , {5} ); \n " . format (
self . name ,
options . get ( self . name , " PIN " ) ,
self . gpio ,
int ( self . pin ) ,
len ( self . adc_fns ) ,
" pin_ {} _adc " . format ( self . name ) if self . adc_fns else " NULL " ,
) ,
" static const machine_pin_adc_obj_t pin_ {:s} _adc[] = {{ " . format ( self . name ( ) ) ,
file = out_source ,
)
else :
raise ValueError ( " Pin ' {} ' has no alternative functions " . format ( self . name ) )
def print_header ( self , out_header ) :
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 , out_source ) :
""" Prints the C representation of this AF. """
print ( f " PIN_ADC( { self . peripheral } { self . instance } , { self . channel } ), " , file = out_source )
for instance , channel , peripheral in self . _adc_fns :
print (
" PIN_ADC( {:s} {:d} , {:d} ), " . format ( peripheral , instance , channel ) ,
file = out_source ,
)
print ( " }; " , file = out_source )
# mimxrt cpu names must be "GPIO_<funcs>_<num>", with zero-prefixed two-digit <num>.
@staticmethod
def validate_cpu_pin_name ( cpu_pin_name ) :
boardgen . Pin . validate_cpu_pin_name ( cpu_pin_name )
class AlternateFunction ( object ) :
""" Holds the information associated with a pins alternate function. """
if not re . match (
" ^((GPIO_((SNVS|EMC|LPSR|DISP)_)?([AS]D_)?(B[012]_)?[0-9][0-9])|WAKEUP|PMIC_(ON|STBY)_REQ)(_DIG)?$ " ,
cpu_pin_name ,
) :
raise boardgen . PinGeneratorError ( " Invalid cpu pin name ' {} ' " . format ( cpu_pin_name ) )
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 , out_source ) :
""" 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 "
) ,
file = out_sourc e,
class MimxrtPinGenerator ( boardgen . PinGenerator ) :
def __init__ ( self ) :
# Use custom pin type above, and also enable the --af-csv argument so
# that add_af gets called on each pin.
super ( ) . __init__ (
pin_type = MimxrtPin ,
enable_af = True ,
)
self . _iomux_pin_config = { }
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 ( )
# Load the iomux configuration from fsl_iomuxc.h.
def load_iomux_header ( self , iomux_filename ) :
with open ( iomux_filename , " r " ) as ipt :
input_str = ipt . read ( )
for regex in regexes :
for regex in IOMUX_REGEXS :
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 " ) ] = {
if match . group ( " pin " ) not in self . _iomux_pin_config :
self . _iomux_pin_config [ match . group ( " pin " ) ] = {
int ( ( match . groupdict ( ) [ " muxMode " ] . strip ( " U " ) ) , 16 ) : match . groupdict ( )
}
else :
iomux_pin_config [ match . group ( " pin " ) ] [
self . _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 )
# 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 ,
# Also load the iomux header.
def load_inputs ( self , out_source ) :
if self . args . iomux_header :
print ( " // --iomux-header {:s} " . format ( self . args . iomux_header ) , file = out_source )
self . load_iomux_header ( self . args . iomux_header )
super ( ) . load_inputs ( out_source )
# Provide a macro for each supported (pin,af) that can be used to
# initialise a struct containing a machine_pin_obj_t* and the
# corresponding af for that pin. e.g. A mimxrt_sdcard_pin_t instance can
# be initialised with GPIO_SD_B0_00_USDHC1_CMD which tells it how to get
# the CMD pin of the USDHC1 function on the GPIO_SD_B0_00 pin.
def print_module_instances ( self , out_header ) :
print ( file = out_header )
for match_fn in ( " USDHC " , " FLEXPWM " , " TMR " ) :
module_instances = defaultdict ( list )
for pin in self . available_pins ( ) :
for i , ( _af_idx , _input_reg , _input_daisy , instance , fn , af ) in enumerate (
pin . _afs
) :
if fn == match_fn :
module_instances [ instance ] . append (
" #define {:s} _ {:s} pin_ {:s} , {:d} " . format (
pin . name ( ) , af , pin . name ( ) , i
)
)
for k , v in module_instances . items ( ) :
print ( " // {:s} " . format ( k ) , file = out_header )
print ( " #define {:s} _AVAIL (1) " . format ( k ) , file = out_header )
if match_fn == " FLEXPWM " :
print ( " #define {:s} {:s} " . format ( k , k [ - 4 : ] ) , file = out_header )
for i in v :
print ( i , file = out_header )
# Override to also print the module instances.
def print_header ( self , out_header ) :
super ( ) . print_header ( out_header )
self . print_module_instances ( out_header )
pin . parse_adc ( row [ adc_col ] )
self . cpu_pins . append ( pin )
@staticmethod
def print_named ( label , pins , out_source ) :
print ( " " , file = out_source )
print (
" STATIC const mp_rom_map_elem_t pin_ {:s} _pins_locals_dict_table[] = {{ " . format ( label ) ,
file = out_source ,
)
for pin in pins :
(
print (
" {{ MP_ROM_QSTR(MP_QSTR_ {} ), MP_ROM_PTR(&pin_ {} ) }}, " . format (
pin . name , pin . pad
) ,
file = out_source ,
) ,
)
print ( " }; " , file = out_source )
print (
" MP_DEFINE_CONST_DICT(machine_pin_ {:s} _pins_locals_dict, pin_ {:s} _pins_locals_dict_table); " . format (
label , label
) ,
file = out_source ,
)
def print ( self , out_source ) :
# Print Pin Object declarations
for pin in self . cpu_pins :
pin . print ( out_source )
print ( " " , file = out_source )
print ( " const machine_pin_obj_t* machine_pin_board_pins [] = { " , file = out_source )
for pin in self . board_pins :
print ( " &pin_ {} , " . format ( pin . pad ) , file = out_source )
print ( " }; " , file = out_source )
print (
" const uint32_t num_board_pins = {:d} ; " . format ( len ( self . board_pins ) ) , file = out_source
)
# Print Pin mapping dictionaries
self . print_named ( " cpu " , self . cpu_pins , out_source )
self . print_named ( " board " , self . board_pins , out_source )
print ( " " , file = out_source )
# Override the default implementation just to change the default arguments
# (extra header row, skip first column).
def parse_af_csv ( self , filename ) :
return super ( ) . parse_af_csv ( filename , header_rows = 1 , pin_col = 0 , af_col = 1 )
def print_header ( self , out_header ) :
for pin in self . cpu_pins :
print ( " extern const machine_pin_obj_t pin_ {} ; " . format ( pin . name ) , file = out_header )
print ( " extern const machine_pin_obj_t* machine_pin_board_pins[]; " , file = out_header )
print ( " extern const uint32_t num_board_pins; " , file = out_header )
print ( " extern const mp_obj_dict_t machine_pin_cpu_pins_locals_dict; " , file = out_header )
print ( " extern const mp_obj_dict_t machine_pin_board_pins_locals_dict; " , file = out_header )
print ( " " , file = out_header )
print ( " // Defines " , file = out_header )
module_instance_factory ( self . cpu_pins , out_header , " USDHC " )
module_instance_factory ( self . cpu_pins , out_header , " FLEXPWM " )
module_instance_factory ( self . cpu_pins , out_header , " TMR " )
def module_instance_factory ( pins , out_header , 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 ( ) :
print ( f " // { k } " , file = out_header )
print ( f " #define { k } _AVAIL (1) " , file = out_header )
if name == " FLEXPWM " :
print ( f " #define { k } { k [ - 4 : ] } " , file = out_header )
for i in v :
print ( i , file = out_header )
def main ( ) :
parser = argparse . ArgumentParser ( description = " Generate board specific pin file " )
parser . add_argument ( " --board-csv " )
parser . add_argument ( " --af-csv " )
parser . add_argument ( " --prefix " )
parser . add_argument ( " --iomux-header " )
parser . add_argument ( " --output-source " )
parser . add_argument ( " --output-header " )
args = parser . parse_args ( )
pins = Pins ( )
with open ( args . output_source , " w " ) as out_source :
if args . af_csv :
print ( " // --af {:s} " . format ( args . af_csv ) , file = out_source )
pins . parse_af_file ( args . af_csv , args . iomux_header )
if args . board_csv :
print ( " // --board {:s} " . format ( args . board_csv ) , file = out_source )
pins . parse_board_file ( args . board_csv )
if args . output_header :
print ( " // --hdr {:s} " . format ( args . output_header ) , file = out_source )
if args . prefix :
print ( " // --prefix {:s} " . format ( args . prefix ) , file = out_source )
with open ( args . prefix , " r " ) as prefix_file :
print ( prefix_file . read ( ) , file = out_source )
pins . print ( out_source )
with open ( args . output_header , " w " ) as out_header :
pins . print_header ( out_header )
# We need to know the mcu to emit the correct AF list.
def extra_args ( self , parser ) :
parser . add_argument ( " --iomux-header " )
if __name__ == " __main__ " :
main ( )
MimxrtPinGenerator ( ) . main ( )