Skip to content

Commit

Permalink
Merge pull request #1213 from antoinefaure/erase
Browse files Browse the repository at this point in the history
Erase addr size / section of the flash memory with st-flash
  • Loading branch information
Nightwalker-87 committed Jan 15, 2022
2 parents 2c62079 + 74957ef commit 541ab17
Show file tree
Hide file tree
Showing 4 changed files with 100 additions and 48 deletions.
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));
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));
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);
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);
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

0 comments on commit 541ab17

Please sign in to comment.