Skip to main content

mp.backend — 24 functions

All blocking operations return ok: bool, err: string.

local ok, err = mp.backend.connect()
if not ok then mp.log.error(err); return end

Standard operations

FunctionReturnsDescription
connect()ok, errConnect to target with current config
read()ok, errRead target memory into buffer
write()ok, errWrite buffer to target (with blank check)
verify()ok, errVerify target matches buffer
erase()ok, errErase target (mass erase when available)
flash()ok, errFull cycle: connect → erase → write → verify
connect_timeout(ms)ok, errconnect() with explicit timeout in ms
read_timeout(ms)ok, errread() with explicit timeout in ms
write_timeout(ms)ok, errwrite() with explicit timeout in ms

Extended operations (TGSN only as of writing)

FunctionReturnsDescription
write_no_blank()ok, errWrite without blank check (relies on NOR semantics)
blank_check()ok, errStandalone blank check; ok=false names the first non-blank block
erase_blocks()ok, errPer-block erase, never mass erase
read_checksums()blocks|nil, errChip-side per-block / per-subblock checksums (see below)

Backends that don't implement these return an explicit "Not Supported: …" error instead of hanging.

write_no_blank()

Writes the buffer to the target, bypassing the host-side blank check. Useful when you want several sequential writes into the same block without erasing in between. Relies on NOR-flash semantics (bits can only flip 1→0). Trying to flip a bit back from 0 to 1 will silently fail at the cell — a subsequent verify() will reveal it.

blank_check()

Returns ok=true if every block in the region is 0xFF, otherwise ok=false with err naming the first non-blank block.

erase_blocks()

Always performs block-level erase via the erase-area command, never mass erase. For families where the standard erase() uses mass erase for speed (e.g. NEC 78K0/Kx2), erase_blocks() guarantees that only the current region's memory is erased and the rest of the flash stays intact.

local ok, err = mp.backend.connect() if not ok then mp.log.error(err); return end
ok, err = mp.backend.erase_blocks() if not ok then mp.log.error(err); return end
ok, err = mp.backend.blank_check() -- ok=true, region is blank

ok, err = mp.backend.write_no_blank() if not ok then mp.log.error(err); return end
ok, err = mp.backend.blank_check() -- ok=false, err contains "Block N not blanked"

mp.memory.write_at("Code Flash", 0x400, {0x00})
ok, err = mp.backend.write_no_blank() -- 0xFF → 0x00 is a valid 1→0 transition
caution

write_no_blank() bypasses a safety check. Writing a 1 on top of a 0 technically succeeds but the cell stays at 0 — a later verify() or read() will expose the divergence. Don't use this unless you understand NOR semantics.

read_checksums() — chip-side checksums

Returns checksums computed by the chip itself for every block and sub-block of every region. Same data the Renesas Checksum dialog shows, but as structured values for scripts. Unlike mp.checksum.* (host-side buffer), these come from the flash controller — and for ECC-enabled families they include the contribution of hidden ECC bytes that are invisible to read().

local blocks, err = mp.backend.read_checksums()
if not blocks then mp.log.error(err); return end

for _, b in ipairs(blocks) do
mp.log.infof("block %d base=0x%04X subs=%04X %04X %04X %04X",
b.block_n, b.base_checksum,
b.sub_checksums[1], b.sub_checksums[2],
b.sub_checksums[3], b.sub_checksums[4])
end

Each entry is a table: {block_n, base_checksum, sub_checksums[]}.

Per-segment operations

A segment is an arbitrary aligned range [addr, addr+size) over the target's absolute address space — not a region. On a multi-region target (Flash + EEPROM/data) the backend resolves which region the range lands in. All four return (ok, err).

Currently the ESP backend only

Other backends (ST-Link/SWD, USBDM, TGSN) do not implement per-segment ops yet and return a "Not Supported: …" error.

FunctionReturnsDescription
read_segment(addr, size)ok, errRead ONE absolute range DEVICE → buffer (non-destructive)
verify_segment(addr, size)ok, errCompare ONE absolute range DEVICE vs buffer
write_segment(addr, size)ok, errWrite buffer slice for ONE absolute range → DEVICE
erase_segment(addr, size)ok, errErase the sectors covering ONE absolute range
local ok, err = mp.backend.read_segment(0x100000, 0x1000) -- chip → buffer
mp.app.allow_hw_writes(true)
ok, err = mp.backend.write_segment(0x100000, 0x1000) -- buffer → chip
ok, err = mp.backend.verify_segment(0x100000, 0x1000) -- chip vs buffer
  • Addresses are absolute — these take the device address, not a region offset; the backend validates bounds/alignment and resolves the region.
  • Alignment contract (ESP): read/verify are word-aligned to 4; write/erase are sector-aligned to 4096 — ESP flash write erases the sectors it touches, so a sub-sector write would clobber neighbours. A misaligned or out-of-map range returns (false, …) before any device IO.
  • write_segment/erase_segment take their data from the live buffer slice (populate it via mp.file.load / mp.memory.*), honor the mp.app.allow_hw_writes gate, and erase_segment also pops the GUI confirmation modal.
  • ESP UI-tab caveat: the ESP backend leaves the UI hex tab empty until a device readmp.memory.get_regions() is {} right after connect. The segment ops still work (absolute-addressed), but call read_segment first if you then want mp.memory.* / get_region_info().

See the bundled scripts/examples/esp_segment_*.lua — start with esp_segment_example.lua (annotated end-to-end), then read, write_verify, roundtrip, validation, app_flash.

State and info

FunctionReturnsDescription
is_connected()boolCurrent connection status
get_target_info()table{name, additional[]}
get_programmer_info()table{name, serial, connected, type} for the currently selected programmer
get_programmers()tableArray of all programmers seen by a probe-scan. serial may be empty for devices that don't expose it over probe
get_progress()table{progress, speed, title, msg} — last snapshot

Power

FunctionReturnsDescription
power_on()voidSet VDD = 3.3 V
power_on_5v()voidSet VDD = 5 V
power_off()voidVDD off
power_toggle()voidToggle power output
set_power(v)void"3v3" | "5v" | "off"