modm_data.atdf.avr
1# Copyright 2013, Niklas Hauser 2# Copyright 2016, Fabian Greif 3# SPDX-License-Identifier: MPL-2.0 4 5import logging 6from pathlib import Path 7 8from ..utils import ext_path, XmlReader 9from .identifier import avr_did_from_string 10 11LOGGER = logging.getLogger(__name__) 12_ATDF_PATH = ext_path("microchip/avr") 13 14# Data is from avrdude v6.3 15avrdude_mcu_map = { 16 "at90s1200": "1200", 17 "at90s2313": "2313", 18 "at90s2333": "2333", 19 "at90s2343": "2343", 20 "at90s4414": "4414", 21 "at90s4433": "4433", 22 "at90s4434": "4434", 23 "at90s8515": "8515", 24 "at90s8535": "8535", 25 "at90can128": "c128", 26 "at90can32": "c32", 27 "at90can64": "c64", 28 "at90pwm216": "pwm216", 29 "at90pwm2": "pwm2", 30 "at90pwm2b": "pwm2b", 31 "at90pwm3": "pwm3", 32 "at90pwm316": "pwm316", 33 "at90pwm3b": "pwm3b", 34 "at90usb1286": "usb1286", 35 "at90usb1287": "usb1287", 36 "at90usb162": "usb162", 37 "at90usb646": "usb646", 38 "at90usb647": "usb647", 39 "at90usb82": "usb82", 40 "atmega103": "m103", 41 "atmega128": "m128", 42 "atmega1280": "m1280", 43 "atmega1281": "m1281", 44 "atmega1284": "m1284", 45 "atmega1284p": "m1284p", 46 "atmega1284rfr2": "m1284rfr2", 47 "atmega128rfa1": "m128rfa1", 48 "atmega128rfr2": "m128rfr2", 49 "atmega16": "m16", 50 "atmega161": "m161", 51 "atmega162": "m162", 52 "atmega163": "m163", 53 "atmega164p": "m164p", 54 "atmega168": "m168", 55 "atmega168p": "m168p", 56 "atmega168pb": "m168pb", 57 "atmega169": "m169", 58 "atmega16u2": "m16u2", 59 "atmega2560": "m2560", 60 "atmega2561": "m2561", 61 "atmega2564rfr2": "m2564rfr2", 62 "atmega256rfr2": "m256rfr2", 63 "atmega32": "m32", 64 "atmega324p": "m324p", 65 "atmega324pa": "m324pa", 66 "atmega325": "m325", 67 "atmega3250": "m3250", 68 "atmega328": "m328", 69 "atmega328p": "m328p", 70 "atmega329": "m329", 71 "atmega3290": "m3290", 72 "atmega3290p": "m3290p", 73 "atmega329p": "m329p", 74 "atmega32m1": "m32m1", 75 "atmega32u2": "m32u2", 76 "atmega32u4": "m32u4", 77 "atmega406": "m406", 78 "atmega48": "m48", 79 "atmega48p": "m48p", 80 "atmega48pb": "m48pb", 81 "atmega64": "m64", 82 "atmega640": "m640", 83 "atmega644": "m644", 84 "atmega644p": "m644p", 85 "atmega644rfr2": "m644rfr2", 86 "atmega645": "m645", 87 "atmega6450": "m6450", 88 "atmega649": "m649", 89 "atmega6490": "m6490", 90 "atmega64rfr2": "m64rfr2", 91 "atmega8": "m8", 92 "atmega8515": "m8515", 93 "atmega8535": "m8535", 94 "atmega88": "m88", 95 "atmega88p": "m88p", 96 "atmega88pb": "m88pb", 97 "atmega8u2": "m8u2", 98 "attiny10": "t10", 99 "attiny11": "t11", 100 "attiny12": "t12", 101 "attiny13": "t13", 102 "attiny15": "t15", 103 "attiny1634": "t1634", 104 "attiny20": "t20", 105 "attiny2313": "t2313", 106 "attiny24": "t24", 107 "attiny25": "t25", 108 "attiny26": "t26", 109 "attiny261": "t261", 110 "attiny28": "t28", 111 "attiny4": "t4", 112 "attiny40": "t40", 113 "attiny4313": "t4313", 114 "attiny43u": "t43u", 115 "attiny44": "t44", 116 "attiny45": "t45", 117 "attiny461": "t461", 118 "attiny5": "t5", 119 "attiny84": "t84", 120 "attiny85": "t85", 121 "attiny861": "t861", 122 "attiny88": "t88", 123 "attiny9": "t9", 124 "atxmega128a1": "x128a1", 125 "atxmega128a1revd": "x128a1d", 126 "atxmega128a1u": "x128a1u", 127 "atxmega128a3": "x128a3", 128 "atxmega128a3u": "x128a3u", 129 "atxmega128a4": "x128a4", 130 "atxmega128a4u": "x128a4u", 131 "atxmega128b1": "x128b1", 132 "atxmega128b3": "x128b3", 133 "atxmega128c3": "x128c3", 134 "atxmega128d3": "x128d3", 135 "atxmega128d4": "x128d4", 136 "atxmega16a4": "x16a4", 137 "atxmega16a4u": "x16a4u", 138 "atxmega16c4": "x16c4", 139 "atxmega16d4": "x16d4", 140 "atxmega16e5": "x16e5", 141 "atxmega192a1": "x192a1", 142 "atxmega192a3": "x192a3", 143 "atxmega192a3u": "x192a3u", 144 "atxmega192c3": "x192c3", 145 "atxmega192d3": "x192d3", 146 "atxmega256a1": "x256a1", 147 "atxmega256a3": "x256a3", 148 "atxmega256a3b": "x256a3b", 149 "atxmega256a3bu": "x256a3bu", 150 "atxmega256a3u": "x256a3u", 151 "atxmega256c3": "x256c3", 152 "atxmega256d3": "x256d3", 153 "atxmega32a4": "x32a4", 154 "atxmega32a4u": "x32a4u", 155 "atxmega32c4": "x32c4", 156 "atxmega32d4": "x32d4", 157 "atxmega32e5": "x32e5", 158 "atxmega384c3": "x384c3", 159 "atxmega384d3": "x384d3", 160 "atxmega64a1": "x64a1", 161 "atxmega64a1u": "x64a1u", 162 "atxmega64a3": "x64a3", 163 "atxmega64a3u": "x64a3u", 164 "atxmega64a4": "x64a4", 165 "atxmega64a4u": "x64a4u", 166 "atxmega64b1": "x64b1", 167 "atxmega64b3": "x64b3", 168 "atxmega64c3": "x64c3", 169 "atxmega64d3": "x64d3", 170 "atxmega64d4": "x64d4", 171 "atxmega8e5": "x8e5", 172} 173 174 175def avrdude_mcu(did) -> str | None: 176 """:return: The avrdude MCU name for a device identifier or None.""" 177 d = did.copy() 178 # Search for key by truncating type 179 while True: 180 name = d.string.split("-")[0] 181 if name in avrdude_mcu_map: 182 return avrdude_mcu_map[name] 183 if len(d.type) == 0: 184 break 185 d.set("type", d.type[:-1]) 186 LOGGER.warning("Avrdude mcu not found for '%s'!", did.string) 187 return None 188 189 190def device_files(prefix: str) -> list[Path]: 191 """ 192 :param prefix: An AVR device prefix, for example, `atmega`, `attiny`, `at90`. 193 :return: A sorted list of ATDF files matching the prefix. 194 """ 195 return sorted(_ATDF_PATH.glob(f"*/AT{prefix[2:]}*")) 196 197 198def devices_from_file(path: Path) -> list[str]: 199 """:return: A sorted list of device order codes described in the ATDF file.""" 200 device_file = XmlReader(path) 201 return sorted(set(d for d in device_file.query("//variants/variant/@ordercode") if d != "standard")) 202 203 204def device_from_ordercode(path: Path, ordercode: str) -> dict | None: 205 """ 206 Extracts the device data of one order code from an AVR ATDF file. 207 208 :param path: Path to the ATDF file. 209 :param ordercode: The device order code, for example, `ATmega328P-AU`. 210 :return: A dictionary of device properties or None if the device is not supported. 211 """ 212 p = {} 213 214 device_file = XmlReader(path) 215 device = device_file.query("//device")[0] 216 variant = device_file.query(f'//variants/variant[@ordercode="{ordercode}"]')[0] 217 did = avr_did_from_string(ordercode.lower()) 218 if did is None: 219 LOGGER.error("Parse Error: unknown platform. Device string: '%s'", ordercode) 220 return None 221 p["id"] = did 222 LOGGER.info("Parsing '%s'", did.string) 223 224 mcu = avrdude_mcu(did) 225 p["mcu"] = "unsupported" if mcu is None else mcu 226 p["core"] = device.get("architecture").lower() 227 # We don't care about Microchip's new AVR8X devices 228 if p["core"] == "avr8x": 229 return None 230 231 p["define"] = "__AVR_" + device.get("name") + "__" 232 p["max_fcpu"] = variant.get("speedmax") 233 p["package"] = variant.get("package") 234 p["pinout"] = variant.get("pinout") 235 pinouts = device_file.query(f'//pinouts/pinout[@name="{p["pinout"]}"]/pin') 236 if not pinouts: 237 pinouts = device_file.query("//pinouts/pinout[1]/pin") 238 p["pinout_pins"] = {pin.get("position"): pin.get("pad") for pin in pinouts} 239 240 # find the values for flash, ram and (optional) eeprom 241 for memory_segment in device_file.query("//memory-segment"): 242 name = memory_segment.get("name") 243 size = int(memory_segment.get("size"), 16) 244 if name in ["FLASH", "APP_SECTION", "PROGMEM"]: 245 p["flash"] = size 246 elif name in ["IRAM", "SRAM", "INTERNAL_SRAM"]: 247 p["ram"] = size 248 elif name == "EEPROM": 249 p["eeprom"] = size 250 251 modules = [] 252 ports = [] 253 for m in device_file.query("//peripherals/module/instance"): 254 tmp = {"module": m.getparent().get("name").lower(), "instance": m.get("name").lower()} 255 # module SPI has two instances USART0_SPI, USART1_SPI 256 if tmp["module"] == "spi" and tmp["instance"].startswith("usart"): 257 continue 258 # some RF modules mistakenly claim flash module 259 if tmp["module"] == "flash": 260 continue 261 if tmp["module"] == "port": 262 ports.append(tmp) 263 else: 264 modules.append(tmp) 265 p["modules"] = sorted(list(set([(m["module"], m["instance"]) for m in modules]))) 266 267 signals = [] 268 gpios = [] 269 raw_signals = device_file.query("//peripherals/module/instance/signals/signal") 270 p["modules_only"] = not len(raw_signals) 271 if p["modules_only"]: 272 # Parse GPIOs manually from mask 273 for port in ports: 274 port = port["instance"][-1:] 275 register = f'//modules/module[@name="PORT"]/register-group[@name="PORT{port.upper()}"]/register[@name="PORT{port.upper()}"]' 276 port_mask = device_file.query(register + "/@mask") 277 if len(port_mask) == 0: 278 # The port mask is split up 279 port_mask = sum([int(mask, 16) for mask in device_file.query(register + "/bitfield/@mask")]) 280 else: 281 port_mask = int(port_mask[0], 16) 282 for pos in range(8): 283 if (1 << pos) & port_mask: 284 gpios.append((port, str(pos))) 285 gpios = sorted(gpios) 286 else: 287 signal_hashs = set() 288 for s in raw_signals: 289 tmp = { 290 "module": s.getparent().getparent().getparent().get("name").lower(), 291 "instance": s.getparent().getparent().get("name").lower(), 292 } 293 # Some ATDF files contain trailing whitespace, for example, group="SCL " 294 tmp.update({k: v.strip().lower() for k, v in s.items()}) 295 if tmp["group"] in ["p", "pin"] or tmp["group"].startswith("port"): 296 gpios.append(tmp) 297 else: 298 # filter out duplicates 299 shash = tmp.get("instance", "") + tmp.get("group", "") + tmp.get("pad", "") + tmp.get("index", "") 300 if shash not in signal_hashs: 301 signal_hashs.add(shash) 302 signals.append(tmp) 303 else: 304 LOGGER.debug("Duplicate signal '%s'", tmp) 305 gpios = sorted([(g["pad"][1], g["pad"][2]) for g in gpios]) 306 307 p["signals"] = signals 308 # Filter gpios by pinout 309 p["gpios"] = [pin for pin in gpios if f"P{pin[0].upper()}{pin[1]}" in p["pinout_pins"].values()] 310 if not p["gpios"]: 311 LOGGER.error("No GPIOs found for '%s'!", did.string) 312 return None 313 314 p["interrupts"] = [ 315 {"position": i.get("index"), "name": i.get("name")} for i in device_file.query("//interrupts/interrupt") 316 ] 317 return p
LOGGER =
<Logger modm_data.atdf.avr (WARNING)>
avrdude_mcu_map =
{'at90s1200': '1200', 'at90s2313': '2313', 'at90s2333': '2333', 'at90s2343': '2343', 'at90s4414': '4414', 'at90s4433': '4433', 'at90s4434': '4434', 'at90s8515': '8515', 'at90s8535': '8535', 'at90can128': 'c128', 'at90can32': 'c32', 'at90can64': 'c64', 'at90pwm216': 'pwm216', 'at90pwm2': 'pwm2', 'at90pwm2b': 'pwm2b', 'at90pwm3': 'pwm3', 'at90pwm316': 'pwm316', 'at90pwm3b': 'pwm3b', 'at90usb1286': 'usb1286', 'at90usb1287': 'usb1287', 'at90usb162': 'usb162', 'at90usb646': 'usb646', 'at90usb647': 'usb647', 'at90usb82': 'usb82', 'atmega103': 'm103', 'atmega128': 'm128', 'atmega1280': 'm1280', 'atmega1281': 'm1281', 'atmega1284': 'm1284', 'atmega1284p': 'm1284p', 'atmega1284rfr2': 'm1284rfr2', 'atmega128rfa1': 'm128rfa1', 'atmega128rfr2': 'm128rfr2', 'atmega16': 'm16', 'atmega161': 'm161', 'atmega162': 'm162', 'atmega163': 'm163', 'atmega164p': 'm164p', 'atmega168': 'm168', 'atmega168p': 'm168p', 'atmega168pb': 'm168pb', 'atmega169': 'm169', 'atmega16u2': 'm16u2', 'atmega2560': 'm2560', 'atmega2561': 'm2561', 'atmega2564rfr2': 'm2564rfr2', 'atmega256rfr2': 'm256rfr2', 'atmega32': 'm32', 'atmega324p': 'm324p', 'atmega324pa': 'm324pa', 'atmega325': 'm325', 'atmega3250': 'm3250', 'atmega328': 'm328', 'atmega328p': 'm328p', 'atmega329': 'm329', 'atmega3290': 'm3290', 'atmega3290p': 'm3290p', 'atmega329p': 'm329p', 'atmega32m1': 'm32m1', 'atmega32u2': 'm32u2', 'atmega32u4': 'm32u4', 'atmega406': 'm406', 'atmega48': 'm48', 'atmega48p': 'm48p', 'atmega48pb': 'm48pb', 'atmega64': 'm64', 'atmega640': 'm640', 'atmega644': 'm644', 'atmega644p': 'm644p', 'atmega644rfr2': 'm644rfr2', 'atmega645': 'm645', 'atmega6450': 'm6450', 'atmega649': 'm649', 'atmega6490': 'm6490', 'atmega64rfr2': 'm64rfr2', 'atmega8': 'm8', 'atmega8515': 'm8515', 'atmega8535': 'm8535', 'atmega88': 'm88', 'atmega88p': 'm88p', 'atmega88pb': 'm88pb', 'atmega8u2': 'm8u2', 'attiny10': 't10', 'attiny11': 't11', 'attiny12': 't12', 'attiny13': 't13', 'attiny15': 't15', 'attiny1634': 't1634', 'attiny20': 't20', 'attiny2313': 't2313', 'attiny24': 't24', 'attiny25': 't25', 'attiny26': 't26', 'attiny261': 't261', 'attiny28': 't28', 'attiny4': 't4', 'attiny40': 't40', 'attiny4313': 't4313', 'attiny43u': 't43u', 'attiny44': 't44', 'attiny45': 't45', 'attiny461': 't461', 'attiny5': 't5', 'attiny84': 't84', 'attiny85': 't85', 'attiny861': 't861', 'attiny88': 't88', 'attiny9': 't9', 'atxmega128a1': 'x128a1', 'atxmega128a1revd': 'x128a1d', 'atxmega128a1u': 'x128a1u', 'atxmega128a3': 'x128a3', 'atxmega128a3u': 'x128a3u', 'atxmega128a4': 'x128a4', 'atxmega128a4u': 'x128a4u', 'atxmega128b1': 'x128b1', 'atxmega128b3': 'x128b3', 'atxmega128c3': 'x128c3', 'atxmega128d3': 'x128d3', 'atxmega128d4': 'x128d4', 'atxmega16a4': 'x16a4', 'atxmega16a4u': 'x16a4u', 'atxmega16c4': 'x16c4', 'atxmega16d4': 'x16d4', 'atxmega16e5': 'x16e5', 'atxmega192a1': 'x192a1', 'atxmega192a3': 'x192a3', 'atxmega192a3u': 'x192a3u', 'atxmega192c3': 'x192c3', 'atxmega192d3': 'x192d3', 'atxmega256a1': 'x256a1', 'atxmega256a3': 'x256a3', 'atxmega256a3b': 'x256a3b', 'atxmega256a3bu': 'x256a3bu', 'atxmega256a3u': 'x256a3u', 'atxmega256c3': 'x256c3', 'atxmega256d3': 'x256d3', 'atxmega32a4': 'x32a4', 'atxmega32a4u': 'x32a4u', 'atxmega32c4': 'x32c4', 'atxmega32d4': 'x32d4', 'atxmega32e5': 'x32e5', 'atxmega384c3': 'x384c3', 'atxmega384d3': 'x384d3', 'atxmega64a1': 'x64a1', 'atxmega64a1u': 'x64a1u', 'atxmega64a3': 'x64a3', 'atxmega64a3u': 'x64a3u', 'atxmega64a4': 'x64a4', 'atxmega64a4u': 'x64a4u', 'atxmega64b1': 'x64b1', 'atxmega64b3': 'x64b3', 'atxmega64c3': 'x64c3', 'atxmega64d3': 'x64d3', 'atxmega64d4': 'x64d4', 'atxmega8e5': 'x8e5'}
def
avrdude_mcu(did) -> str | None:
176def avrdude_mcu(did) -> str | None: 177 """:return: The avrdude MCU name for a device identifier or None.""" 178 d = did.copy() 179 # Search for key by truncating type 180 while True: 181 name = d.string.split("-")[0] 182 if name in avrdude_mcu_map: 183 return avrdude_mcu_map[name] 184 if len(d.type) == 0: 185 break 186 d.set("type", d.type[:-1]) 187 LOGGER.warning("Avrdude mcu not found for '%s'!", did.string) 188 return None
Returns
The avrdude MCU name for a device identifier or None.
def
device_files(prefix: str) -> list[pathlib.Path]:
191def device_files(prefix: str) -> list[Path]: 192 """ 193 :param prefix: An AVR device prefix, for example, `atmega`, `attiny`, `at90`. 194 :return: A sorted list of ATDF files matching the prefix. 195 """ 196 return sorted(_ATDF_PATH.glob(f"*/AT{prefix[2:]}*"))
Parameters
- prefix: An AVR device prefix, for example,
atmega,attiny,at90.
Returns
A sorted list of ATDF files matching the prefix.
def
devices_from_file(path: pathlib.Path) -> list[str]:
199def devices_from_file(path: Path) -> list[str]: 200 """:return: A sorted list of device order codes described in the ATDF file.""" 201 device_file = XmlReader(path) 202 return sorted(set(d for d in device_file.query("//variants/variant/@ordercode") if d != "standard"))
Returns
A sorted list of device order codes described in the ATDF file.
def
device_from_ordercode(path: pathlib.Path, ordercode: str) -> dict | None:
205def device_from_ordercode(path: Path, ordercode: str) -> dict | None: 206 """ 207 Extracts the device data of one order code from an AVR ATDF file. 208 209 :param path: Path to the ATDF file. 210 :param ordercode: The device order code, for example, `ATmega328P-AU`. 211 :return: A dictionary of device properties or None if the device is not supported. 212 """ 213 p = {} 214 215 device_file = XmlReader(path) 216 device = device_file.query("//device")[0] 217 variant = device_file.query(f'//variants/variant[@ordercode="{ordercode}"]')[0] 218 did = avr_did_from_string(ordercode.lower()) 219 if did is None: 220 LOGGER.error("Parse Error: unknown platform. Device string: '%s'", ordercode) 221 return None 222 p["id"] = did 223 LOGGER.info("Parsing '%s'", did.string) 224 225 mcu = avrdude_mcu(did) 226 p["mcu"] = "unsupported" if mcu is None else mcu 227 p["core"] = device.get("architecture").lower() 228 # We don't care about Microchip's new AVR8X devices 229 if p["core"] == "avr8x": 230 return None 231 232 p["define"] = "__AVR_" + device.get("name") + "__" 233 p["max_fcpu"] = variant.get("speedmax") 234 p["package"] = variant.get("package") 235 p["pinout"] = variant.get("pinout") 236 pinouts = device_file.query(f'//pinouts/pinout[@name="{p["pinout"]}"]/pin') 237 if not pinouts: 238 pinouts = device_file.query("//pinouts/pinout[1]/pin") 239 p["pinout_pins"] = {pin.get("position"): pin.get("pad") for pin in pinouts} 240 241 # find the values for flash, ram and (optional) eeprom 242 for memory_segment in device_file.query("//memory-segment"): 243 name = memory_segment.get("name") 244 size = int(memory_segment.get("size"), 16) 245 if name in ["FLASH", "APP_SECTION", "PROGMEM"]: 246 p["flash"] = size 247 elif name in ["IRAM", "SRAM", "INTERNAL_SRAM"]: 248 p["ram"] = size 249 elif name == "EEPROM": 250 p["eeprom"] = size 251 252 modules = [] 253 ports = [] 254 for m in device_file.query("//peripherals/module/instance"): 255 tmp = {"module": m.getparent().get("name").lower(), "instance": m.get("name").lower()} 256 # module SPI has two instances USART0_SPI, USART1_SPI 257 if tmp["module"] == "spi" and tmp["instance"].startswith("usart"): 258 continue 259 # some RF modules mistakenly claim flash module 260 if tmp["module"] == "flash": 261 continue 262 if tmp["module"] == "port": 263 ports.append(tmp) 264 else: 265 modules.append(tmp) 266 p["modules"] = sorted(list(set([(m["module"], m["instance"]) for m in modules]))) 267 268 signals = [] 269 gpios = [] 270 raw_signals = device_file.query("//peripherals/module/instance/signals/signal") 271 p["modules_only"] = not len(raw_signals) 272 if p["modules_only"]: 273 # Parse GPIOs manually from mask 274 for port in ports: 275 port = port["instance"][-1:] 276 register = f'//modules/module[@name="PORT"]/register-group[@name="PORT{port.upper()}"]/register[@name="PORT{port.upper()}"]' 277 port_mask = device_file.query(register + "/@mask") 278 if len(port_mask) == 0: 279 # The port mask is split up 280 port_mask = sum([int(mask, 16) for mask in device_file.query(register + "/bitfield/@mask")]) 281 else: 282 port_mask = int(port_mask[0], 16) 283 for pos in range(8): 284 if (1 << pos) & port_mask: 285 gpios.append((port, str(pos))) 286 gpios = sorted(gpios) 287 else: 288 signal_hashs = set() 289 for s in raw_signals: 290 tmp = { 291 "module": s.getparent().getparent().getparent().get("name").lower(), 292 "instance": s.getparent().getparent().get("name").lower(), 293 } 294 # Some ATDF files contain trailing whitespace, for example, group="SCL " 295 tmp.update({k: v.strip().lower() for k, v in s.items()}) 296 if tmp["group"] in ["p", "pin"] or tmp["group"].startswith("port"): 297 gpios.append(tmp) 298 else: 299 # filter out duplicates 300 shash = tmp.get("instance", "") + tmp.get("group", "") + tmp.get("pad", "") + tmp.get("index", "") 301 if shash not in signal_hashs: 302 signal_hashs.add(shash) 303 signals.append(tmp) 304 else: 305 LOGGER.debug("Duplicate signal '%s'", tmp) 306 gpios = sorted([(g["pad"][1], g["pad"][2]) for g in gpios]) 307 308 p["signals"] = signals 309 # Filter gpios by pinout 310 p["gpios"] = [pin for pin in gpios if f"P{pin[0].upper()}{pin[1]}" in p["pinout_pins"].values()] 311 if not p["gpios"]: 312 LOGGER.error("No GPIOs found for '%s'!", did.string) 313 return None 314 315 p["interrupts"] = [ 316 {"position": i.get("index"), "name": i.get("name")} for i in device_file.query("//interrupts/interrupt") 317 ] 318 return p
Extracts the device data of one order code from an AVR ATDF file.
Parameters
- path: Path to the ATDF file.
- ordercode: The device order code, for example,
ATmega328P-AU.
Returns
A dictionary of device properties or None if the device is not supported.