Misc. fixes and improvements

Abstracted break and continue,
added missing constant for WDT,
improved command routine compatibility.
This commit is contained in:
Dominic Höglinger 2025-07-02 11:10:23 +02:00
parent b04dc85f36
commit aa18c27fff

57
iapy.py
View File

@ -4,23 +4,38 @@ import time
# get the current inferior, i.e. the connection to target
inferior = gdb.selected_inferior()
def target_break():
if inferior.threads()[0].is_running():
gdb.execute(interrupt)
def target_continue():
t = inferior.threads()
if not(inferior.threads()[0].is_running()):
gdb.execute('continue')
def target_u32read(address, endian='little'):
target_break()
value = inferior.read_memory(address, 4)
return int.from_bytes(value, byteorder=endian)
def target_u32write(address, value, endian='little'):
target_break()
data = value.to_bytes(4, byteorder=endian) # Adjust byteorder as needed
inferior.write_memory(address, data)
def target_regset(name, value):
target_break()
gdb.execute(f'set ${name} = {value}')
def target_prepare():
"""
Prepares the target for IAP operations.
This implementation is an example for the LPC546xx series of chips.
"""
LPC546XX_WDT_MODE = 0x4000C000
LPC546XX_WDT_PERIOD_MAX = 0xFFFFFF
LPC546XX_WDT_PROTECT = (1 << 4)
LPC546XX_MAINCLKSELA = 0x40000280
@ -28,24 +43,29 @@ def target_prepare():
LPC546XX_AHBCLKDIV = 0x40000380
LPC546XX_FLASHCFG = 0x40000400
gdb.execute('interrupt')
gdb.execute('set mem inaccessible-by-default off')
target_break()
gdb.Breakpoint("*0x00020000")
gdb.Breakpoint("*0x00020001")
# check if watchdog timer's on
wdt_mode = target_u32read(LPC546XX_WDT_MODE)
# if WDT on, we can't disable it, but we may be able to set a long period
if (wdt_mode and not(wdt_mode & LPC546XX_WDT_PROTECT)):
# if WDT on, we can't disable it, but we may be able to set a long period
if (wdt_mode and not(wdt_mode & LPC546XX_WDT_PROTECT)):
target_u32write(LPC546XX_WDT_CNT, LPC546XX_WDT_PERIOD_MAX)
# SYSCLK: 12MHz FRO
target_u32write(LPC546XX_MAINCLKSELA, 0)
# use MAINCLKSELA
target_u32write(LPC546XX_MAINCLKSELB, 0)
target_u32write(LPC546XX_MAINCLKSELB, 0)
# div by 1
target_u32write(LPC546XX_AHBCLKDIV, 0)
target_u32write(LPC546XX_AHBCLKDIV, 0)
# recommended default configuration
target_u32write(LPC546XX_FLASHCFG, 0x1A)
target_u32write(LPC546XX_FLASHCFG, 0x1A)
def iap_command(a0, a1=0, a2=0, a3=0, a4=0):
gdb.execute('interrupt')
print(f"IAPy: Command {a0} {a1} {a2} {a3} {a4}")
target_break()
# setup request
target_u32write(0x2000ffa0, a0)
target_u32write(0x2000ffa4, a1)
@ -61,17 +81,25 @@ def iap_command(a0, a1=0, a2=0, a3=0, a4=0):
target_u32write(0x2000ffd0, 0xAAAAAAAA)
# call setup
target_break()
target_regset('lr', 0x00020001)
target_regset('r0', 0x2000ffa0)
target_regset('r1', 0x2000ffc0)
target_regset('pc', 0x03000205)
target_regset('primask', 1)
target_regset('msp', 0x2000ffa0)
# set PC
gdb.execute('jump *0x03000205')
# use PSP instead because MSP is most-likely not accessible
target_regset('psp', 0x2000ffa0)
target_regset('control', 0x2)
# execute and wait
gdb.execute('continue')
target_continue()
time.sleep(0.5)
# restore execution to MSP
target_break()
target_regset('msp', 0x2000ffa0)
target_regset('control', 0x0)
# gather results
res0 = target_u32read(0x2000ffc0)
res1 = target_u32read(0x2000ffc4)
@ -88,7 +116,4 @@ def iap_flash_sector_erase(start_sector, end_sector, sysclk=12000):
iap_command(50, start_sector, end_sector)
# erase sectors
iap_command(52, start_sector, end_sector, sysclk)
gdb.execute('interrupt')
target_break()