From b7a700d2d908cbf04f0000d3711a115f2d3070de Mon Sep 17 00:00:00 2001 From: Fabien Poussin Date: Mon, 8 May 2017 17:20:33 +0200 Subject: Adding mx2board script --- tools/board_gpio.tpl | 53 ++++++++++ tools/mx2board.py | 275 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 328 insertions(+) create mode 100644 tools/board_gpio.tpl create mode 100644 tools/mx2board.py (limited to 'tools') diff --git a/tools/board_gpio.tpl b/tools/board_gpio.tpl new file mode 100644 index 0000000..ea72b97 --- /dev/null +++ b/tools/board_gpio.tpl @@ -0,0 +1,53 @@ +#ifndef _BOARD_GPIO_H_ +#define _BOARD_GPIO_H_ + +{% for d, v in defines %} +#define {{ d }} {{ v }} +{%- endfor %} + +{% for p, v in ports %} +/* PORT {{p}} */ +#define VAL_GPIO{{p}}_MODER ( \ + {%- for i in v.MODER %} + {{ i }} | \ + {%- endfor %} + 0) + +#define VAL_GPIO{{p}}_OTYPER ( \ + {%- for i in v.OTYPER %} + {{ i }} | \ + {%- endfor %} + 0) + +#define VAL_GPIO{{p}}_OSPEEDR ( \ + {%- for i in v.OSPEEDR %} + {{ i }} | \ + {%- endfor %} + 0) + +#define VAL_GPIO{{p}}_PUPDR ( \ + {%- for i in v.PUPDR %} + {{ i }} | \ + {%- endfor %} + 0) + +#define VAL_GPIO{{p}}_ODR ( \ + {%- for i in v.ODR %} + {{ i }} | \ + {%- endfor %} + 0) + +#define VAL_GPIO{{p}}_AFRL ( \ + {%- for i in v.AFRL %} + {{ i }} | \ + {%- endfor %} + 0) + +#define VAL_GPIO{{p}}_AFRH ( \ + {%- for i in v.AFRH %} + {{ i }} | \ + {%- endfor %} + 0) +{% endfor %} + +#endif \ No newline at end of file diff --git a/tools/mx2board.py b/tools/mx2board.py new file mode 100644 index 0000000..6bbd41f --- /dev/null +++ b/tools/mx2board.py @@ -0,0 +1,275 @@ +#!/usr/bin/python + +__author__ = 'Fabien Poussin' +__version__ = '0.2' + + +import re +from xml.etree import ElementTree as etree +import argparse +from jinja2 import Template +import pprint + +pretty_print = pprint.PrettyPrinter(indent=2) + + +def pprint(*kwargs): + pretty_print.pprint(kwargs) + +PIN_MODE_INPUT = "PIN_MODE_INPUT({0})" +PIN_MODE_OUTPUT = "PIN_MODE_OUTPUT({0})" +PIN_MODE_ALTERNATE = "PIN_MODE_ALTERNATE({0})" +PIN_MODE_ANALOG = "PIN_MODE_ANALOG({0})" +PIN_ODR_LOW = "PIN_ODR_LOW({0})" +PIN_ODR_HIGH = "PIN_ODR_HIGH({0})" +PIN_OTYPE_PUSHPULL = "PIN_OTYPE_PUSHPULL({0})" +PIN_OTYPE_OPENDRAIN = "PIN_OTYPE_OPENDRAIN({0})" +PIN_OSPEED_VERYLOW = "PIN_OSPEED_VERYLOW({0})" +PIN_OSPEED_LOW = "PIN_OSPEED_LOW({0})" +PIN_OSPEED_MEDIUM = "PIN_OSPEED_MEDIUM({0})" +PIN_OSPEED_HIGH = "PIN_OSPEED_HIGH({0})" +PIN_PUPDR_FLOATING = "PIN_PUPDR_FLOATING({0})" +PIN_PUPDR_PULLUP = "PIN_PUPDR_PULLUP({0})" +PIN_PUPDR_PULLDOWN = "PIN_PUPDR_PULLDOWN({0})" +PIN_AFIO_AF = "PIN_AFIO_AF({0}, {1})" + +FMT = '{0}' +FMT_DEF = '({0})' + +PIN_CONF_LIST = ['MODER', 'OTYPER', 'OSPEEDR', 'PUPDR', 'ODR'] +PIN_CONF_LIST_AF = ['AFRL', 'AFRH'] + +DEFAULT_PAD = {"SIGNAL": "UNUSED", + "LABEL": "", + "MODER": PIN_MODE_ANALOG, + "OTYPER": PIN_OTYPE_PUSHPULL, + "OSPEEDR": PIN_OSPEED_VERYLOW, + "PUPDR": PIN_PUPDR_FLOATING, + "ODR": PIN_ODR_HIGH} + +PIN_MODE_TRANSLATE = {"GPIO_MODE_AF_PP": PIN_MODE_ALTERNATE, + "GPIO_MODE_ANALOG": PIN_MODE_ANALOG, + "GPIO_MODE_INPUT": PIN_MODE_INPUT, + "GPIO_MODE_OUTPUT": PIN_MODE_OUTPUT, + "GPIO_MODE_OUTPUT_PP": PIN_MODE_OUTPUT, + "GPIO_MODE_OUTPUT_OD": PIN_MODE_OUTPUT} + +PIN_OTYPE_TRANSLATE = {"GPIO_MODE_OUTPUT_PP": PIN_OTYPE_PUSHPULL, + "GPIO_MODE_OUTPUT_OD": PIN_OTYPE_OPENDRAIN} + +PIN_OSPEED_TRANSLATE = {"GPIO_SPEED_FREQ_LOW": PIN_OSPEED_VERYLOW, + "GPIO_SPEED_FREQ_MEDIUM": PIN_OSPEED_LOW, + "GPIO_SPEED_FREQ_HIGH": PIN_OSPEED_MEDIUM, + "GPIO_SPEED_FREQ_VERY_HIGH": PIN_OSPEED_HIGH + } + +PIN_PUPDR_TRANSLATE = {"GPIO_NOPULL": PIN_PUPDR_FLOATING, + "GPIO_PULLUP": PIN_PUPDR_PULLUP, + "GPIO_PULLDOWN": PIN_PUPDR_PULLDOWN} + +parser = argparse.ArgumentParser(description='Generate ChibiOS GPIO header file from STM32CubeMX file.') +parser.add_argument('-g', '--gpio', required=True, type=str) +parser.add_argument('-b', '--project', required=True, type=str) +parser.add_argument('-o', '--output', default='board_gpio.h', type=str) + + +def open_xml(filename): + # Remove namespace + with open(filename, 'r') as xmlfile: + xml = re.sub(' xmlns="[^"]+"', '', xmlfile.read(), count=1) + return etree.fromstring(xml) + + +def char_range(c1, c2): + """Generates the characters from `c1` to `c2`, inclusive.""" + for c in range(ord(c1), ord(c2)+1): + yield chr(c) + + +def read_gpio(filename): + gpio = {'ports': {}, 'defaults': {}, 'modes': {}} + root = open_xml(filename) + + gpio['defaults']['GPIO_Mode'] = 'GPIO_MODE_ANALOG' + + for modes in root.findall("RefParameter"): + try: + name = modes.attrib['Name'] + gpio['defaults'][name] = modes.attrib['DefaultValue'] + gpio['modes'][name] = [] + except KeyError as e: + continue + + if 'GPIO_' not in name: + continue + + for m in modes.findall("PossibleValue"): + prop_val = m.attrib['Value'] + gpio['modes'][name].append(prop_val) + + for pin in root.findall('GPIO_Pin'): + try: + port = pin.attrib['Name'][1] + num = int(pin.attrib['Name'][2:]) + if port not in gpio['ports']: + gpio['ports'][port] = {} + if num not in gpio['ports'][port]: + gpio['ports'][port][num] = {} + except ValueError as e: + continue + + for s in pin.findall('PinSignal'): + try: + af = s.find('SpecificParameter/PossibleValue').text + af = int(''.join(af.split('_')[1])[2:]) + gpio['ports'][port][num][s.attrib['Name']] = af + except ValueError as e: + print(e) + except AttributeError as e: + print(e) + + return gpio + + +# Extract signals from IOC +def read_project(gpio, filename): + with open(filename, 'r') as mx_file: + tmp = mx_file.readlines() + pads = {} + + # Default all pads to analog + for p in gpio['ports'].keys(): + pads[p] = {} + for i in range(0, 16): + pads[p][i] = DEFAULT_PAD.copy() + pads[p][i]['PUPDR'] = PIN_PUPDR_TRANSLATE[gpio['defaults']['GPIO_PuPdOD']] + pads[p][i]['OTYPER'] = PIN_OTYPE_TRANSLATE[gpio['defaults']['GPIO_ModeDefaultOutputPP']] + pads[p][i]['OSPEEDR'] = PIN_OSPEED_TRANSLATE[gpio['defaults']['GPIO_Speed']] + + for t in tmp: + if re.search(r"^P[A-Z]\d{1,2}(-OSC.+)?\.", t, re.M): + split = t.split('=') + pad_name = split[0].split(".")[0] + pad_port = pad_name[1:2] + pad_num = int(pad_name[2:4].replace('.', '').replace('-', '')) + pad_prop = split[0].split(".")[-1] + prop_value = split[-1].rstrip('\r\n') + + if pad_prop == "Signal": + if 'S_TIM' in prop_value: + prop_value = prop_value[2:] + + if 'ADC' in prop_value or 'DAC' in prop_value or 'OSC' in prop_value: + pads[pad_port][pad_num]["MODER"] = PIN_MODE_ANALOG + elif 'GPIO_Output' == prop_value: + pads[pad_port][pad_num]["MODER"] = PIN_MODE_OUTPUT + elif 'GPIO_Input' == prop_value: + pads[pad_port][pad_num]["MODER"] = PIN_MODE_INPUT + else: + pads[pad_port][pad_num]["SIGNAL"] = prop_value + pads[pad_port][pad_num]["MODER"] = PIN_MODE_ALTERNATE + pads[pad_port][pad_num]["OSPEEDR"] = PIN_OSPEED_MEDIUM + elif pad_prop == "GPIO_Mode": + pads[pad_port][pad_num]["MODER"] = PIN_MODE_TRANSLATE[prop_value] + elif pad_prop == "GPIO_Label": + pads[pad_port][pad_num]["LABEL"] = prop_value + elif pad_prop == "GPIO_PuPd": + pads[pad_port][pad_num]["PUPDR"] = PIN_PUPDR_TRANSLATE[prop_value] + elif pad_prop == "GPIO_ModeDefaultOutputPP": + pads[pad_port][pad_num]["OTYPER"] = PIN_OTYPE_TRANSLATE[prop_value] + pads[pad_port][pad_num]["MODER"] = PIN_MODE_OUTPUT + elif pad_prop == "GPIO_Speed": + pads[pad_port][pad_num]["OSPEEDR"] = PIN_OSPEED_TRANSLATE[prop_value] + + return pads + + +# Add defines for all pins with labels +def gen_defines(project): + defines = {} + + for port_key in sorted(project.keys()): + for pad_key in sorted(project[port_key].keys()): + + pad_data = project[port_key][pad_key] + if pad_data['SIGNAL'] != 'UNUSED' and not pad_data['LABEL']: + pad_data['LABEL'] = pad_data['SIGNAL'] + pad_data['LABEL'] = pad_data['LABEL'].replace('-', '_') + label = pad_data['LABEL'] + signal = pad_data['SIGNAL'] + if not label: + continue + + defines['PORT_'+label] = 'GPIO' + port_key + defines['PAD_'+label] = pad_key + + if re.search(r"TIM\d_CH\d", signal, re.M): + timer = signal.replace('S_TIM', '').replace('_CH', '')[:-1] + ch_num = int(signal[-1:]) + + defines['TIM_' + label] = timer + defines['CCR_' + label] = 'CCR' + timer[-1] + defines['PWMD_' + label] = 'PWMD' + timer[-1] + defines['ICUD_' + label] = 'ICUD' + timer[-1] + defines['CHN_' + label] = ch_num - 1 + + return defines + + +# Each Port (A.B.C...) +def gen_ports(gpio, project): + ports = {} + for port_key in sorted(project.keys()): + + ports[port_key] = {} + # Each property (mode, output/input...) + for conf in PIN_CONF_LIST: + ports[port_key][conf] = [] + for pin in project[port_key]: + out = project[port_key][pin][conf] + out = out.format(pin) + ports[port_key][conf].append(out) + + conf = PIN_CONF_LIST_AF[0] + ports[port_key][conf] = [] + for pin in range(0, 8): + try: + af = project[port_key][pin]['SIGNAL'] + out = PIN_AFIO_AF.format(pin, gpio['ports'][port_key][pin][af]) + except KeyError as e: + out = PIN_AFIO_AF.format(pin, 0) + ports[port_key][conf].append(out) + + conf = PIN_CONF_LIST_AF[1] + ports[port_key][conf] = [] + for pin in range(8, 16): + try: + af = project[port_key][pin]['SIGNAL'] + out = PIN_AFIO_AF.format(pin, gpio['ports'][port_key][pin][af]) + except KeyError: + out = PIN_AFIO_AF.format(pin, 0) + ports[port_key][conf].append(out) + + return ports + + +if __name__ == '__main__': + args = parser.parse_args() + gpio = read_gpio(args.gpio) + proj = read_project(gpio, args.project) + defines = gen_defines(proj) + ports = gen_ports(gpio, proj) + + with open('board_gpio.tpl', 'r') as tpl_file: + tpl = tpl_file.read() + template = Template(tpl) + + defines_sorted = [] + for d in sorted(defines.keys()): + defines_sorted.append((d, defines[d])) + + ports_sorted = [] + for p in sorted(ports.keys()): + ports_sorted.append((p, ports[p])) + + template.stream(defines=defines_sorted, ports=ports_sorted).dump(args.output) -- cgit v1.2.3