Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Erase addr size / section of the flash memory with st-flash #1213

Merged
merged 8 commits into from
Jan 15, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions inc/stlink.h
Original file line number Diff line number Diff line change
Expand Up @@ -274,6 +274,7 @@ int stlink_trace_enable(stlink_t* sl, uint32_t frequency);
int stlink_trace_disable(stlink_t* sl);
int stlink_trace_read(stlink_t* sl, uint8_t* buf, size_t size);
int stlink_erase_flash_mass(stlink_t* sl);
int stlink_erase_flash_section(stlink_t *sl, stm32_addr_t base_addr, size_t size, bool align_size);
int stlink_write_flash(stlink_t* sl, stm32_addr_t address, uint8_t* data, uint32_t length, uint8_t eraseonly);
int stlink_parse_ihex(const char* path, uint8_t erased_pattern, uint8_t * * mem, size_t * size, uint32_t * begin);
uint8_t stlink_get_erased_pattern(stlink_t *sl);
Expand All @@ -288,6 +289,8 @@ int stlink_cpu_id(stlink_t *sl, cortex_m3_cpuid_t *cpuid);

int stlink_erase_flash_page(stlink_t* sl, stm32_addr_t flashaddr);
uint32_t stlink_calculate_pagesize(stlink_t *sl, uint32_t flashaddr);
int stlink_check_address_range_validity(stlink_t *sl, stm32_addr_t addr, size_t size);
int stlink_check_address_alignment(stlink_t *sl, stm32_addr_t addr);
uint16_t read_uint16(const unsigned char *c, const int pt);
void stlink_core_stat(stlink_t *sl);
void stlink_print_data(stlink_t *sl);
Expand Down
119 changes: 74 additions & 45 deletions src/common.c
Original file line number Diff line number Diff line change
Expand Up @@ -2951,30 +2951,81 @@ int stlink_erase_flash_page(stlink_t *sl, stm32_addr_t flashaddr) {
return check_flash_error(sl);
}

// Check if an address and size are within the flash
int stlink_check_address_range_validity(stlink_t *sl, stm32_addr_t addr, size_t size) {
if (addr < sl->flash_base || addr >= (sl->flash_base + sl->flash_size)) {
ELOG("Invalid address, it should be within 0x%08x - 0x%08lx\n", sl->flash_base, (sl->flash_base + sl->flash_size -1));
Nightwalker-87 marked this conversation as resolved.
Show resolved Hide resolved
return (-1);
}
if ((addr + size) > (sl->flash_base + sl->flash_size)) {
ELOG("The size exceeds the size of the flash (0x%08lx bytes available)\n", (sl->flash_base + sl->flash_size - addr));
Nightwalker-87 marked this conversation as resolved.
Show resolved Hide resolved
return (-1);
}
return 0;
}

// Check if an address is aligned with the beginning of a page
int stlink_check_address_alignment(stlink_t *sl, stm32_addr_t addr) {
stm32_addr_t page = sl->flash_base;

while (page < addr) {
page += stlink_calculate_pagesize(sl, page);
}

if (page != addr) {
return -1;
}

return 0;
}

int stlink_erase_flash_section(stlink_t *sl, stm32_addr_t base_addr, size_t size, bool align_size) {
// Check the address and size validity
if (stlink_check_address_range_validity(sl, base_addr, size) < 0) {
return -1;
}

// Make sure the requested address is aligned with the beginning of a page
if (stlink_check_address_alignment(sl, base_addr) < 0) {
ELOG("The address to erase is not aligned with the beginning of a page\n");
return -1;
}

stm32_addr_t addr = base_addr;
do {
size_t page_size = stlink_calculate_pagesize(sl, addr);

// Check if size is aligned with a page, unless we want to completely erase the last page
if ((addr + page_size) > (base_addr + size) && !align_size) {
ELOG("Invalid size (not aligned with a page). Page size at address %#x is %#lx\n", addr, page_size);
Nightwalker-87 marked this conversation as resolved.
Show resolved Hide resolved
return -1;
}

if (stlink_erase_flash_page(sl, addr)) {
WLOG("Failed to erase_flash_page(%#x) == -1\n", addr);
return (-1);
}

fprintf(stdout, "-> Flash page at %#x erased (size: %#lx)\n", addr, page_size);
Nightwalker-87 marked this conversation as resolved.
Show resolved Hide resolved
fflush(stdout);

// check the next page is within the range to erase
addr += page_size;
} while (addr < (base_addr + size));

fprintf(stdout, "\n");
return 0;
}

