diff --git a/src/flash/nor/stm32lx.c b/src/flash/nor/stm32lx.c index 264a45ca6..fc0fb9e1a 100644 --- a/src/flash/nor/stm32lx.c +++ b/src/flash/nor/stm32lx.c @@ -32,6 +32,7 @@ #include #include #include +#include /* stm32lx flash register locations */ @@ -299,6 +300,18 @@ static int stm32lx_write_half_pages(struct flash_bank *bank, uint8_t *buffer, return retval; } + struct armv7m_common *armv7m = target_to_armv7m(target); + if (armv7m == NULL) { + + /* something is very wrong if armv7m is NULL */ + LOG_ERROR("unable to get armv7m target"); + return retval; + } + + /* save any DEMCR flags and configure target to catch any Hard Faults */ + uint32_t demcr_save = armv7m->demcr; + armv7m->demcr = VC_HARDERR; + /* Loop while there are bytes to write */ while (count > 0) { uint32_t this_count; @@ -324,6 +337,10 @@ static int stm32lx_write_half_pages(struct flash_bank *bank, uint8_t *buffer, if (retval != ERROR_OK) break; + /* check for Hard Fault */ + if (armv7m->exception_number == 3) + break; + /* 6: Wait while busy */ retval = stm32lx_wait_until_bsy_clear(bank); if (retval != ERROR_OK) @@ -334,6 +351,42 @@ static int stm32lx_write_half_pages(struct flash_bank *bank, uint8_t *buffer, count -= this_count; } + /* restore previous flags */ + armv7m->demcr = demcr_save; + + if (armv7m->exception_number == 3) { + + /* the stm32l15x devices seem to have an issue when blank. + * if a ram loader is executed on a blank device it will + * Hard Fault, this issue does not happen for a already programmed device. + * A related issue is described in the stm32l151xx errata (Doc ID 17721 Rev 6 - 2.1.3). + * The workaround of handling the Hard Fault exception does work, but makes the + * loader more complicated, as a compromise we manually write the pages, programming time + * is reduced by 50% using this slower method. + */ + + LOG_WARNING("couldn't use loader, falling back to page memory writes"); + + while (count > 0) { + uint32_t this_count; + this_count = (count > 128) ? 128 : count; + + /* Write the next half pages */ + retval = target_write_buffer(target, address, this_count, buffer); + if (retval != ERROR_OK) + break; + + /* Wait while busy */ + retval = stm32lx_wait_until_bsy_clear(bank); + if (retval != ERROR_OK) + break; + + buffer += this_count; + address += this_count; + count -= this_count; + } + } + if (retval == ERROR_OK) retval = stm32lx_lock_program_memory(bank);