Skip to content

Flash Programming

The Flash subsystem wraps OpenOCD’s flash command family for programming on-chip flash memory. It handles bank enumeration, sector-level erase, raw byte read/write through temporary files, high-level firmware image programming, verification, and write protection.

Access it through the session:

# Async
session.flash
# Sync
sync_session.flash

banks() returns a list of FlashBank descriptors for every flash bank OpenOCD has configured. These come without detailed sector information — use info() for that.

import asyncio
from openocd import Session
async def main():
async with await Session.connect() as session:
banks = await session.flash.banks()
for bank in banks:
print(f"Bank #{bank.index}: {bank.name}")
print(f" Base: 0x{bank.base:08X}, Size: 0x{bank.size:X}")
print(f" Bus width: {bank.bus_width}, Chip width: {bank.chip_width}")
print(f" Target: {bank.target}")
asyncio.run(main())

info(bank=0) returns a FlashBank with its sectors list populated. Each sector is a FlashSector with index, offset, size, and protection status.

async with await Session.connect() as session:
bank = await session.flash.info(0)
print(f"{bank.name}: {len(bank.sectors)} sectors")
for sector in bank.sectors:
prot = "protected" if sector.protected else "unprotected"
print(f" Sector {sector.index}: offset=0x{sector.offset:X}, "
f"size=0x{sector.size:X}, {prot}")

Two methods for reading flash content:

  • read(bank, offset, size) — returns raw bytes by writing to a temp file, then reading the data back through TCL or from the local filesystem.
  • read_to_file(bank, path) — dumps the entire bank directly to a file on disk.
from pathlib import Path
async with await Session.connect() as session:
# Read 256 bytes from the start of bank 0
data = await session.flash.read(bank=0, offset=0, size=256)
print(f"Read {len(data)} bytes: {data[:16].hex()}")
# Dump the entire bank to a file
await session.flash.read_to_file(bank=0, path=Path("flash_dump.bin"))

write(bank, offset, data) writes raw bytes to a flash bank at a given offset. Like read(), it uses a temporary file since OpenOCD’s flash write_bank reads from a file.

async with await Session.connect() as session:
config_data = b"\x01\x02\x03\x04"
await session.flash.write(bank=0, offset=0x1000, data=config_data)

write_image(path, erase=True, verify=True) is the high-level “flash and go” command. It handles erase, write, and verification in one operation. It accepts .bin, .hex, and .elf files.

from pathlib import Path
async with await Session.connect() as session:
firmware = Path("build/firmware.hex")
await session.flash.write_image(firmware, erase=True, verify=True)
print("Firmware programmed and verified")

When verify=True, the method runs verify_image after writing. If the verification finds a mismatch, it raises FlashError.

erase_sector(bank, first, last) erases sectors from first to last (both inclusive). Validates that first <= last and raises FlashError if the range is invalid.

async with await Session.connect() as session:
# Erase sectors 0 through 3 in bank 0
await session.flash.erase_sector(bank=0, first=0, last=3)

erase_all(bank=0) queries the bank info to find the last sector, then erases the full range.

await session.flash.erase_all(bank=0)

protect(bank, first, last, on) sets or clears hardware write protection on a range of sectors.

async with await Session.connect() as session:
# Protect the bootloader (sectors 0-1)
await session.flash.protect(bank=0, first=0, last=1, on=True)
# Unprotect application sectors (2-7)
await session.flash.protect(bank=0, first=2, last=7, on=False)

verify(bank, path) compares flash contents against a reference binary file and returns True if they match, False otherwise.

from pathlib import Path
async with await Session.connect() as session:
matches = await session.flash.verify(bank=0, path=Path("golden.bin"))
if matches:
print("Flash contents match reference file")
else:
print("MISMATCH detected")
FieldTypeDescription
indexintBank number
namestrBank name (e.g. stm32f1x.flash)
baseintBase address
sizeintTotal size in bytes
bus_widthintBus width
chip_widthintChip width
targetstrAssociated target or driver name
sectorslist[FlashSector]Sector list (empty from banks(), populated from info())
FieldTypeDescription
indexintSector number within the bank
offsetintByte offset from the bank base
sizeintSector size in bytes
protectedboolWhether write protection is enabled

All flash operations raise FlashError on failure. The error message includes the OpenOCD response for diagnostics.

from openocd import Session, FlashError
try:
with Session.connect_sync() as session:
session.flash.write_image(Path("firmware.bin"))
except FlashError as e:
print(f"Flash operation failed: {e}")
MethodReturn TypeDescription
banks()list[FlashBank]List all configured flash banks
info(bank=0)FlashBankDetailed bank info with sectors
read(bank, offset, size)bytesRead raw flash via temp file
read_to_file(bank, path)NoneDump entire bank to file
write(bank, offset, data)NoneWrite raw bytes via temp file
write_image(path, erase=True, verify=True)NoneHigh-level flash programming
erase_sector(bank, first, last)NoneErase a sector range
erase_all(bank=0)NoneErase entire bank
protect(bank, first, last, on)NoneSet/clear write protection
verify(bank, path)boolVerify flash against a file