int stlink_erase_flash_mass(stlink_t *sl) {
int err = 0;

// TODO: User MER bit to mass-erase WB series.
if (sl->flash_type == STLINK_FLASH_TYPE_L0 ||
sl->flash_type == STLINK_FLASH_TYPE_WB) {
// erase each page
int i = 0, num_pages = (int)(sl->flash_size / sl->flash_pgsz);

for (i = 0; i < num_pages; i++) {
// addr must be an addr inside the page
stm32_addr_t addr =
(stm32_addr_t)sl->flash_base + i * (stm32_addr_t)sl->flash_pgsz;

if (stlink_erase_flash_page(sl, addr)) {
WLOG("Failed to erase_flash_page(%#x) == -1\n", addr);
return (-1);
}
err = stlink_erase_flash_section(sl, sl->flash_base, sl->flash_size, false);

fprintf(stdout, "-> Flash page at %5d/%5d erased\n", i, num_pages);
fflush(stdout);
}

fprintf(stdout, "\n");
} else {
wait_flash_busy(sl);
clear_flash_error(sl);
Expand Down Expand Up @@ -3464,30 +3515,20 @@ int stlink_flashloader_stop(stlink_t *sl, flash_loader_t *fl) {

int stlink_write_flash(stlink_t *sl, stm32_addr_t addr, uint8_t *base,
uint32_t len, uint8_t eraseonly) {
size_t off;
int ret;
flash_loader_t fl;
ILOG("Attempting to write %d (%#x) bytes to stm32 address: %u (%#x)\n", len,
len, addr, addr);
// check addr range is inside the flash
stlink_calculate_pagesize(sl, addr);

if (addr < sl->flash_base) {
ELOG("addr too low %#x < %#x\n", addr, sl->flash_base);
return (-1);
} else if ((addr + len) < addr) {
ELOG("addr overruns\n");
return (-1);
} else if ((addr + len) > (sl->flash_base + sl->flash_size)) {
ELOG("addr too high\n");
return (-1);
} else if (addr & 1) {
ELOG("unaligned addr 0x%x\n", addr);
// Check the address and size validity
if (stlink_check_address_range_validity(sl, addr, len) < 0) {
return (-1);
} else if (len & 1) {
WLOG("unaligned len 0x%x -- padding with zero\n", len);
len += 1;
} else if (addr & (sl->flash_pgsz - 1)) {
} else if (stlink_check_address_alignment(sl, addr) < 0) {
ELOG("addr not a multiple of current pagesize (%u bytes), not supported, "
"check page start address and compare with flash module organisation "
"in related ST reference manual of your device.\n",
Expand All @@ -3498,24 +3539,12 @@ int stlink_write_flash(stlink_t *sl, stm32_addr_t addr, uint8_t *base,
// make sure we've loaded the context with the chip details
stlink_core_id(sl);

// Erase each page
int page_count = 0;

for (off = 0; off < len;
off += stlink_calculate_pagesize(sl, addr + (uint32_t)off)) {
// addr must be an addr inside the page
if (stlink_erase_flash_page(sl, addr + (uint32_t)off) == -1) {
ELOG("Failed to erase_flash_page(%#x) == -1\n", (unsigned)(addr + off));
return (-1);
}

ILOG("Flash page at addr: 0x%08lx erased\n", (unsigned long)(addr + off));
page_count++;
// Erase this section of the flash
if (stlink_erase_flash_section(sl, addr, len, true) < 0) {
ELOG("Failed to erase the flash prior to writing\n");
return (-1);
}

ILOG("Finished erasing %d pages of %u (%#x) bytes\n", page_count,
(unsigned)(sl->flash_pgsz), (unsigned)(sl->flash_pgsz));

if (eraseonly) {
return (0);
}
Expand Down
7 changes: 5 additions & 2 deletions src/st-flash/flash.c
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ static void cleanup(int signum) {

static void usage(void) {
puts("command line: ./st-flash [--debug] [--reset] [--connect-under-reset] [--hot-plug] [--opt] [--serial <serial>] [--format <format>] [--flash=<fsize>] [--freq=<kHz>] [--area=<area>] {read|write} [path] [addr] [size]");
puts("command line: ./st-flash [--debug] [--connect-under-reset] [--hot-plug] [--freq=<kHz>] [--serial <serial>] erase");
puts("command line: ./st-flash [--debug] [--connect-under-reset] [--hot-plug] [--freq=<kHz>] [--serial <serial>] erase [addr] [size]");
puts("command line: ./st-flash [--debug] [--freq=<kHz>] [--serial <serial>] reset");
puts(" <addr>, <serial> and <size>: Use hex format.");
puts(" <fsize>: Use decimal, octal or hex (prefix 0xXXX) format, optionally followed by k=KB, or m=MB (eg. --flash=128k)");
Expand Down Expand Up @@ -168,7 +168,10 @@ int main(int ac, char** av) {
goto on_error;
}
} else if (o.cmd == FLASH_CMD_ERASE) {
err = stlink_erase_flash_mass(sl);
if (o.size > 0 && o.addr > 0)
err = stlink_erase_flash_section(sl, o.addr, o.size, false);
else
err = stlink_erase_flash_mass(sl);

if (err == -1) {
printf("stlink_erase_flash_mass() == -1\n");
Expand Down
19 changes: 18 additions & 1 deletion src/st-flash/flash_opts.c
Original file line number Diff line number Diff line change
Expand Up @@ -234,7 +234,24 @@ int flash_get_opts(struct flash_opts* o, int ac, char** av) {
return(-1);

case FLASH_CMD_ERASE: // no more arguments expected
if (ac != 0) { return(-1); }
if (ac != 0 && ac != 2) { return(-1); }
if (ac == 2) {
uint32_t address;
result = get_integer_from_char_array(av[0], &address);
if (result != 0) {
return bad_arg ("addr");
} else {
o->addr = (stm32_addr_t) address;
}

uint32_t size;
result = get_integer_from_char_array(av[1], &size);
if (result != 0) {
return bad_arg ("size");
} else {
o->size = (size_t) size;
}
}

break;

Expand Down