diff --git a/contrib/loaders/flash/stm32/stm32lx.S b/contrib/loaders/flash/stm32/stm32lx.S index bcae7a46c..7cfe48545 100644 --- a/contrib/loaders/flash/stm32/stm32lx.S +++ b/contrib/loaders/flash/stm32/stm32lx.S @@ -20,44 +20,61 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * ***************************************************************************/ - .text .syntax unified .cpu cortex-m0 .thumb /* +Parameters r0 - destination address r1 - source address - r2 - count + r2 - half pages + r3 - bytes per half page + r4 - flash base +Variables + r0 - destination write pointer + r1 - source read pointer + r2 - source limit address + r3 - bytes per half page + r4 - flash base + r5 - pages left in current half page + r6 - temporary r/w */ +/* offsets of registers from flash reg base */ +#define STM32_FLASH_SR_OFFSET 0x18 + .thumb_func .global _start _start: - // r2 = source + count * 4 - lsls r2, r2, #2 - adds r2, r1, r2 + // r2 = source + half pages * bytes per half page + muls r2, r2, r3 + add r2, r1, r2 // Go to compare - b test_done + b test_done +write_half_page: + // initialize pages left in current half page + mov r5, r3 write_word: // load word from address in r1 and increase r1 by 4 - ldmia r1!, {r3} + ldmia r1!, {r6} // store word to address in r0 and increase r0 by 4 - stmia r0!, {r3} + stmia r0!, {r6} + // check for end of half page + subs r5, r5, #4 + bne write_word +wait_busy: + // read status register into r6, loop while bottom bit is set + ldr r6, [r4, #STM32_FLASH_SR_OFFSET] + lsls r6, r6, #31 + bne wait_busy test_done: - // compare r1 and r2 + // compare r1 and r2, loop if not equal cmp r1, r2 - // loop if not equal - bne write_word + bne write_half_page // Set breakpoint to exit - bkpt #0x00 - + bkpt #0x00 diff --git a/contrib/loaders/flash/stm32/stm32lx.inc b/contrib/loaders/flash/stm32/stm32lx.inc index eaaf1848a..668de2778 100644 --- a/contrib/loaders/flash/stm32/stm32lx.inc +++ b/contrib/loaders/flash/stm32/stm32lx.inc @@ -1,2 +1,3 @@ /* Autogenerated with ../../../../src/helper/bin2char.sh */ -0x92,0x00,0x8a,0x18,0x01,0xe0,0x08,0xc9,0x08,0xc0,0x91,0x42,0xfb,0xd1,0x00,0xbe, +0x5a,0x43,0x0a,0x44,0x07,0xe0,0x1d,0x46,0x40,0xc9,0x40,0xc0,0x04,0x3d,0xfb,0xd1, +0xa6,0x69,0xf6,0x07,0xfc,0xd1,0x91,0x42,0xf5,0xd1,0x00,0xbe, diff --git a/src/flash/nor/stm32lx.c b/src/flash/nor/stm32lx.c index 488dc978a..122119606 100644 --- a/src/flash/nor/stm32lx.c +++ b/src/flash/nor/stm32lx.c @@ -425,12 +425,12 @@ static int stm32lx_write_half_pages(struct flash_bank *bank, const uint8_t *buff struct stm32lx_flash_bank *stm32lx_info = bank->driver_priv; uint32_t hp_nb = stm32lx_info->part_info.page_size / 2; - uint32_t buffer_size = 16384; + uint32_t buffer_size = (16384 / hp_nb) * hp_nb; /* must be multiple of hp_nb */ struct working_area *write_algorithm; struct working_area *source; uint32_t address = bank->base + offset; - struct reg_param reg_params[3]; + struct reg_param reg_params[5]; struct armv7m_algorithm armv7m_info; int retval = ERROR_OK; @@ -440,6 +440,10 @@ static int stm32lx_write_half_pages(struct flash_bank *bank, const uint8_t *buff }; /* Make sure we're performing a half-page aligned write. */ + if (offset % hp_nb) { + LOG_ERROR("The offset must be %" PRIu32 "B-aligned but it is %" PRIi32 "B)", hp_nb, offset); + return ERROR_FAIL; + } if (count % hp_nb) { LOG_ERROR("The byte count must be %" PRIu32 "B-aligned but count is %" PRIu32 "B)", hp_nb, count); return ERROR_FAIL; @@ -476,6 +480,9 @@ static int stm32lx_write_half_pages(struct flash_bank *bank, const uint8_t *buff LOG_WARNING("no large enough working area available, can't do block memory writes"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + } else { + /* Make sure we're still asking for an integral number of half-pages */ + buffer_size -= buffer_size % hp_nb; } } @@ -484,6 +491,8 @@ static int stm32lx_write_half_pages(struct flash_bank *bank, const uint8_t *buff init_reg_param(®_params[0], "r0", 32, PARAM_OUT); init_reg_param(®_params[1], "r1", 32, PARAM_OUT); init_reg_param(®_params[2], "r2", 32, PARAM_OUT); + init_reg_param(®_params[3], "r3", 32, PARAM_OUT); + init_reg_param(®_params[4], "r4", 32, PARAM_OUT); /* Enable half-page write */ retval = stm32lx_enable_write_half_page(bank); @@ -494,6 +503,8 @@ static int stm32lx_write_half_pages(struct flash_bank *bank, const uint8_t *buff destroy_reg_param(®_params[0]); destroy_reg_param(®_params[1]); destroy_reg_param(®_params[2]); + destroy_reg_param(®_params[3]); + destroy_reg_param(®_params[4]); return retval; } @@ -524,8 +535,12 @@ static int stm32lx_write_half_pages(struct flash_bank *bank, const uint8_t *buff buf_set_u32(reg_params[0].value, 0, 32, address); /* The source address of the copy (R1) */ buf_set_u32(reg_params[1].value, 0, 32, source->address); - /* The length of the copy (R2) */ - buf_set_u32(reg_params[2].value, 0, 32, this_count / 4); + /* The number of half pages to copy (R2) */ + buf_set_u32(reg_params[2].value, 0, 32, this_count / hp_nb); + /* The size in byes of a half page (R3) */ + buf_set_u32(reg_params[3].value, 0, 32, hp_nb); + /* The flash base address (R4) */ + buf_set_u32(reg_params[4].value, 0, 32, stm32lx_info->flash_base); /* 5: Execute the bunch of code */ retval = target_run_algorithm(target, 0, NULL, @@ -593,6 +608,8 @@ static int stm32lx_write_half_pages(struct flash_bank *bank, const uint8_t *buff destroy_reg_param(®_params[0]); destroy_reg_param(®_params[1]); destroy_reg_param(®_params[2]); + destroy_reg_param(®_params[3]); + destroy_reg_param(®_params[4]); return retval; }