aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorSpencer Oliver <spen@spen-soft.co.uk>2013-01-04 11:46:00 +0000
committerSpencer Oliver <spen@spen-soft.co.uk>2013-01-21 16:46:09 +0000
commitd631b2e5aca26e96fb6feed2aceb40632bdfca71 (patch)
treeba06485537949fcce361a1a7416e6b6fc2c1a35b /src
parent6efcd943b28cf904362283226b3f51cf52ce3252 (diff)
downloadriscv-openocd-d631b2e5aca26e96fb6feed2aceb40632bdfca71.zip
riscv-openocd-d631b2e5aca26e96fb6feed2aceb40632bdfca71.tar.gz
riscv-openocd-d631b2e5aca26e96fb6feed2aceb40632bdfca71.tar.bz2
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 <spen@spen-soft.co.uk> Reviewed-on: http://openocd.zylin.com/1010 Tested-by: jenkins
Diffstat (limited to 'src')
-rw-r--r--src/flash/nor/stm32lx.c53
1 files changed, 53 insertions, 0 deletions
diff --git a/src/flash/nor/stm32lx.c b/src/flash/nor/stm32lx.c
index 264a45c..fc0fb9e 100644
--- a/src/flash/nor/stm32lx.c
+++ b/src/flash/nor/stm32lx.c
@@ -32,6 +32,7 @@
#include <helper/binarybuffer.h>
#include <target/algorithm.h>
#include <target/armv7m.h>
+#include <target/cortex_m.h>
/* 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);