From d631b2e5aca26e96fb6feed2aceb40632bdfca71 Mon Sep 17 00:00:00 2001 From: Spencer Oliver Date: Fri, 4 Jan 2013 11:46:00 +0000 Subject: [PATCH] flash: add stm32lx loader Hard Fault workaround An issue has been seen with the stm32lx flash driver that if a power cycle/reset is applied after a erase, any ram loader will Hard Fault on execution. A similar issue is mentioned in the errata for the device. Two solution's seem to workaround this issue: 1, Handle the exception, this means adding exception vectors to the loader and changing the exception address using nvic vtor register. 2. falling back to using slower direct page writes - approx 50% slower. Using solution 1 would mean restrictions are placed on the loader location. Solution 2 was chosen mainly as it was simpler too implement. Change-Id: I429f06b5a3e3b1d8de90071a88a7df11fc9b46a7 Signed-off-by: Spencer Oliver Reviewed-on: http://openocd.zylin.com/1010 Tested-by: jenkins --- src/flash/nor/stm32lx.c | 53 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/src/flash/nor/stm32lx.c b/src/flash/nor/stm32lx.c index 264a45ca6e..fc0fb9e1ae 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); -- 2.30.2