Skip to content

Instantly share code, notes, and snippets.

@huming2207
Created November 8, 2020 03:02
Show Gist options
  • Save huming2207/9c4792f18cc94cfcb7868a2c8d201e0e to your computer and use it in GitHub Desktop.
Save huming2207/9c4792f18cc94cfcb7868a2c8d201e0e to your computer and use it in GitHub Desktop.
STM32L0x1 Mass erase with pyOCD
from pyocd.core.exceptions import TransferError
from pyocd.core.helpers import ConnectHelper
from pyocd.core.target import Target
from usb.core import USBError
import time
class Stm32L0x1Eraser():
FLASH_PECR = 0x40022004
FLASH_PDKEYR = 0x40022008
FLASH_PKEYR = 0x4002200C
FLASH_PRGKEYR = 0x40022010
FLASH_OPTKEYR = 0x40022014
FLASH_SR = 0x40022018
FLASH_OPTR = 0x4002201C
FLASH_WRPROT1 = 0x40022020
FLASH_WRPROT2 = 0x40022080
FLASH_OPT_BASE = 0x1ff80000
def wait_flash_busy(self, target: Target):
result = 1,
while result != 0:
result = target.read32(self.FLASH_SR) & 0b1
def mass_erase(self):
"""
This toggles the Read Protection Level from 0 to 1 and then 0, so that it can achieve a mass erase.
Check out RM0377's FLASH sections and A.3.12 Mass Erase code example
"""
with ConnectHelper.session_with_chosen_probe(options={
"target_override": "stm32l071kbux",
"logging": {
"loggers": {
"pyocd.board.board": {
"level": "CRITICAL" # Shut up the board logging
}
}
}
}) as session:
board = session.board
target = board.target
target.reset_and_halt()
# Unlock flash
target.write32(self.FLASH_PKEYR, 0x89abcdef)
target.write32(self.FLASH_PKEYR, 0x02030405)
self.wait_flash_busy(target)
target.write32(self.FLASH_PRGKEYR, 0x8c9daebf)
target.write32(self.FLASH_PRGKEYR, 0x13141516)
self.wait_flash_busy(target)
target.write32(self.FLASH_OPTKEYR, 0xfbead9c8)
target.write32(self.FLASH_OPTKEYR, 0x24252627)
self.wait_flash_busy(target)
# Detect RDPROT
optr_ret = target.read32(self.FLASH_OPTR)
if optr_ret & 0xff == 0xCC: # Level 2
raise ValueError('You are on RDP Level 2, got a second-hand chip??')
elif optr_ret & 0xff == 0xAA: # Level 0 - default
print("Setting RDP level to 0 to 1 first...")
# Enable erasing
target.write32(self.FLASH_PECR, 0x200)
self.wait_flash_busy(target)
# Erase the OPT1
target.write32(self.FLASH_OPT_BASE, 0)
self.wait_flash_busy(target)
# Try OBR_LAUNCH to commit option bytes change
# This will reboot the MCU
try:
target.write32(self.FLASH_PECR, 0x40000)
session.close()
time.sleep(1)
self.mass_erase()
except (TransferError, USBError):
print('No ACK anymore - MCU probably restarts')
else: # Level 1 - Set to Level 0
print("Setting RDP level to 1 to 0 to trigger mass erase...")
opt_lsb = optr_ret & 0xffff
opt_lsb &= (~0xff)
opt_lsb |= 0xAA
opt_write = (~opt_lsb) << 16 | opt_lsb
target.write32(self.FLASH_OPT_BASE, opt_write)
self.wait_flash_busy(target)
# Try OBR_LAUNCH to commit option bytes change
# This will reboot the MCU
try:
target.write32(self.FLASH_PECR, 0x40000)
session.close()
print('Done~!')
except (TransferError, USBError):
print('No ACK anymore - MCU probably restarts')
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment