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 <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);
|
||||
|
||||
|
|
Loading…
Reference in New Issue