Created
June 7, 2023 16:31
-
-
Save alufers/085c1f0302e5d889f4bf02d430ffdccf to your computer and use it in GitHub Desktop.
GDB script for printing gpio configuration of a STM32F412 (requires SVDParser and a svd for the mcu)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# First connect to the mcu via blackmagic probe or whatever | |
# usage (in gdb): source gpio-getter.py | |
from cmsis_svd.parser import SVDParser | |
import gdb | |
def read_memory(address, length): | |
inferior = gdb.selected_inferior() | |
return inferior.read_memory(address, length) | |
def print_pin_mode(mode): | |
if mode == 0b00: | |
return "Input" | |
elif mode == 0b01: | |
return "General purpose output" | |
elif mode == 0b10: | |
return "Alternate function" | |
elif mode == 0b11: | |
return "Analog" | |
else: | |
return "Invalid" | |
def print_pull_mode(mode): | |
""" | |
00: No pull-up, pull-down | |
01: Pull-up | |
10: Pull-down | |
11: Reserved | |
""" | |
if mode == 0b00: | |
return "No pull-up, pull-down" | |
elif mode == 0b01: | |
return "Pull-up" | |
elif mode == 0b10: | |
return "Pull-down" | |
elif mode == 0b11: | |
return "Reserved" | |
else: | |
return "Invalid" | |
def print_alternate_mode(mode): | |
""" | |
AF0 (system) | |
AF1 (TIM1/TIM2) | |
AF2 (TIM3/5) | |
AF3 (TIM8/9) | |
AF4 (I2C1..3, I2CFMP1) | |
AF5 (SPI1/2/3/4) | |
AF6 (SPI2/3/4, DFSDM) | |
AF7 (SPI2, USART1..3) | |
AF8 (DFSDM, USART3/6, CAN1) | |
AF9 (I2C1..3, I2CFMP1, CAN1/2, TIM12..14, QUADSPI) | |
AF10 (DFSDM, FSMC, QUADSPI, OTG_FS) | |
AF11 | |
AF12 (FMC, SDIO) | |
AF13 | |
AF14 | |
AF15 (EVENTOUT) | |
""" | |
if mode == 0x01: | |
return "TIM1/TIM2" | |
elif mode == 0x02: | |
return "TIM3/5" | |
elif mode == 0x03: | |
return "TIM8/9" | |
elif mode == 0x04: | |
return "(I2C1..3, I2CFMP1)" | |
elif mode == 0x05: | |
return "(SPI1/2/3/4)" | |
elif mode == 0x06: | |
return "(SPI2/3/4, DFSDM)" | |
elif mode == 0x07: | |
return "(SPI2, USART1..3)" | |
elif mode == 0x08: | |
return "(DFSDM, USART3/6, CAN1)" | |
elif mode == 0x09: | |
return "(I2C1..3, I2CFMP1, CAN1/2, TIM12..14, QUADSPI)" | |
elif mode == 0x0A: | |
return "(DFSDM, FSMC, QUADSPI, OTG_FS)" | |
else: | |
return str(mode) | |
def get_register_value(peripheral, register_name): | |
peripheral_address = peripheral.base_address | |
for register in peripheral.registers: | |
if register.name == register_name: | |
address = peripheral_address + register.address_offset | |
value = None | |
try: | |
value = read_memory(address, register.size / 8).tobytes() | |
except: | |
print("Failed to read memory at 0x%08x for %s.%s" % (address, peripheral.name, register_name)) | |
return None | |
value = int.from_bytes(value, byteorder='little') | |
return value | |
return None | |
parser = SVDParser.for_xml_file("STM32F412.svd") | |
gdb.execute("set mem inaccessible-by-default off") | |
limit_ports = ["GPIOA", "GPIOB", "GPIOC"] | |
for peripheral in parser.get_device().peripherals: | |
if peripheral.name.startswith("GPIO"): | |
if len(limit_ports) > 0 and peripheral.name not in limit_ports: | |
continue | |
letter = peripheral.name[-1] | |
peripheral_address = peripheral.base_address | |
for register in peripheral.registers: | |
if register.name.startswith("MODER"): | |
moder_address = peripheral_address + register.address_offset | |
moder_value = None | |
try: | |
moder_value = read_memory(moder_address, register.size / 8).tobytes() | |
except: | |
print("Failed to read memory at 0x%08x for %s.MODER" % (moder_address, peripheral.name)) | |
continue | |
print("%s.MODER @ 0x%08x:" % (peripheral.name, moder_address)) | |
moder_value = int.from_bytes(moder_value, byteorder='little') | |
for pin in range(16): | |
pin_mode = (moder_value >> (pin*2)) & 0b11 | |
extra = "" | |
if pin_mode == 0b00: | |
# find the PUPDR register | |
pupdr_value = get_register_value(peripheral, "PUPDR") | |
pull_mode = (pupdr_value >> (pin*2)) & 0b11 | |
extra = "(%s)" % print_pull_mode(pull_mode) | |
if pin_mode == 0b10: | |
# Alternate function registers (low and high) | |
afrl_value = get_register_value(peripheral, "AFRL" if pin < 8 else "AFRH") | |
# each pin is a nibble | |
nibble_offset = pin if pin < 8 else pin - 8 | |
afrl_value = (afrl_value >> (nibble_offset*4)) & 0b1111 | |
extra = "(%s)" % print_alternate_mode(afrl_value) | |
# print(afrl_value) | |
print(" P%s%d: %s %s" % (letter, pin, print_pin_mode(pin_mode), extra)) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment