modm_data.picosdk
Raspberry Pi Pico SDK
Parses the CMSIS-SVD files of the RP2040 and RP2350 devices from the Pico SDK.
1# Copyright 2026, Niklas Hauser 2# SPDX-License-Identifier: MPL-2.0 3 4""" 5# Raspberry Pi Pico SDK 6 7Parses the CMSIS-SVD files of the RP2040 and RP2350 devices from the Pico SDK. 8""" 9 10from .device_data import device_files, device_from_file, did_from_string 11 12__all__ = [ 13 "device_files", 14 "device_from_file", 15 "did_from_string", 16]
def
device_files(prefix: str) -> list[pathlib.Path]:
34def device_files(prefix: str) -> list[Path]: 35 """ 36 :param prefix: A device prefix, for example, `rp2040`. 37 :return: A sorted list of SVD files matching the prefix. 38 """ 39 return sorted(_SVD_PATH.glob(f"{prefix.lower()}*.svd"))
Parameters
- prefix: A device prefix, for example,
rp2040.
Returns
A sorted list of SVD files matching the prefix.
def
device_from_file(path: pathlib.Path) -> dict:
84def device_from_file(path: Path) -> dict: 85 """ 86 Extracts the device data from an RP SVD file. 87 88 :param path: Path to the SVD file. 89 :return: A dictionary of device properties. 90 """ 91 device_file = XmlReader(path) 92 p = {"id": (did := did_from_string(Path(path).stem))} 93 LOGGER.info("Parsing '%s'", did.string) 94 95 # information about the core and architecture 96 core = device_file.query("//device/cpu/name")[0].text.lower().replace("cm", "cortex-m") 97 if device_file.query("//device/cpu/fpuPresent")[0].text in ("1", "true"): 98 p["fpu"] = "fpv5-sp-d16" 99 p["core"] = core 100 p["revision"] = device_file.query("//device/cpu/revision")[0].text 101 102 # TODO: Memories are not described in the SVD file 103 p["memories"] = [ 104 {"name": "ram", "access": "rwx", "size": str(0x40000), "start": "0x20000000"}, 105 {"name": "core1", "access": "rwx", "size": str(0x1000), "start": "0x20040000"}, 106 {"name": "core0", "access": "rwx", "size": str(0x1000), "start": "0x20041000"}, 107 ] 108 109 modules = [ 110 {"module": "jtag", "instance": "jtag"}, 111 {"module": "usb", "instance": "usb"}, 112 {"module": "xip", "instance": "xip"}, 113 ] 114 gpios = [] 115 adc_channels = [] 116 dma_channels = [] 117 clocks = [] 118 for m in device_file.query("//peripherals/peripheral"): 119 modulename = m.find("name").text 120 if modulename == "IO_BANK0": 121 for r in m.findall("./registers/register"): 122 if r.find("description") is not None and r.find("description").text == "GPIO status": 123 name = re.search(r"^GPIO(?P<name>.*)_STATUS$", r.find("name").text).group("name").lower() 124 ctrl = m.find("./registers/register[name='GPIO" + name + "_CTRL']") 125 gpios.append({"name": name, "bank": "bank0", "idx": int(name), "funcs": _gpio_funcs(ctrl)}) 126 elif modulename == "IO_QSPI": 127 for r in m.findall("./registers/register"): 128 if r.find("description") is not None and r.find("description").text == "GPIO status": 129 name = re.search(r"^GPIO_QSPI_(?P<name>.*)_STATUS$", r.find("name").text).group("name").lower() 130 ctrl = m.find("./registers/register[name='GPIO_QSPI_" + name.upper() + "_CTRL']") 131 idx = int(int(r.find("addressOffset").text[2:], 16) / 8) 132 gpios.append({"name": name, "idx": idx, "bank": "qspi", "funcs": _gpio_funcs(ctrl)}) 133 elif modulename == "ADC": 134 # TODO: Find way to get ADC channels info 135 adc_channels = [ 136 {"id": 0, "name": "Ch0"}, 137 {"id": 1, "name": "Ch1"}, 138 {"id": 2, "name": "Ch2"}, 139 {"id": 3, "name": "Ch3"}, 140 {"id": 4, "name": "Temperature"}, 141 ] 142 modules.append({"module": "adc", "instance": "adc"}) 143 elif modulename == "DMA": 144 for r in m.findall("./registers/register"): 145 if match := re.search(r"^CH(?P<name>\d+)_READ_ADDR$", r.find("name").text): 146 dma_channels.append({"name": match.group("name").lower()}) 147 elif modulename == "CLOCKS": 148 for r in m.findall("./registers/register"): 149 if match := re.search(r"^CLK_(?P<name>.+)_CTRL$", r.find("name").text): 150 name = match.group("name").lower() 151 aux_fld = r.find("./fields/field[name='AUXSRC']") 152 if aux_fld is None: 153 continue 154 idx = int(int(r.find("addressOffset").text, 16) / 12) 155 sources = [] 156 aux_sel = 0 157 src_fld = r.find("./fields/field[name='SRC']") 158 if src_fld is not None: 159 for f in src_fld.findall("./enumeratedValues/enumeratedValue"): 160 src_name = f.find("name").text 161 if src_name == "clksrc_clk_" + name + "_aux": 162 aux_sel = f.find("value").text 163 else: 164 sources.append( 165 {"name": _clock_source_name(src_name), "src": f.find("value").text, "aux": 0} 166 ) 167 for f in aux_fld.findall("./enumeratedValues/enumeratedValue"): 168 sources.append( 169 { 170 "name": _clock_source_name(f.find("name").text), 171 "src": aux_sel, 172 "aux": f.find("value").text, 173 } 174 ) 175 clocks.append({"name": name, "sources": sources, "glitchless": src_fld is not None, "idx": idx}) 176 else: 177 match = re.search(r"(?P<module>.*\D)(?P<instance>\d*$)", modulename) 178 modules.append({"module": match.group("module").lower(), "instance": modulename.lower()}) 179 180 p["modules"] = sorted(list(set([(m["module"], m["instance"]) for m in modules]))) 181 p["gpios"] = gpios 182 p["adc_channels"] = adc_channels 183 p["dma_channels"] = dma_channels 184 p["clocks"] = clocks 185 186 modules_map = {"clocks": {"module": "clocks", "instance": "clocks"}} 187 for m in modules: 188 modules_map[m["instance"]] = m 189 190 # Manually patch this here instead of the SVD file 191 adc_map = { 192 "bank026": {"driver": "adc", "name": "in0", "af": "-1"}, 193 "bank027": {"driver": "adc", "name": "in1", "af": "-1"}, 194 "bank028": {"driver": "adc", "name": "in2", "af": "-1"}, 195 "bank029": {"driver": "adc", "name": "in3", "af": "-1"}, 196 } 197 for gpio in gpios: 198 gpio["signals"] = [_func_to_signal(modules_map, func) for func in gpio["funcs"]] 199 if adcsig := adc_map.get(gpio["bank"] + gpio["name"]): 200 gpio["signals"].append(adcsig) 201 202 # Unique interrupts 203 p["interrupts"] = [] 204 for i in device_file.query("//peripherals/peripheral/interrupt"): 205 interrupt = {"position": i.find("value").text, "name": i.find("name").text} 206 if interrupt not in p["interrupts"]: 207 p["interrupts"].append(interrupt) 208 return p
Extracts the device data from an RP SVD file.
Parameters
- path: Path to the SVD file.
Returns
A dictionary of device properties.
16def did_from_string(string: str) -> DeviceIdentifier: 17 """ 18 Parses RP device strings, for example, `rp2040`, organized as 19 `{platform}{cores}{type}{ram}{flash}`. 20 """ 21 string = string.lower() 22 if not string.startswith("rp"): 23 raise ValueError(f"Unknown identifier '{string}'!") 24 i = DeviceIdentifier("{platform}{cores}{type}{ram}{flash}") 25 i.set("platform", "rp") 26 i.set("cores", string[2]) 27 i.set("type", string[3]) 28 i.set("ram", string[4]) 29 i.set("flash", string[5]) 30 i.set("family", string[2:4]) 31 return i
Parses RP device strings, for example, rp2040, organized as
{platform}{cores}{type}{ram}{flash}.