make-pins.py 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405
  1. #!/usr/bin/env python
  2. """Creates the pin file for the Teensy."""
  3. from __future__ import print_function
  4. import argparse
  5. import sys
  6. import csv
  7. SUPPORTED_FN = {
  8. 'FTM' : ['CH0', 'CH1', 'CH2', 'CH3', 'CH4', 'CH5', 'CH6', 'CH7',
  9. 'QD_PHA', 'QD_PHB'],
  10. 'I2C' : ['SDA', 'SCL'],
  11. 'UART' : ['RX', 'TX', 'CTS', 'RTS'],
  12. 'SPI' : ['NSS', 'SCK', 'MISO', 'MOSI']
  13. }
  14. def parse_port_pin(name_str):
  15. """Parses a string and returns a (port-num, pin-num) tuple."""
  16. if len(name_str) < 4:
  17. raise ValueError("Expecting pin name to be at least 4 charcters.")
  18. if name_str[0:2] != 'PT':
  19. raise ValueError("Expecting pin name to start with PT")
  20. if name_str[2] not in ('A', 'B', 'C', 'D', 'E', 'Z'):
  21. raise ValueError("Expecting pin port to be between A and E or Z")
  22. port = ord(name_str[2]) - ord('A')
  23. pin_str = name_str[3:].split('/')[0]
  24. if not pin_str.isdigit():
  25. raise ValueError("Expecting numeric pin number.")
  26. return (port, int(pin_str))
  27. def split_name_num(name_num):
  28. num = None
  29. for num_idx in range(len(name_num) - 1, -1, -1):
  30. if not name_num[num_idx].isdigit():
  31. name = name_num[0:num_idx + 1]
  32. num_str = name_num[num_idx + 1:]
  33. if len(num_str) > 0:
  34. num = int(num_str)
  35. break
  36. return name, num
  37. class AlternateFunction(object):
  38. """Holds the information associated with a pins alternate function."""
  39. def __init__(self, idx, af_str):
  40. self.idx = idx
  41. self.af_str = af_str
  42. self.func = ''
  43. self.fn_num = None
  44. self.pin_type = ''
  45. self.supported = False
  46. af_words = af_str.split('_', 1)
  47. self.func, self.fn_num = split_name_num(af_words[0])
  48. if len(af_words) > 1:
  49. self.pin_type = af_words[1]
  50. if self.func in SUPPORTED_FN:
  51. pin_types = SUPPORTED_FN[self.func]
  52. if self.pin_type in pin_types:
  53. self.supported = True
  54. def is_supported(self):
  55. return self.supported
  56. def ptr(self):
  57. """Returns the numbered function (i.e. USART6) for this AF."""
  58. if self.fn_num is None:
  59. return self.func
  60. return '{:s}{:d}'.format(self.func, self.fn_num)
  61. def mux_name(self):
  62. return 'AF{:d}_{:s}'.format(self.idx, self.ptr())
  63. def print(self):
  64. """Prints the C representation of this AF."""
  65. if self.supported:
  66. print(' AF', end='')
  67. else:
  68. print(' //', end='')
  69. fn_num = self.fn_num
  70. if fn_num is None:
  71. fn_num = 0
  72. print('({:2d}, {:8s}, {:2d}, {:10s}, {:8s}), // {:s}'.format(self.idx,
  73. self.func, fn_num, self.pin_type, self.ptr(), self.af_str))
  74. def qstr_list(self):
  75. return [self.mux_name()]
  76. class Pin(object):
  77. """Holds the information associated with a pin."""
  78. def __init__(self, port, pin):
  79. self.port = port
  80. self.pin = pin
  81. self.alt_fn = []
  82. self.alt_fn_count = 0
  83. self.adc_num = 0
  84. self.adc_channel = 0
  85. self.board_pin = False
  86. def port_letter(self):
  87. return chr(self.port + ord('A'))
  88. def cpu_pin_name(self):
  89. return '{:s}{:d}'.format(self.port_letter(), self.pin)
  90. def is_board_pin(self):
  91. return self.board_pin
  92. def set_is_board_pin(self):
  93. self.board_pin = True
  94. def parse_adc(self, adc_str):
  95. if (adc_str[:3] != 'ADC'):
  96. return
  97. (adc,channel) = adc_str.split('_')
  98. for idx in range(3, len(adc)):
  99. adc_num = int(adc[idx]) # 1, 2, or 3
  100. self.adc_num |= (1 << (adc_num - 1))
  101. self.adc_channel = int(channel[2:])
  102. def parse_af(self, af_idx, af_strs_in):
  103. if len(af_strs_in) == 0:
  104. return
  105. # If there is a slash, then the slash separates 2 aliases for the
  106. # same alternate function.
  107. af_strs = af_strs_in.split('/')
  108. for af_str in af_strs:
  109. alt_fn = AlternateFunction(af_idx, af_str)
  110. self.alt_fn.append(alt_fn)
  111. if alt_fn.is_supported():
  112. self.alt_fn_count += 1
  113. def alt_fn_name(self, null_if_0=False):
  114. if null_if_0 and self.alt_fn_count == 0:
  115. return 'NULL'
  116. return 'pin_{:s}_af'.format(self.cpu_pin_name())
  117. def adc_num_str(self):
  118. str = ''
  119. for adc_num in range(1,4):
  120. if self.adc_num & (1 << (adc_num - 1)):
  121. if len(str) > 0:
  122. str += ' | '
  123. str += 'PIN_ADC'
  124. str += chr(ord('0') + adc_num)
  125. if len(str) == 0:
  126. str = '0'
  127. return str
  128. def print(self):
  129. if self.alt_fn_count == 0:
  130. print("// ", end='')
  131. print('const pin_af_obj_t {:s}[] = {{'.format(self.alt_fn_name()))
  132. for alt_fn in self.alt_fn:
  133. alt_fn.print()
  134. if self.alt_fn_count == 0:
  135. print("// ", end='')
  136. print('};')
  137. print('')
  138. print('const pin_obj_t pin_{:s} = PIN({:s}, {:d}, {:d}, {:s}, {:s}, {:d});'.format(
  139. self.cpu_pin_name(), self.port_letter(), self.pin,
  140. self.alt_fn_count, self.alt_fn_name(null_if_0=True),
  141. self.adc_num_str(), self.adc_channel))
  142. print('')
  143. def print_header(self, hdr_file):
  144. hdr_file.write('extern const pin_obj_t pin_{:s};\n'.
  145. format(self.cpu_pin_name()))
  146. if self.alt_fn_count > 0:
  147. hdr_file.write('extern const pin_af_obj_t pin_{:s}_af[];\n'.
  148. format(self.cpu_pin_name()))
  149. def qstr_list(self):
  150. result = []
  151. for alt_fn in self.alt_fn:
  152. if alt_fn.is_supported():
  153. result += alt_fn.qstr_list()
  154. return result
  155. class NamedPin(object):
  156. def __init__(self, name, pin):
  157. self._name = name
  158. self._pin = pin
  159. def pin(self):
  160. return self._pin
  161. def name(self):
  162. return self._name
  163. class Pins(object):
  164. def __init__(self):
  165. self.cpu_pins = [] # list of NamedPin objects
  166. self.board_pins = [] # list of NamedPin objects
  167. def find_pin(self, port_num, pin_num):
  168. for named_pin in self.cpu_pins:
  169. pin = named_pin.pin()
  170. if pin.port == port_num and pin.pin == pin_num:
  171. return pin
  172. def parse_af_file(self, filename, pinname_col, af_col):
  173. with open(filename, 'r') as csvfile:
  174. rows = csv.reader(csvfile)
  175. for row in rows:
  176. try:
  177. (port_num, pin_num) = parse_port_pin(row[pinname_col])
  178. except:
  179. continue
  180. pin = Pin(port_num, pin_num)
  181. for af_idx in range(af_col, len(row)):
  182. if af_idx >= af_col:
  183. pin.parse_af(af_idx - af_col, row[af_idx])
  184. self.cpu_pins.append(NamedPin(pin.cpu_pin_name(), pin))
  185. def parse_board_file(self, filename):
  186. with open(filename, 'r') as csvfile:
  187. rows = csv.reader(csvfile)
  188. for row in rows:
  189. try:
  190. (port_num, pin_num) = parse_port_pin(row[1])
  191. except:
  192. continue
  193. pin = self.find_pin(port_num, pin_num)
  194. if pin:
  195. pin.set_is_board_pin()
  196. self.board_pins.append(NamedPin(row[0], pin))
  197. def print_named(self, label, named_pins):
  198. print('STATIC const mp_rom_map_elem_t pin_{:s}_pins_locals_dict_table[] = {{'.format(label))
  199. for named_pin in named_pins:
  200. pin = named_pin.pin()
  201. if pin.is_board_pin():
  202. print(' {{ MP_ROM_QSTR(MP_QSTR_{:s}), MP_ROM_PTR(&pin_{:s}) }},'.format(named_pin.name(), pin.cpu_pin_name()))
  203. print('};')
  204. print('MP_DEFINE_CONST_DICT(pin_{:s}_pins_locals_dict, pin_{:s}_pins_locals_dict_table);'.format(label, label));
  205. def print(self):
  206. for named_pin in self.cpu_pins:
  207. pin = named_pin.pin()
  208. if pin.is_board_pin():
  209. pin.print()
  210. self.print_named('cpu', self.cpu_pins)
  211. print('')
  212. self.print_named('board', self.board_pins)
  213. def print_adc(self, adc_num):
  214. print('');
  215. print('const pin_obj_t * const pin_adc{:d}[] = {{'.format(adc_num))
  216. for channel in range(16):
  217. adc_found = False
  218. for named_pin in self.cpu_pins:
  219. pin = named_pin.pin()
  220. if (pin.is_board_pin() and
  221. (pin.adc_num & (1 << (adc_num - 1))) and (pin.adc_channel == channel)):
  222. print(' &pin_{:s}, // {:d}'.format(pin.cpu_pin_name(), channel))
  223. adc_found = True
  224. break
  225. if not adc_found:
  226. print(' NULL, // {:d}'.format(channel))
  227. print('};')
  228. def print_header(self, hdr_filename):
  229. with open(hdr_filename, 'wt') as hdr_file:
  230. for named_pin in self.cpu_pins:
  231. pin = named_pin.pin()
  232. if pin.is_board_pin():
  233. pin.print_header(hdr_file)
  234. hdr_file.write('extern const pin_obj_t * const pin_adc1[];\n')
  235. hdr_file.write('extern const pin_obj_t * const pin_adc2[];\n')
  236. hdr_file.write('extern const pin_obj_t * const pin_adc3[];\n')
  237. def print_qstr(self, qstr_filename):
  238. with open(qstr_filename, 'wt') as qstr_file:
  239. qstr_set = set([])
  240. for named_pin in self.cpu_pins:
  241. pin = named_pin.pin()
  242. if pin.is_board_pin():
  243. qstr_set |= set(pin.qstr_list())
  244. qstr_set |= set([named_pin.name()])
  245. for named_pin in self.board_pins:
  246. qstr_set |= set([named_pin.name()])
  247. for qstr in sorted(qstr_set):
  248. print('Q({})'.format(qstr), file=qstr_file)
  249. def print_af_hdr(self, af_const_filename):
  250. with open(af_const_filename, 'wt') as af_const_file:
  251. af_hdr_set = set([])
  252. mux_name_width = 0
  253. for named_pin in self.cpu_pins:
  254. pin = named_pin.pin()
  255. if pin.is_board_pin():
  256. for af in pin.alt_fn:
  257. if af.is_supported():
  258. mux_name = af.mux_name()
  259. af_hdr_set |= set([mux_name])
  260. if len(mux_name) > mux_name_width:
  261. mux_name_width = len(mux_name)
  262. for mux_name in sorted(af_hdr_set):
  263. key = 'MP_OBJ_NEW_QSTR(MP_QSTR_{}),'.format(mux_name)
  264. val = 'MP_OBJ_NEW_SMALL_INT(GPIO_{})'.format(mux_name)
  265. print(' { %-*s %s },' % (mux_name_width + 26, key, val),
  266. file=af_const_file)
  267. def print_af_py(self, af_py_filename):
  268. with open(af_py_filename, 'wt') as af_py_file:
  269. print('PINS_AF = (', file=af_py_file);
  270. for named_pin in self.board_pins:
  271. print(" ('%s', " % named_pin.name(), end='', file=af_py_file)
  272. for af in named_pin.pin().alt_fn:
  273. if af.is_supported():
  274. print("(%d, '%s'), " % (af.idx, af.af_str), end='', file=af_py_file)
  275. print('),', file=af_py_file)
  276. print(')', file=af_py_file)
  277. def main():
  278. parser = argparse.ArgumentParser(
  279. prog="make-pins.py",
  280. usage="%(prog)s [options] [command]",
  281. description="Generate board specific pin file"
  282. )
  283. parser.add_argument(
  284. "-a", "--af",
  285. dest="af_filename",
  286. help="Specifies the alternate function file for the chip",
  287. default="mk20dx256_af.csv"
  288. )
  289. parser.add_argument(
  290. "--af-const",
  291. dest="af_const_filename",
  292. help="Specifies header file for alternate function constants.",
  293. default="build/pins_af_const.h"
  294. )
  295. parser.add_argument(
  296. "--af-py",
  297. dest="af_py_filename",
  298. help="Specifies the filename for the python alternate function mappings.",
  299. default="build/pins_af.py"
  300. )
  301. parser.add_argument(
  302. "-b", "--board",
  303. dest="board_filename",
  304. help="Specifies the board file",
  305. )
  306. parser.add_argument(
  307. "-p", "--prefix",
  308. dest="prefix_filename",
  309. help="Specifies beginning portion of generated pins file",
  310. default="mk20dx256_prefix.c"
  311. )
  312. parser.add_argument(
  313. "-q", "--qstr",
  314. dest="qstr_filename",
  315. help="Specifies name of generated qstr header file",
  316. default="build/pins_qstr.h"
  317. )
  318. parser.add_argument(
  319. "-r", "--hdr",
  320. dest="hdr_filename",
  321. help="Specifies name of generated pin header file",
  322. default="build/pins.h"
  323. )
  324. args = parser.parse_args(sys.argv[1:])
  325. pins = Pins()
  326. print('// This file was automatically generated by make-pins.py')
  327. print('//')
  328. if args.af_filename:
  329. print('// --af {:s}'.format(args.af_filename))
  330. pins.parse_af_file(args.af_filename, 4, 3)
  331. if args.board_filename:
  332. print('// --board {:s}'.format(args.board_filename))
  333. pins.parse_board_file(args.board_filename)
  334. if args.prefix_filename:
  335. print('// --prefix {:s}'.format(args.prefix_filename))
  336. print('')
  337. with open(args.prefix_filename, 'r') as prefix_file:
  338. print(prefix_file.read())
  339. pins.print()
  340. pins.print_adc(1)
  341. pins.print_adc(2)
  342. pins.print_adc(3)
  343. pins.print_header(args.hdr_filename)
  344. pins.print_qstr(args.qstr_filename)
  345. pins.print_af_hdr(args.af_const_filename)
  346. pins.print_af_py(args.af_py_filename)
  347. if __name__ == "__main__":
  348. main()