Skip to content

Instantly share code, notes, and snippets.

@elfmimi
Last active May 27, 2023 14:00
Show Gist options
  • Save elfmimi/3ef312d59878e7f0d8f5e820bfa68943 to your computer and use it in GitHub Desktop.
Save elfmimi/3ef312d59878e7f0d8f5e820bfa68943 to your computer and use it in GitHub Desktop.
pyOCD user script for Nuvoton ARM MCUs
# How to invoke:
# pyocd cmd --script nuvoton.py -c "ident"
# pyocd cmd --script nuvoton.py -c "read_config_regs"
# pyocd cmd --script nuvoton.py -c "write_config_regs 0xFFFFFFFF 0xFFFFFFFF"
# pyocd cmd --script nuvoton.py -c "chip_erase"
#
# and for the commander prompt, invoke it like this:
# pyocd cmd --script nuvoton.py
from pyocd.core.exceptions import TransferFaultError, TransferTimeoutError
options.update({
# "target_override": "cortex_m",
})
if not "target_override" in options:
options.set("target_override", "cortex_m")
if not "frequency" in options:
options.set("frequency", 16000000)
PART_NAME_DICT = {
0x12000: "NUC120LE3AN",
0x12305: "NUC123SC2AN1",
0x12315: "NUC123SD4AN0",
0x12325: "NUC123LC2AN1",
0x12335: "NUC123LD4AN0",
0x12345: "NUC123ZC2AN1",
0x12355: "NUC123ZD4AN0",
0xC05204: "NUC126LG4AE",
0xC05205: "NUC126LE4AE",
0xC05212: "NUC126SG4AE",
0xC05213: "NUC126SE4AE",
0xC05231: "NUC126VG4AE",
0x295C50: "NUC029LGE",
0x295C51: "NUC029SGE",
0x295C52: "NUC029KGE",
0xF250E0: "M253ZE3AE",
0xF25210: "M252SD2AE",
0xF252B0: "M252FC2AE",
0x1132CB0: "M032FC1AE",
0x1132DE0: "M032TD2AE",
0x01647192: "M471R1E6AE",
0x00D4851F: "M48SSIDAE",
}
class Context:
pass
self = Context()
def read8(off):
return target.read8(self.sys_base + off)
def read32(off):
return target.read32(self.sys_base + off)
def write8(off, dat):
target.write8(self.sys_base + off, dat)
def write32(off, dat):
target.write32(self.sys_base + off, dat)
def unlock_reg():
# Unlock
write8(0x0100, 0x59)
write8(0x0100, 0x16)
write8(0x0100, 0x88)
def lock_reg():
write8(0x0100, 0x00)
def read_via_isp(addr):
# Enable ISP
write8(0xC000, 0x79) # ISPCTL
# ISP-Command = Flash Read
write8(0xC00C, 0x00) # ISPCMD
write32(0xC004, addr) # ISPADDR
# Write ISP Trigger Control Register (ISPTRG)
write8(0xC010, 0x01) # ISPTRG
# Read ISPTRG until finished
while read8(0xC010) != 0: # ISPTRG
pass
# Read ISP Data Register (ISPDAT)
dat = read32(0xC008) # ISPDAT
# Disable ISP
write8(0xC000, 0x00)
return dat
def write_via_isp(adr, dat):
write8(0xC000, 0x79) # ISPCTL
# ISP-Command = Flash Program
write8(0xC00C, 0x21) # ISPCMD
write32(0xC004, adr) # ISPADDR
write32(0xC008, dat) # ISPDAT
write8(0xC010, 0x01) # ISPTRG
# Read ISPTRG until finished
while read8(0xC010) != 0: # ISPTRG
pass
if read8(0xC000) & 0x40: # ISPCTL
print("ISP Error")
return
write8(0xC000, 0x00) # ISPCTL
def erase_page(adr):
write8(0xC000, 0x79) # ISPCTL
# ISP-Command = Flash page erase
write8(0xC00C, 0x22) # ISPCMD
write32(0xC004, adr) # ISPADDR
write8(0xC010, 0x01) # ISPTRG
# Read ISPTRG until finished
while True:
try:
if read8(0xC010) == 0: # ISPTRG
break
except (TransferFaultError, TransferTimeoutError):
pass
# print(".")
if read8(0xC000) & 0x40: # ISPCTL
print("ISP Error")
return
write8(0xC000, 0x00) # ISPCTL
def ident_sys_base():
# Older Cortex-M0 variants use different address for peripherals' mapping
if target.read32(0x4000_0000) in [0x0000_0000, 0xFFFF_FFFF]:
self.sys_base = 0x5000_0000
else:
self.sys_base = 0x4000_0000
@command(help="Identify Part")
def ident():
ident_sys_base()
core_type_name = target.selected_core.name
pdid = read32(0) # PDID
part_name = PART_NAME_DICT.get(pdid)
if part_name is not None:
print(f"PDID=0x{pdid:08X} {part_name} ({core_type_name})")
else:
print(f"PDID=0x{pdid:08X} ({core_type_name})")
@command(help="Read Configuration Registers")
def read_config_regs():
ident()
unlock_reg()
config0 = read_via_isp(0x0030_0000)
config1 = read_via_isp(0x0030_0004)
print(f"CONFIG0 = 0x{config0:08X}")
print(f"CONFIG1 = 0x{config1:08X}")
lock_reg()
@command(help="Write Configuration Registers")
def write_config_regs(config0: int, config1: int):
ident()
unlock_reg()
# print(f"config0=0x{config0:08X} config1=0x{config1:08X}")
erase_page(0x0030_0000)
write_via_isp(0x0030_0000, config0)
write_via_isp(0x0030_0004, config1)
config0 = read_via_isp(0x0030_0000)
config1 = read_via_isp(0x0030_0004)
lock_reg()
print(f"CONFIG0 = 0x{config0:08X}")
print(f"CONFIG1 = 0x{config1:08X}")
@command(help="Boot Select")
def boot_select(sel: str):
ident_sys_base()
if sel.lower() in ["ap", "aprom"]:
unlock_reg()
write32(0xC000, 0)
elif sel.lower() in ["ld", "ldrom"]:
unlock_reg()
write32(0xC000, 2)
else:
print(f"Wrong parameter: {sel}")
@command(help="Chip Erase")
def chip_erase():
ident_sys_base()
unlock_reg()
write8(0xC000, 0x79) # ISPCTL
write8(0xC01C, 0x01) # Write one to undocumented flash control register
# ISP-Command = Flash Mass Erase
write8(0xC00C, 0x26) # ISPCMD
write32(0xC004, 0) # ISPADDR
print("Performing chip erase.")
write8(0xC010, 0x01) # ISPTRG
# Read ISPTRG until finished
while True:
try:
if read8(0xC010) == 0: # ISPTRG
break
except (TransferFaultError, TransferTimeoutError):
pass
# print(".")
if read8(0xC000) & 0x40: # ISPCTL
print("ISP Error")
return
write8(0xC000, 0x00) # ISPCTL
print("Done.")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment