modm_data.cubemx.device_data
1# Copyright 2016, Fabian Greif 2# Copyright 2016, Niklas Hauser 3# SPDX-License-Identifier: MPL-2.0 4 5import os 6import re 7import logging 8from collections import defaultdict 9 10from ..owl.stmicro import did_from_string 11from ..utils import ext_path, XmlReader 12from . import stm32_data 13from ..cubehal import read_request_map as dmamux_request_map 14from . import peripherals 15 16LOGGER = logging.getLogger(__file__) 17 18 19_MCU_PATH = ext_path("stmicro/cubemx/mcu") 20_FAMILY_FILE = None 21 22def _family_file() -> XmlReader: 23 global _FAMILY_FILE 24 if _FAMILY_FILE is None: 25 _FAMILY_FILE = XmlReader(_MCU_PATH / "families.xml") 26 return _FAMILY_FILE 27 28 29# ============================= MULTIPLE DEVICES ============================== 30def _format_raw_devices(rawDevices): 31 TemperatureMap = {0: "6", 105: "7", 125: "3"} 32 devices = set() 33 for dev in rawDevices: 34 temp_max = dev.find("Temperature") 35 temp_max = "" if temp_max is None else temp_max.get("Max") 36 name = dev.get("RefName") 37 temp_max = int(float(temp_max)) if len(temp_max) else min(TemperatureMap) 38 for temp, value in TemperatureMap.items(): 39 if temp_max >= temp: 40 devices.add(name[:12] + value + name[13:]) 41 return sorted(list(devices)) 42 43 44def devices_from_family(family: str) -> list[str]: 45 """ 46 :param family: A STM32 family name, for example, F0, H7, G4. 47 :return: A list of device names belonging to a STM32 family. 48 """ 49 devices = _family_file().query(f'//Family[@Name="{family.upper()}"]/SubFamily/Mcu/@RefName') 50 devices = _format_raw_devices(devices) 51 LOGGER.info("Found devices of family '{}': {}".format(family, ", ".join(devices))) 52 return devices 53 54 55def devices_from_prefix(prefix: str) -> list[str]: 56 """ 57 :param prefix: A STM32 device prefix, for example, STM32, STM32H7, STM32G432. 58 :return: A list of device names starting with the prefix. 59 """ 60 devices = _family_file().query(f'//Family/SubFamily/Mcu[starts-with(@RefName,"{prefix.upper()}")]') 61 devices = _format_raw_devices(devices) 62 devices = [d for d in devices if not stm32_data.ignoreDevice(d)] 63 LOGGER.info("Found devices for prefix '{}': {}".format(prefix, ", ".join(devices))) 64 return list(sorted(devices)) 65 66def cubemx_device_list() -> list["modm_data.owl.DeviceIdentifier"]: 67 """ 68 :return: A list of all STM32 device identifiers. 69 """ 70 return [did_from_string(d) for d in devices_from_prefix("STM32")] 71 72 73# ============================= INDIVIDUAL DEVICE ============================= 74def devices_from_partname(partname: str) -> list[dict[str]]: 75 """ 76 Find the STM32 device name in the STM32CubeMX database and convert the data 77 into a device specific key-value mapping describing the hardware. 78 79 .. note:: 80 One partname may contain multiple devices, for example, multiple 81 asymmetric CPU cores like in the STM32H745 device. 82 83 :param partname: A full STM32 device name. 84 :return: a list of dictionaries containing a device specific data structure. 85 """ 86 deviceNames = _family_file().query('//Family/SubFamily/Mcu[starts-with(@RefName,"{}")]' 87 .format(partname[:12] + "x" + partname[13:])) 88 comboDeviceName = sorted([d.get("Name") for d in deviceNames])[0] 89 device_file = XmlReader(os.path.join(_MCU_PATH, comboDeviceName + ".xml")) 90 did = did_from_string(partname.lower()) 91 LOGGER.info("Parsing '{}'".format(did.string)) 92 93 # information about the core and architecture 94 cores = [c.text.lower().replace("arm ", "") for c in device_file.query('//Core')] 95 if len(cores) > 1: did.naming_schema += "@{core}" 96 devices = [_properties_from_id(comboDeviceName, device_file, did.copy(), c) for c in cores] 97 return [d for d in devices if d is not None] 98 99 100def _properties_from_id(comboDeviceName, device_file, did, core): 101 if core.endswith("m4") or core.endswith("m7") or core.endswith("m33"): 102 core += "f" 103 if did.family in ["h7"] or (did.family in ["f7"] and did.name not in ["45", "46", "56"]): 104 core += "d" 105 if "@" in did.naming_schema: 106 did.set("core", core[7:9]) 107 p = {"id": did, "core": core} 108 109 # Maximum operating frequency 110 max_frequency = float(device_file.query('//Frequency')[0].text) 111 # H7 dual-core devices run the M4 core at half the frequency as the M7 core 112 if did.get("core", "") == "m4": max_frequency /= 2.0; 113 p["max_frequency"] = int(max_frequency * 1e6) 114 115 # Information from the CMSIS headers 116 # stm_header = Header(did) 117 # if not stm_header.is_valid: 118 # LOGGER.error("CMSIS Header invalid for %s", did.string) 119 # return None 120 121 # flash and ram sizes 122 # The <ram> and <flash> can occur multiple times. 123 # they are "ordered" in the same way as the `(S-I-Z-E)` ids in the device combo name 124 # we must first find out which index the current did.size has inside `(S-I-Z-E)` 125 sizeIndexFlash = 0 126 sizeIndexRam = 0 127 128 match = re.search(r"\(.(-.)*\)", comboDeviceName) 129 if match: 130 sizeArray = match.group(0)[1:-1].lower().split("-") 131 sizeIndexFlash = sizeArray.index(did.size) 132 sizeIndexRam = sizeIndexFlash 133 134 rams = sorted([int(r.text) for r in device_file.query('//Ram')]) 135 if sizeIndexRam >= len(rams): 136 sizeIndexRam = len(rams) - 1 137 138 flashs = sorted([int(f.text) for f in device_file.query('//Flash')]) 139 if sizeIndexFlash >= len(flashs): 140 sizeIndexFlash = len(flashs) - 1 141 142 143 p["ram"] = rams[sizeIndexRam] * 1024 144 p["flash"] = flashs[sizeIndexFlash] * 1024 145 146 memories = [] 147 for (mem_name, mem_start, mem_size) in stm32_data.getMemoryForDevice(did, p["flash"], p["ram"]): 148 access = "rwx" 149 if did.family == "f4" and mem_name == "ccm": access = "rw"; 150 if "flash" in mem_name: access = "rx"; 151 memories.append({"name": mem_name, "access": access, "size": str(mem_size), 152 "start": "0x{:02X}".format(mem_start)}) 153 154 p["memories"] = memories 155 156 # packaging 157 package = device_file.query('//@Package')[0] 158 p["pin-count"] = re.findall(r"[0-9]+", package)[0] 159 p["package"] = re.findall(r"[A-Za-z\.]+", package)[0] 160 161 def clean_up_version(version): 162 match = re.search("v[1-9]_[0-9x]", version.replace(".", "_")) 163 if match: 164 version = match.group(0).replace("_", ".") 165 else: 166 pass 167 # print(version) 168 return version 169 170 modules = [] 171 dmaFile = None 172 for ip in device_file.query('//IP'): 173 # These IPs are all software modules, NOT hardware modules. Their version string is weird too. 174 software_ips = {"GFXSIMULATOR", "GRAPHICS", "FATFS", "TOUCHSENSING", "PDM2PCM", 175 "MBEDTLS", "FREERTOS", "CORTEX_M", "NVIC", "USB_DEVICE", 176 "USB_HOST", "LWIP", "LIBJPEG", "GUI_INTERFACE", "TRACER", 177 "FILEX", "LEVELX", "THREADX", "USBX", "LINKEDLIST", "NETXDUO"} 178 if any(ip.get("Name").upper().startswith(p) for p in software_ips): 179 continue 180 181 rversion = ip.get("Version") 182 module = (ip.get("Name"), ip.get("InstanceName"), clean_up_version(rversion)) 183 184 if module[0] == "DMA": 185 # lets load additional information about the DMA 186 dmaFile = XmlReader(os.path.join(_MCU_PATH, "IP", "DMA-" + rversion + "_Modes.xml")) 187 for rdma in dmaFile.query('//IP/ModeLogicOperator/Mode[starts-with(@Name,"DMA")]/@Name'): 188 for dma in rdma.split(","): 189 modules.append((module[0].lower(), dma.strip().lower(), module[2].lower())) 190 continue 191 if module[0].startswith("TIM"): 192 module = ("TIM",) + module[1:] 193 194 modules.append(tuple([m.lower() for m in module])) 195 196 modules.append( ("flash", "flash", "v1.0")) 197 modules = [m + peripherals.getPeripheralData(did, m) for m in modules] 198 199 p["modules"] = modules 200 LOGGER.debug("Available Modules are:\n" + _modulesToString(modules)) 201 instances = [m[1] for m in modules] 202 # print("\n".join(str(m) for m in modules)) 203 204 # p["stm_header"] = stm_header 205 # p["interrupts"] = stm_header.interrupt_table 206 # Flash latency table 207 # p["flash_latency"] = stm32_data.getFlashLatencyForDevice(did) 208 209 # lets load additional information about the GPIO IP 210 ip_file = device_file.query('//IP[@Name="GPIO"]')[0].get("Version") 211 ip_file = os.path.join(_MCU_PATH, "IP", "GPIO-" + ip_file + "_Modes.xml") 212 gpioFile = XmlReader(ip_file) 213 214 pins = device_file.query('//Pin[@Type="I/O"][starts-with(@Name,"P")]') 215 def raw_pin_sort(p): 216 port = p.get("Name")[1:2] 217 pin = p.get("Name")[:4] 218 if len(pin) > 3 and not pin[3].isdigit(): 219 pin = pin[:3] 220 return (port, int(pin[2:])) 221 pins = sorted(pins, key=raw_pin_sort) 222 # Remove package remaps from GPIO data (but not from package) 223 pins.sort(key=lambda p: "PINREMAP" not in p.get("Variant", "")) 224 225 gpios = [] 226 227 def pin_name(name): 228 name = name[:4] 229 if len(name) > 3 and not name[3].isdigit(): 230 name = name[:3] 231 return (name[1:2].lower(), name[2:].lower()) 232 233 # Find the remap pin pairs, if they exist 234 double_pinouts = defaultdict(list) 235 for pin in device_file.query('//Pin'): 236 double_pinouts[pin.get("Position")].append((pin.get("Name"), pin.get("Variant", "DEFAULT"))) 237 double_pinouts = {pos: {pin:variant for (pin, variant) in pins} 238 for pos, pins in double_pinouts.items() 239 if len(pins) > 1 and any("PINREMAP" in pin[1] for pin in pins)} 240 241 # Get the pinout for this package with correct remap variants 242 pinout = [] 243 for pin in device_file.query("//Pin"): 244 name = pin.get("Name") 245 pos = pin.get("Position") 246 pinv = { 247 "name": name, 248 "position": pos, 249 "type": pin.get("Type"), 250 } 251 variant = double_pinouts.get(pos, {}).get(name) 252 if (variant is not None and (pin.get("Type") != "I/O" or ( 253 pin_name(name)[0] in ['a'] and 254 pin_name(name)[1] in ['9', '10', '11', '12']))): 255 pinv["variant"] = "remap" if "PINREMAP" in variant else "remap-default" 256 pinout.append(pinv) 257 258 p["pinout"] = pinout 259 p["package"] = device_file.query("/Mcu/@Package")[0] 260 261 def split_af(af): 262 # entry 0 contains names without instance 263 # entry 1 contains names with instance 264 mdriv = [m for m in modules if af.startswith(m[0] + "_")] 265 minst = [m for m in modules if af.startswith(m[1] + "_")] 266 # print(af, mdriv, minst) 267 if len(minst) > 1: 268 LOGGER.warning("Ambiguos driver: {} {}".format(af, minst)) 269 exit(1) 270 271 minst = minst[0] if len(minst) else None 272 mdriv = mdriv[0] if len(mdriv) else None 273 274 driver = minst[0] if minst else (mdriv[0] if mdriv else None) 275 if not driver: 276 LOGGER.debug("Unknown driver: {}".format(af)) 277 instance = None 278 if minst and driver: 279 pinst = minst[1].replace(driver, "") 280 if len(pinst): instance = pinst; 281 if minst or mdriv: 282 name = af.replace((minst[1] if minst else mdriv[0]) + "_", "") 283 if not len(name): 284 LOGGER.error("Unknown name: {} {}".format(af, minst, mdriv)) 285 exit(1) 286 else: 287 name = af 288 289 return (driver, instance, name) 290 291 def split_multi_af(af): 292 af = af.replace("ir_", "irtim_") \ 293 .replace("crs_", "rcc_crs_") \ 294 .replace("timx_", "tim_") 295 if af == "cec": af = "hdmi_cec_cec"; 296 297 driver, instance, names = split_af(af) 298 rafs = [] 299 for name in names.split("-"): 300 rafs.append( (driver, instance, name) ) 301 return rafs 302 303 if dmaFile is not None: 304 dma_dumped = [] 305 dma_streams = defaultdict(lambda: defaultdict(lambda: defaultdict(list))) 306 dma_request_map = None 307 for sig in dmaFile.query('//ModeLogicOperator[@Name="XOR"]/Mode'): 308 name = rname = sig.get("Name") 309 if did.family == "wl" and rname in ["SAI1_A", "SAI1_B", "QUADSPI"]: 310 continue # CubeMX data is wrong, WL devices don't have these peripherals 311 312 parent = sig.getparent().getparent().get("Name") 313 instance = parent.split("_")[0][3:] 314 parent = parent.split("_")[1] 315 316 request = dmaFile.query('//RefMode[@Name="{}"]'.format(name))[0] 317 def rv(param, default=[]): 318 vls = request.xpath('./Parameter[@Name="{}"]/PossibleValue/text()'.format(param)) 319 if not len(vls): vls = default; 320 return vls 321 322 name = name.lower().split(":")[0] 323 if name == "memtomem": 324 continue 325 326 # Several corrections 327 name = name.replace("spdif_rx", "spdifrx") 328 if name.startswith("dac") and "_" not in name: name = "dac_{}".format(name); 329 if any(name == n for n in ["sdio", "sdmmc2", "sdmmc1"]): continue 330 if len(name.split("_")) < 2: name = "{}_default".format(name); 331 driver, inst, name = split_af(name) 332 333 if "[" in parent: 334 if dma_request_map is None: 335 dma_request_map = dmamux_request_map(did) 336 channel = dma_request_map[rname] 337 stream = instance = 0 338 p["dma_naming"] = (None, "request", "signal") 339 elif "Stream" in parent: 340 channel = rv("Channel", ["software"])[0].replace("DMA_CHANNEL_", "") 341 stream = parent.replace("Stream", "") 342 p["dma_naming"] = ("stream", "channel", "signal") 343 elif rv("Request"): 344 channel = rv("Request", ["software"])[0].replace("DMA_REQUEST_", "") 345 stream = parent.replace("Channel", "") 346 p["dma_naming"] = ("channel", "request", "signal") 347 else: 348 channel = parent.replace("Channel", "") 349 stream = channel 350 p["dma_naming"] = (None, "channel", "signal") 351 352 if driver is None: # peripheral is not part of this device 353 dma_dumped.append( (instance, stream, name) ) 354 continue 355 mode = [v[4:].lower() for v in rv("Mode")] 356 for sname in ([None] if name == "default" else name.split("/")): 357 signal = { 358 "driver": driver, 359 "name": sname, 360 "direction": [v[4:].replace("PERIPH", "p").replace("MEMORY", "m").replace("_TO_", "2") for v in rv("Direction")], 361 "mode": mode, 362 "increase": "ENABLE" in rv("PeriphInc", ["DMA_PINC_ENABLE"])[0], 363 } 364 if inst: signal["instance"] = inst; 365 remaps = stm32_data.getDmaRemap(did, instance, channel, driver, inst, sname) 366 if remaps: signal["remap"] = remaps; 367 dma_streams[instance][stream][channel].append(signal) 368 # print(instance, stream, channel) 369 # print(signal) 370 371 # Manually handle condition expressions from XML for 372 # (STM32F030CCTx|STM32F030RCTx) and (STM32F070CBTx|STM32F070RBTx) 373 if did.family in ['f0']: 374 if (did.name == '30' and did.size == 'c'): 375 dma_streams['1'].pop('6') 376 dma_streams['1'].pop('7') 377 dma_streams.pop('2') 378 if (did.name == '70' and did.size == 'b'): 379 dma_streams['1'].pop('6') 380 dma_streams['1'].pop('7') 381 382 # De-duplicate DMA signal entries 383 def deduplicate_list(l): 384 return [i for n, i in enumerate(l) if i not in l[n + 1:]] 385 for stream in dma_streams: 386 for channel in dma_streams[stream]: 387 for signal in dma_streams[stream][channel]: 388 dma_streams[stream][channel][signal] = deduplicate_list( 389 dma_streams[stream][channel][signal]) 390 391 # if p["dma_naming"][1] == "request": 392 # print(did, dmaFile.filename) 393 p["dma"] = dma_streams 394 if len(dma_dumped): 395 for instance, stream, name in sorted(dma_dumped): 396 LOGGER.debug("DMA{}#{}: dumping {}".format(instance, stream, name)) 397 398 # If DMAMUX is used, add DMAMUX to DMA peripheral channel mappings 399 if p["dma_naming"] == (None, "request", "signal"): 400 # There can be multiple "//RefParameter[@Name="Instance"]" nodes constrained by 401 # a <Condition> child node filtering by the STM32 die id 402 # Try to match a node with condition first, if nothing matches choose the default one 403 die_id = device_file.query('//Die')[0].text 404 q = '//RefParameter[@Name="Instance"]/Condition[@Expression="%s"]/../PossibleValue/@Value' % die_id 405 channels = dmaFile.query(q) 406 if len(channels) == 0: 407 # match channels from node without <Condition> child node 408 channels = dmaFile.query('//RefParameter[@Name="Instance" and not(Condition)]/PossibleValue/@Value') 409 410 mux_channels = [] 411 # H7 has "Stream" instead of "Channel" for DMAMUX1 412 mux_channel_regex = re.compile(r"DMA(?P<instance>([0-9]))_(Channel|Stream)(?P<channel>([0-9]+))") 413 for mux_ch_position, channel in enumerate(channels): 414 m = mux_channel_regex.match(channel) 415 assert m is not None 416 mux_channels.append({'position' : mux_ch_position, 417 'dma-instance' : int(m.group("instance")), 418 'dma-channel' : int(m.group("channel"))}) 419 p["dma_mux_channels"] = mux_channels 420 421 if did.family == "f1": 422 grouped_f1_signals = gpioFile.compactQuery('//GPIO_Pin/PinSignal/@Name') 423 424 _seen_gpio = set() 425 for pin in pins: 426 rname = pin.get("Name") 427 name = pin_name(rname) 428 429 # the analog channels are only available in the Mcu file, not the GPIO file 430 localSignals = device_file.compactQuery('//Pin[@Name="{}"]/Signal[not(@Name="GPIO")]/@Name'.format(rname)) 431 # print(name, localSignals) 432 altFunctions = [] 433 434 if did.family == "f1": 435 altFunctions = [ (s.lower(), "-1") for s in localSignals if s not in grouped_f1_signals] 436 else: 437 allSignals = gpioFile.compactQuery('//GPIO_Pin[@Name="{}"]/PinSignal/SpecificParameter[@Name="GPIO_AF"]/..'.format(rname)) 438 signalMap = { a.get("Name"): a[0][0].text.lower().replace("gpio_af", "")[:2].replace("_", "") for a in allSignals } 439 altFunctions = [ (s.lower(), (signalMap[s] if s in signalMap else "-1")) for s in localSignals ] 440 441 afs = [] 442 for af in altFunctions: 443 for raf in split_multi_af(af[0]): 444 naf = {} 445 naf["driver"], naf["instance"], naf["name"] = raf 446 naf["af"] = af[1] if int(af[1]) >= 0 else None 447 if "exti" in naf["name"]: continue; 448 afs.append(naf) 449 450 gpio = (name[0], name[1], afs) 451 if name not in _seen_gpio: 452 gpios.append(gpio) 453 _seen_gpio.add(name) 454 # print(gpio[0].upper(), gpio[1], afs) 455 # LOGGER.debug("{}{}: {} ->".format(gpio[0].upper(), gpio[1])) 456 457 remaps = {} 458 if did.family == "f1": 459 for remap in gpioFile.compactQuery('//GPIO_Pin/PinSignal/RemapBlock/@Name'): 460 module = remap.split("_")[0].lower() 461 config = remap.split("_")[1].replace("REMAP", "").replace("IREMAP", "") 462 mapping = stm32_data.getGpioRemapForModuleConfig(module, config) 463 464 mpins = [] 465 for pin in gpioFile.compactQuery('//GPIO_Pin/PinSignal/RemapBlock[@Name="{}"]/..'.format(remap)): 466 name = pin.getparent().get("Name")[:4].split("-")[0].split("/")[0].strip().lower() 467 pport, ppin = name[1:2], name[2:] 468 if not any([pp[0] == pport and pp[1] == ppin for pp in gpios]): 469 continue 470 mmm = {"port": pport, "pin": ppin} 471 driver, _, name = split_af(pin.get("Name").lower()) 472 if driver is None: continue; 473 mmm["name"] = name; 474 mpins.append(mmm) 475 476 if module not in remaps: 477 driver, instance, _ = split_af(module + "_lol") 478 if not driver: continue; 479 remaps[module] = { 480 "mask": mapping["mask"], 481 "position": mapping["position"], 482 "groups": {}, 483 "driver": driver, 484 "instance": instance, 485 } 486 if len(mpins) > 0: 487 remaps[module]["groups"][mapping["mapping"]] = mpins 488 LOGGER.debug("{:<20}{}".format(module + "_" + config, ["{}{}:{}".format(b["port"], b["pin"], b["name"]) for b in mpins])) 489 490 # import json 491 # print(json.dumps(remaps, indent=4)) 492 493 p["remaps"] = remaps 494 p["gpios"] = gpios 495 496 return p 497 498 499def _modulesToString(modules): 500 string = "" 501 mods = sorted(modules) 502 char = mods[0][0][0:1] 503 for _, instance, _, _, _, _ in mods: 504 if not instance.startswith(char): 505 string += "\n" 506 string += instance + " \t" 507 char = instance[0][0:1] 508 return string
LOGGER =
<Logger /opt/hostedtoolcache/Python/3.12.2/x64/lib/python3.12/site-packages/modm_data/cubemx/device_data.py (WARNING)>
def
devices_from_family(family: str) -> list[str]:
45def devices_from_family(family: str) -> list[str]: 46 """ 47 :param family: A STM32 family name, for example, F0, H7, G4. 48 :return: A list of device names belonging to a STM32 family. 49 """ 50 devices = _family_file().query(f'//Family[@Name="{family.upper()}"]/SubFamily/Mcu/@RefName') 51 devices = _format_raw_devices(devices) 52 LOGGER.info("Found devices of family '{}': {}".format(family, ", ".join(devices))) 53 return devices
Parameters
- family: A STM32 family name, for example, F0, H7, G4.
Returns
A list of device names belonging to a STM32 family.
def
devices_from_prefix(prefix: str) -> list[str]:
56def devices_from_prefix(prefix: str) -> list[str]: 57 """ 58 :param prefix: A STM32 device prefix, for example, STM32, STM32H7, STM32G432. 59 :return: A list of device names starting with the prefix. 60 """ 61 devices = _family_file().query(f'//Family/SubFamily/Mcu[starts-with(@RefName,"{prefix.upper()}")]') 62 devices = _format_raw_devices(devices) 63 devices = [d for d in devices if not stm32_data.ignoreDevice(d)] 64 LOGGER.info("Found devices for prefix '{}': {}".format(prefix, ", ".join(devices))) 65 return list(sorted(devices))
Parameters
- prefix: A STM32 device prefix, for example, STM32, STM32H7, STM32G432.
Returns
A list of device names starting with the prefix.
67def cubemx_device_list() -> list["modm_data.owl.DeviceIdentifier"]: 68 """ 69 :return: A list of all STM32 device identifiers. 70 """ 71 return [did_from_string(d) for d in devices_from_prefix("STM32")]
Returns
A list of all STM32 device identifiers.
def
devices_from_partname(partname: str) -> list[dict[str]]:
75def devices_from_partname(partname: str) -> list[dict[str]]: 76 """ 77 Find the STM32 device name in the STM32CubeMX database and convert the data 78 into a device specific key-value mapping describing the hardware. 79 80 .. note:: 81 One partname may contain multiple devices, for example, multiple 82 asymmetric CPU cores like in the STM32H745 device. 83 84 :param partname: A full STM32 device name. 85 :return: a list of dictionaries containing a device specific data structure. 86 """ 87 deviceNames = _family_file().query('//Family/SubFamily/Mcu[starts-with(@RefName,"{}")]' 88 .format(partname[:12] + "x" + partname[13:])) 89 comboDeviceName = sorted([d.get("Name") for d in deviceNames])[0] 90 device_file = XmlReader(os.path.join(_MCU_PATH, comboDeviceName + ".xml")) 91 did = did_from_string(partname.lower()) 92 LOGGER.info("Parsing '{}'".format(did.string)) 93 94 # information about the core and architecture 95 cores = [c.text.lower().replace("arm ", "") for c in device_file.query('//Core')] 96 if len(cores) > 1: did.naming_schema += "@{core}" 97 devices = [_properties_from_id(comboDeviceName, device_file, did.copy(), c) for c in cores] 98 return [d for d in devices if d is not None]
Find the STM32 device name in the STM32CubeMX database and convert the data into a device specific key-value mapping describing the hardware.
One partname may contain multiple devices, for example, multiple asymmetric CPU cores like in the STM32H745 device.
Parameters
- partname: A full STM32 device name.
Returns
a list of dictionaries containing a device specific data structure.