Skip to content

Instantly share code, notes, and snippets.

@fpoussin
Last active September 23, 2017 03:16
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save fpoussin/3317dc197ef0857294f0 to your computer and use it in GitHub Desktop.
Save fpoussin/3317dc197ef0857294f0 to your computer and use it in GitHub Desktop.
#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
#!/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 GPIO header file from STM32CubeMX file.')
parser.add_argument('-g', '--gpio', default='GPIO-STM32F303_gpio_v1_0_Modes.xml', type=str)
parser.add_argument('-b', '--project', default='../../board/board.ioc', 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)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment