2017-04-09 21:53:07 -07:00
|
|
|
# This file is a mess, but does the job
|
|
|
|
|
|
|
|
import xml.etree.ElementTree as ET
|
|
|
|
import os.path
|
|
|
|
from os import listdir
|
|
|
|
import sys
|
|
|
|
import re
|
|
|
|
|
|
|
|
cubemx_dir = 'D:\programs\STM32Cube\STM32CubeMX'
|
|
|
|
|
|
|
|
stm32_dir = '../../STM32/cores/arduino/stm32/'
|
|
|
|
system_dir = '../../STM32/system/'
|
|
|
|
header_lines = []
|
|
|
|
|
|
|
|
with open(system_dir + 'STM32F0/CMSIS_Inc/stm32f0xx.h') as f:
|
|
|
|
header_lines.extend(f.readlines())
|
|
|
|
with open(system_dir + 'STM32F1/CMSIS_Inc/stm32f1xx.h') as f:
|
|
|
|
header_lines.extend(f.readlines())
|
|
|
|
with open(system_dir + 'STM32F2/CMSIS_Inc/stm32f2xx.h') as f:
|
|
|
|
header_lines.extend(f.readlines())
|
|
|
|
with open(system_dir + 'STM32F3/CMSIS_Inc/stm32f3xx.h') as f:
|
|
|
|
header_lines.extend(f.readlines())
|
|
|
|
with open(system_dir + 'STM32F4/CMSIS_Inc/stm32f4xx.h') as f:
|
|
|
|
header_lines.extend(f.readlines())
|
|
|
|
with open(system_dir + 'STM32F7/CMSIS_Inc/stm32f7xx.h') as f:
|
|
|
|
header_lines.extend(f.readlines())
|
|
|
|
with open(system_dir + 'STM32L0/CMSIS_Inc/stm32l0xx.h') as f:
|
|
|
|
header_lines.extend(f.readlines())
|
|
|
|
with open(system_dir + 'STM32L1/CMSIS_Inc/stm32l1xx.h') as f:
|
|
|
|
header_lines.extend(f.readlines())
|
|
|
|
with open(system_dir + 'STM32L4/CMSIS_Inc/stm32l4xx.h') as f:
|
|
|
|
header_lines.extend(f.readlines())
|
|
|
|
|
|
|
|
def find_header(name):
|
|
|
|
include = False
|
|
|
|
define = False
|
|
|
|
for line in header_lines:
|
|
|
|
if '/* #define' in line:
|
|
|
|
define = line[line.index('#define ')+8:][:11]
|
|
|
|
|
|
|
|
if '#endif' in line:
|
|
|
|
define = False
|
|
|
|
|
|
|
|
if not define:
|
|
|
|
continue
|
|
|
|
|
|
|
|
if (name in line):
|
|
|
|
include = define
|
|
|
|
break
|
|
|
|
if ((name[:-2] + "x" + name[-1:]) in line):
|
|
|
|
include = define
|
|
|
|
break
|
2017-04-10 21:30:57 -07:00
|
|
|
|
|
|
|
if not include:
|
|
|
|
define = False
|
|
|
|
for line in header_lines:
|
|
|
|
if '/* #define' in line:
|
|
|
|
define = line[line.index('#define ')+8:][:11]
|
|
|
|
|
|
|
|
if '#endif' in line:
|
|
|
|
define = False
|
|
|
|
|
|
|
|
if not define:
|
|
|
|
continue
|
|
|
|
|
|
|
|
if ((name[:-2] + "xx") in line):
|
|
|
|
include = define
|
|
|
|
break
|
|
|
|
|
2017-04-09 21:53:07 -07:00
|
|
|
if not include:
|
|
|
|
raise Exception(name)
|
|
|
|
|
|
|
|
return include
|
|
|
|
|
|
|
|
|
|
|
|
families_xml = os.path.join(cubemx_dir, 'db', 'mcu', 'families.xml')
|
|
|
|
if not os.path.exists(families_xml):
|
|
|
|
print 'Could not find CubeMX, please set CubeMX directory'
|
|
|
|
exit(-1)
|
|
|
|
families = ET.parse(families_xml).getroot()
|
|
|
|
ns = {'stm': 'http://mcd.rou.st.com/modules.php?name=mcu'}
|
|
|
|
|
|
|
|
mcus = families.findall(".//Mcu")
|
|
|
|
|
|
|
|
|
2017-04-14 12:37:01 -07:00
|
|
|
def natural_sort_key(s, _nsre=re.compile('([0-9]+)')):
|
|
|
|
return [int(text) if text.isdigit() else text.lower()
|
|
|
|
for text in re.split(_nsre, s)]
|
2017-04-09 21:53:07 -07:00
|
|
|
class load_mcu:
|
|
|
|
def __init__(self, name):
|
|
|
|
print name
|
|
|
|
|
|
|
|
self.mcu_name = name
|
|
|
|
|
|
|
|
if families.find(".//Mcu[@RefName='" + self.mcu_name + "Tx']") is not None:
|
|
|
|
self.mcu_xml = families.find(".//Mcu[@RefName='" + self.mcu_name + "Tx']").attrib['Name'] + '.xml'
|
|
|
|
else:
|
|
|
|
self.mcu_xml = families.find(".//Mcu[@RPN='" + self.mcu_name + "']").attrib['Name'] + '.xml'
|
|
|
|
|
|
|
|
self.mcu = ET.parse(os.path.join(cubemx_dir, 'db', 'mcu', self.mcu_xml)).getroot()
|
|
|
|
self.remap_xml = 'GPIO-' + self.mcu.find("stm:IP[@Name='GPIO']", ns).attrib['Version'] + '_Modes.xml'
|
|
|
|
|
|
|
|
self.remap_root = ET.parse(os.path.join(cubemx_dir, 'db', 'mcu', 'IP', self.remap_xml )).getroot()
|
|
|
|
|
|
|
|
self.mcu_pins = self.mcu.findall('stm:Pin', ns);
|
|
|
|
|
|
|
|
self.remaps = {}
|
|
|
|
self.defaultremaps = {}
|
|
|
|
self.af_functions=[]
|
|
|
|
self.pins = []
|
|
|
|
self.peripherals = []
|
|
|
|
self.groups = {}
|
|
|
|
self.group_signals = {}
|
2017-04-11 21:15:09 -07:00
|
|
|
|
|
|
|
def load_rcc(self):
|
|
|
|
self.rcc_xml = 'RCC-' + self.mcu.find("stm:IP[@Name='RCC']", ns).attrib['Version'] + '_Modes.xml'
|
|
|
|
|
|
|
|
self.rcc_root = ET.parse(os.path.join(cubemx_dir, 'db', 'mcu', 'IP', self.rcc_xml )).getroot()
|
|
|
|
|
|
|
|
pclk1 = self.rcc_root.find(".//stm:RefParameter[@Name='APB1Freq_Value']", ns)
|
|
|
|
pclk2 = self.rcc_root.find("stm:RefParameter[@Name='APB2Freq_Value']", ns)
|
|
|
|
|
|
|
|
if pclk1 is not None:
|
|
|
|
self.PCLK1_PERIPHERALS = pclk1.attrib['IP'].split(',')
|
|
|
|
else:
|
|
|
|
self.PCLK1_PERIPHERALS = []
|
|
|
|
|
|
|
|
if pclk2 is not None:
|
|
|
|
self.PCLK2_PERIPHERALS = pclk2.attrib['IP'].split(',')
|
|
|
|
else:
|
|
|
|
self.PCLK2_PERIPHERALS = []
|
|
|
|
|
2017-04-09 21:53:07 -07:00
|
|
|
def find_remaps(self):
|
|
|
|
for pin in self.remap_root.findall('stm:GPIO_Pin', ns):
|
|
|
|
pin_name = pin.attrib['Name']
|
|
|
|
|
|
|
|
pin_name = re.search('^(\D*\d*)', pin_name).group(1)
|
|
|
|
|
|
|
|
gpio_signals = pin.findall('stm:PinSignal', ns)
|
|
|
|
for gpio_signal in gpio_signals:
|
|
|
|
signal = gpio_signal.attrib['Name']
|
|
|
|
|
|
|
|
periph = signal.split('_')[0]
|
|
|
|
if signal not in self.remaps:
|
|
|
|
self.remaps[signal] = {}
|
|
|
|
|
|
|
|
if self.mcu_name.startswith('STM32F1'):
|
|
|
|
remap_function = False
|
|
|
|
|
|
|
|
remap_block = gpio_signal.find('stm:RemapBlock', ns)
|
|
|
|
if remap_block is not None:
|
|
|
|
if 'DefaultRemap' in remap_block.attrib:
|
|
|
|
remap_function = 'AF__HAL_AFIO_REMAP_' + periph + '_DISABLE'
|
|
|
|
self.defaultremaps[signal] = pin_name
|
|
|
|
else:
|
|
|
|
remap_function = 'AF' + remap_block.find('stm:SpecificParameter', ns).find('stm:PossibleValue', ns).text
|
|
|
|
else:
|
|
|
|
remap_function = 'AF__NO_REMAP'
|
|
|
|
if signal not in self.defaultremaps:
|
|
|
|
self.defaultremaps[signal] = pin_name
|
|
|
|
|
|
|
|
self.remaps[signal][pin_name] = remap_function
|
|
|
|
if remap_function not in self.af_functions:
|
|
|
|
self.af_functions.append(remap_function)
|
|
|
|
|
|
|
|
else:
|
|
|
|
gpio_af = gpio_signal.find("stm:SpecificParameter[@Name='GPIO_AF']", ns)
|
|
|
|
self.remaps[signal][pin_name] = gpio_af.find("stm:PossibleValue", ns).text
|
|
|
|
|
|
|
|
def process_pins(self):
|
|
|
|
for pin in self.mcu_pins:
|
|
|
|
pin_name = pin.attrib['Name']
|
|
|
|
|
|
|
|
pin_name = re.search('^(\D*\d*)', pin_name).group(1)
|
|
|
|
|
|
|
|
self.pins.append(pin_name)
|
|
|
|
|
|
|
|
if not pin.attrib['Type'] == 'I/O':
|
|
|
|
continue
|
|
|
|
|
|
|
|
signals = pin.findall('stm:Signal', ns)
|
|
|
|
for signal_element in signals:
|
|
|
|
signal = signal_element.attrib['Name']
|
|
|
|
if not signal.startswith('USART') \
|
|
|
|
and not signal.startswith('SPI') \
|
|
|
|
and not signal.startswith('I2C') \
|
2017-04-15 01:25:11 -07:00
|
|
|
and not signal.startswith('TIM') \
|
|
|
|
and not signal.startswith('ADC1') \
|
|
|
|
and not signal.startswith('ADC_'):
|
2017-04-09 21:53:07 -07:00
|
|
|
continue
|
|
|
|
|
|
|
|
(periph, sig) = signal.split('_', 1)
|
|
|
|
|
|
|
|
if periph not in self.peripherals:
|
|
|
|
self.peripherals.append(periph)
|
|
|
|
|
|
|
|
self.groups.setdefault(periph[:-1], []).append(sig)
|
|
|
|
|
|
|
|
self.group_signals.setdefault(periph[:-1] + '_' + sig, []).append(signal)
|
|
|
|
|
|
|
|
if signal not in self.defaultremaps:
|
|
|
|
self.defaultremaps[signal] = pin_name
|
|
|
|
|
|
|
|
if signal not in self.remaps:
|
|
|
|
self.remaps[signal] = {}
|
|
|
|
self.remaps[signal][pin_name] = 'AF_NO_REMAP'
|
|
|
|
|
|
|
|
def generate_source_code(self):
|
|
|
|
self.peripherals.sort()
|
|
|
|
|
|
|
|
self.af_functions.sort()
|
|
|
|
|
|
|
|
source_code = '';
|
|
|
|
source_code = '//Autogenerated file\n'
|
|
|
|
source_code += '//MCU name: ' + self.mcu_name+ '\n'
|
|
|
|
source_code += '//MCU xml: ' + self.mcu_xml+ '\n'
|
|
|
|
source_code += '//GPIO remap/alternate function xml: ' + self.remap_xml+ '\n'
|
|
|
|
|
|
|
|
source_code += '\n'
|
|
|
|
|
|
|
|
gpio_pins = [pin for pin in self.pins if pin.startswith('P') and pin != 'PDR_ON']
|
|
|
|
|
|
|
|
source_code += '/*\n'
|
|
|
|
source_code += 'const stm32_port_pin_type port_pin_list[] = {\n'
|
|
|
|
|
|
|
|
for pin in sorted(gpio_pins, key=lambda x: (x[0:2], int(x[2:]))):
|
|
|
|
source_code += ' { GPIO' + pin[1:2] + ', GPIO_PIN_' + pin[2:].ljust(2) + '},\n'
|
|
|
|
|
|
|
|
source_code += '};\n'
|
|
|
|
source_code += '*/\n'
|
|
|
|
source_code += '\n'
|
|
|
|
source_code += '/*\n'
|
|
|
|
source_code += 'enum {\n'
|
|
|
|
for pin in sorted(gpio_pins, key=lambda x: (x[0:2], int(x[2:]))):
|
|
|
|
source_code += ' ' + pin.ljust(4) + ',\n'
|
|
|
|
source_code += 'NUM_PINS,\n'
|
|
|
|
source_code += '};\n'
|
|
|
|
source_code += '*/\n'
|
|
|
|
|
|
|
|
if len(self.af_functions) > 0:
|
|
|
|
source_code += 'static void AF_NO_REMAP (void) { }\n'
|
|
|
|
|
|
|
|
for af_function in self.af_functions:
|
|
|
|
source_code += 'static void ' + af_function + '(void) { ' + af_function[2:] + '(); }\n'
|
|
|
|
|
2017-04-15 01:25:11 -07:00
|
|
|
|
2017-04-09 21:53:07 -07:00
|
|
|
for periph in sorted(self.groups):
|
|
|
|
for sig in sorted(set(self.groups[periph])):
|
2017-04-15 01:25:11 -07:00
|
|
|
|
|
|
|
if sig not in ['SDA', 'SCL', 'TX', 'RX', 'MISO', 'MOSI', 'SCK']:
|
2017-04-09 21:53:07 -07:00
|
|
|
continue
|
|
|
|
|
|
|
|
source_code += '\n'
|
2017-04-11 21:15:09 -07:00
|
|
|
source_code += 'const stm32_af_pin_list_type chip_af_'+(periph + '_' + sig).lower()+' [] = {\n'
|
2017-04-09 21:53:07 -07:00
|
|
|
#print self.group_signals
|
|
|
|
old = False
|
|
|
|
for signal in sorted(set(self.group_signals[periph + '_' +sig])):
|
|
|
|
if old != signal.split('_')[0]:
|
|
|
|
source_code += '//' + signal.split('_')[0] + '\n'
|
|
|
|
p = signal.split('_')[0]
|
2017-04-14 12:37:01 -07:00
|
|
|
for pin in sorted(set(self.remaps[signal]), key = natural_sort_key):
|
2017-04-09 21:53:07 -07:00
|
|
|
if pin in self.pins:
|
|
|
|
remap = self.remaps[signal][pin]
|
|
|
|
|
|
|
|
split = signal.split('_')
|
|
|
|
p = split[0]
|
|
|
|
|
|
|
|
source_code += ' { ' + p.ljust(6) + ', GPIO' + pin[1:2] + ', GPIO_PIN_' + pin[2:].ljust(3) + ', ' + remap.ljust(15) + '}, \n'
|
|
|
|
|
|
|
|
source_code += '}; \n'
|
2017-04-11 21:15:09 -07:00
|
|
|
|
|
|
|
source_code += '\n'
|
|
|
|
|
2017-04-15 01:25:11 -07:00
|
|
|
source_code += 'const stm32_chip_adc1_channel_type chip_adc1_channel[] = {\n'
|
|
|
|
|
|
|
|
for instance_signal in sorted(self.defaultremaps.keys(), key = natural_sort_key):
|
|
|
|
if 'ADC1_IN' not in instance_signal and 'ADC_IN' not in instance_signal:
|
|
|
|
continue
|
|
|
|
|
|
|
|
(_, channel) = instance_signal.split('_', 1)
|
|
|
|
pin = self.defaultremaps[instance_signal]
|
|
|
|
source_code += ' { GPIO' + pin[1:2] + ', GPIO_PIN_' + pin[2:].ljust(3) + ', ADC_CHANNEL_' + channel[2:].ljust(3) + '}, \n'
|
|
|
|
|
|
|
|
source_code += '};\n'
|
|
|
|
source_code += '\n'
|
|
|
|
|
|
|
|
source_code += 'const stm32_clock_freq_list_type chip_clock_freq_list[] = {\n'
|
2017-04-11 21:15:09 -07:00
|
|
|
for periph in sorted(self.PCLK1_PERIPHERALS):
|
|
|
|
if not periph.startswith('USART') and not periph.startswith('SPI') and not periph.startswith('I2C'):
|
|
|
|
continue
|
2017-04-09 21:53:07 -07:00
|
|
|
|
2017-04-11 21:15:09 -07:00
|
|
|
if periph not in self.peripherals:
|
|
|
|
continue
|
|
|
|
|
2017-04-15 01:25:11 -07:00
|
|
|
source_code += ' {' + periph.ljust(6) + ', HAL_RCC_GetPCLK1Freq }, \n'
|
2017-04-11 21:15:09 -07:00
|
|
|
|
|
|
|
source_code += '\n'
|
|
|
|
|
|
|
|
for periph in sorted(self.PCLK2_PERIPHERALS):
|
|
|
|
if not periph.startswith('USART') and not periph.startswith('SPI') and not periph.startswith('I2C'):
|
|
|
|
continue
|
|
|
|
|
|
|
|
if periph not in self.peripherals:
|
|
|
|
continue
|
2017-04-09 21:53:07 -07:00
|
|
|
|
2017-04-15 01:25:11 -07:00
|
|
|
source_code += ' {' + periph.ljust(6) + ', HAL_RCC_GetPCLK2Freq }, \n'
|
2017-04-09 21:53:07 -07:00
|
|
|
|
2017-04-11 21:15:09 -07:00
|
|
|
source_code += '};\n'
|
|
|
|
source_code += '\n'
|
2017-04-09 21:53:07 -07:00
|
|
|
|
|
|
|
dir = system_dir + name[:7] + "/stm32_chip/"
|
|
|
|
with open(dir + 'stm32_' + self.mcu_name + '.h', 'w') as file:
|
|
|
|
file.write(source_code)
|
|
|
|
|
|
|
|
|
|
|
|
with open(stm32_dir + 'stm32_build_defines.h', 'w') as file:
|
|
|
|
file.write('//Autogenerated file\n')
|
|
|
|
file.write('\n')
|
|
|
|
file.write('#ifndef STM32_BUILD_DEFINES_H\n')
|
|
|
|
file.write('#define STM32_BUILD_DEFINES_H\n')
|
|
|
|
file.write('\n')
|
|
|
|
|
|
|
|
name_processed = []
|
2017-04-10 21:30:57 -07:00
|
|
|
|
|
|
|
file.write('#if __IGNORE\n')
|
|
|
|
|
2017-04-09 21:53:07 -07:00
|
|
|
for mcu in mcus:
|
|
|
|
name = mcu.attrib['RefName']
|
|
|
|
name = name[:11]
|
|
|
|
|
|
|
|
if name in name_processed:
|
|
|
|
continue
|
|
|
|
name_processed.append(name)
|
|
|
|
|
|
|
|
dir = system_dir + name[:7] + "/CMSIS_Inc/"
|
|
|
|
#filename = name.lower()
|
|
|
|
define = find_header(name)
|
|
|
|
|
|
|
|
file.write('\n');
|
2017-04-10 21:30:57 -07:00
|
|
|
file.write('#elif defined(' + name + ')\n')
|
|
|
|
file.write(' #define ' + define + ' 1\n')
|
2017-04-09 21:53:07 -07:00
|
|
|
file.write(' #define CMSIS_STARTUP_ASSEMBLY "startup_' + define.lower() + '.s"\n')
|
|
|
|
file.write(' #define CHIP_PERIPHERAL_INCLUDE "stm32_' + name + '.h"\n')
|
|
|
|
|
|
|
|
mcu = load_mcu(name)
|
2017-04-11 21:15:09 -07:00
|
|
|
mcu.load_rcc()
|
2017-04-09 21:53:07 -07:00
|
|
|
mcu.find_remaps()
|
|
|
|
mcu.process_pins()
|
|
|
|
mcu.generate_source_code()
|
2017-04-10 21:30:57 -07:00
|
|
|
file.write('#else \n')
|
|
|
|
file.write('#error UNKNOWN CHIP \n')
|
|
|
|
file.write('#endif\n')
|
|
|
|
|
2017-04-09 21:53:07 -07:00
|
|
|
file.write('\n')
|
|
|
|
file.write('#endif')
|
|
|
|
|
|
|
|
|
|
|
|
|