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
This commit is contained in:
parent
6efcd943b2
commit
d631b2e5ac
|
@ -32,6 +32,7 @@
|
||||||
#include <helper/binarybuffer.h>
|
#include <helper/binarybuffer.h>
|
||||||
#include <target/algorithm.h>
|
#include <target/algorithm.h>
|
||||||
#include <target/armv7m.h>
|
#include <target/armv7m.h>
|
||||||
|
#include <target/cortex_m.h>
|
||||||
|
|
||||||
/* stm32lx flash register locations */
|
/* stm32lx flash register locations */
|
||||||
|
|
||||||
|
@ -299,6 +300,18 @@ static int stm32lx_write_half_pages(struct flash_bank *bank, uint8_t *buffer,
|
||||||
return retval;
|
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 */
|
/* Loop while there are bytes to write */
|
||||||
while (count > 0) {
|
while (count > 0) {
|
||||||
uint32_t this_count;
|
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)
|
if (retval != ERROR_OK)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
/* check for Hard Fault */
|
||||||
|
if (armv7m->exception_number == 3)
|
||||||
|
break;
|
||||||
|
|
||||||
/* 6: Wait while busy */
|
/* 6: Wait while busy */
|
||||||
retval = stm32lx_wait_until_bsy_clear(bank);
|
retval = stm32lx_wait_until_bsy_clear(bank);
|
||||||
if (retval != ERROR_OK)
|
if (retval != ERROR_OK)
|
||||||
|
@ -334,6 +351,42 @@ static int stm32lx_write_half_pages(struct flash_bank *bank, uint8_t *buffer,
|
||||||
count -= this_count;
|
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)
|
if (retval == ERROR_OK)
|
||||||
retval = stm32lx_lock_program_memory(bank);
|
retval = stm32lx_lock_program_memory(bank);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue