This is an automated email from Gerrit. nh minus ([email protected]) just uploaded a new patch set to Gerrit, which you can find at http://openocd.zylin.com/5597
-- gerrit commit 1e494caaac21543ed45f850e86853b0157e749a3 Author: Jimmy <[email protected]> Date: Thu Apr 23 21:03:37 2020 +0800 flash/nor/stm32lx: speed up erases The flash program time is dominated by a slow erase, so we move the tight erase loop onto the target for a 40% reduction in programming time. Change-Id: I3a07937c9001451c3bb59bf41991ee89ea6170d3 Signed-off-by: Jimmy <[email protected]> diff --git a/contrib/loaders/flash/stm32/Makefile b/contrib/loaders/flash/stm32/Makefile index b58b412..f9e07a8 100644 --- a/contrib/loaders/flash/stm32/Makefile +++ b/contrib/loaders/flash/stm32/Makefile @@ -8,7 +8,7 @@ OBJDUMP=$(CROSS_COMPILE)objdump CFLAGS = -static -nostartfiles -mlittle-endian -Wa,-EL -all: stm32f1x.inc stm32f2x.inc stm32h7x.inc stm32l4x.inc stm32lx.inc +all: stm32f1x.inc stm32f2x.inc stm32h7x.inc stm32l4x.inc stm32lx.inc stm32lx_erase.inc .PHONY: clean diff --git a/contrib/loaders/flash/stm32/stm32lx_erase.S b/contrib/loaders/flash/stm32/stm32lx_erase.S new file mode 100644 index 0000000..eb4d27b --- /dev/null +++ b/contrib/loaders/flash/stm32/stm32lx_erase.S @@ -0,0 +1,69 @@ +/*************************************************************************** + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * 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 base address + r1 - pages + r2 - bytes per page + r3 - flash base +Variables + r0 - destination erase pointer + r1 - destination limit pointer + r2 - bytes per page + r3 - flash base + r4 - temporary r/w + r5 - erase command + r6 - 0 +*/ + +/* offsets of registers from flash reg base */ +#define STM32_FLASH_PECR 0x04 +#define STM32_FLASH_SR_OFFSET 0x18 + + .thumb_func + .global _start +_start: + movs r5, #0x41 /* set bits 3 and 9 (program and erase) */ + lsls r5, 3 + movs r6, #0 /* zero for the erase command */ + muls r1, r1, r2 /* calculate limit = base + pages * pagesize */ + add r1, r1, r0 + b test_done /* check loop condition */ +arm_erase: + str r5, [r3, #STM32_FLASH_PECR] +wait_busy1: + ldr r4, [r3, #STM32_FLASH_SR_OFFSET] + lsls r4, r4, #31 + bne wait_busy1 + str r6, [r0] /* start the erase */ + add r0, r0, r2 /* calc next erase address */ +wait_busy2: + ldr r4, [r3, #STM32_FLASH_SR_OFFSET] + lsls r4, r4, #31 + bne wait_busy2 +test_done: + cmp r0, r1 + bne arm_erase + +exit: + bkpt #0x00 diff --git a/contrib/loaders/flash/stm32/stm32lx_erase.inc b/contrib/loaders/flash/stm32/stm32lx_erase.inc new file mode 100644 index 0000000..011a4de --- /dev/null +++ b/contrib/loaders/flash/stm32/stm32lx_erase.inc @@ -0,0 +1,4 @@ +/* Autogenerated with ../../../../src/helper/bin2char.sh */ +0x41,0x25,0xed,0x00,0x00,0x26,0x51,0x43,0x01,0x44,0x08,0xe0,0x5d,0x60,0x9c,0x69, +0xe4,0x07,0xfc,0xd1,0x06,0x60,0x10,0x44,0x9c,0x69,0xe4,0x07,0xfc,0xd1,0x88,0x42, +0xf4,0xd1,0x00,0xbe, diff --git a/src/flash/nor/stm32lx.c b/src/flash/nor/stm32lx.c index c3f9c72..fb594cd 100644 --- a/src/flash/nor/stm32lx.c +++ b/src/flash/nor/stm32lx.c @@ -99,7 +99,6 @@ static int stm32lx_unlock_program_memory(struct flash_bank *bank); static int stm32lx_lock_program_memory(struct flash_bank *bank); static int stm32lx_enable_write_half_page(struct flash_bank *bank); -static int stm32lx_erase_sector(struct flash_bank *bank, int sector); static int stm32lx_wait_until_bsy_clear(struct flash_bank *bank); static int stm32lx_lock(struct flash_bank *bank); static int stm32lx_unlock(struct flash_bank *bank); @@ -399,26 +398,88 @@ static int stm32lx_protect_check(struct flash_bank *bank) static int stm32lx_erase(struct flash_bank *bank, int first, int last) { int retval; + struct target *target = bank->target; + struct stm32lx_flash_bank *stm32lx_info = bank->driver_priv; + struct working_area *erase_algorithm; + struct reg_param reg_params[4]; + struct armv7m_algorithm armv7m_info; + static const uint8_t stm32lx_flash_erase_code[] = { +#include "../../../contrib/loaders/flash/stm32/stm32lx_erase.inc" + }; /* * It could be possible to do a mass erase if all sectors must be * erased, but it is not implemented yet. */ - if (bank->target->state != TARGET_HALTED) { + if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } - /* - * Loop over the selected sectors and erase them - */ - for (int i = first; i <= last; i++) { - retval = stm32lx_erase_sector(bank, i); - if (retval != ERROR_OK) - return retval; - bank->sectors[i].is_erased = 1; + /* Allocate the erase code */ + if (target_alloc_working_area(target, sizeof(stm32lx_flash_erase_code), + &erase_algorithm) != ERROR_OK) { + LOG_DEBUG("no working area for block memory writes"); + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + } + + /* Write the erase code */ + retval = target_write_buffer(target, + erase_algorithm->address, + sizeof(stm32lx_flash_erase_code), + stm32lx_flash_erase_code); + if (retval != ERROR_OK) { + target_free_working_area(target, erase_algorithm); + return retval; + } + + armv7m_info.common_magic = ARMV7M_COMMON_MAGIC; + armv7m_info.core_mode = ARM_MODE_THREAD; + 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); + + retval = stm32lx_unlock_program_memory(bank); + if (retval != ERROR_OK) { + target_free_working_area(target, erase_algorithm); + destroy_reg_param(®_params[0]); + destroy_reg_param(®_params[1]); + destroy_reg_param(®_params[2]); + destroy_reg_param(®_params[3]); + return retval; } + + /* Pass parameters */ + uint32_t totalBytes = bank->sectors[last].offset + bank->sectors[last].size - bank->sectors[first].offset; + uint32_t totalPages = totalBytes / stm32lx_info->part_info.page_size; + buf_set_u32(reg_params[0].value, 0, 32, bank->base + bank->sectors[first].offset); + buf_set_u32(reg_params[1].value, 0, 32, totalPages); + buf_set_u32(reg_params[2].value, 0, 32, stm32lx_info->part_info.page_size); + buf_set_u32(reg_params[3].value, 0, 32, stm32lx_info->flash_base); + + /* Execute the erase code */ + retval = target_run_algorithm(target, 0, NULL, sizeof(reg_params) + / sizeof(*reg_params), reg_params, + erase_algorithm->address, 0, 5000 + totalPages * 8, &armv7m_info); + + target_free_working_area(target, erase_algorithm); + destroy_reg_param(®_params[0]); + destroy_reg_param(®_params[1]); + destroy_reg_param(®_params[2]); + destroy_reg_param(®_params[3]); + + if (retval != ERROR_OK) + return retval; + + retval = stm32lx_lock_program_memory(bank); + if (retval != ERROR_OK) + return retval; + + for (int i = first; i <= last; i++) + bank->sectors[i].is_erased = 1; + return ERROR_OK; } @@ -1094,53 +1155,6 @@ static int stm32lx_lock_program_memory(struct flash_bank *bank) return ERROR_OK; } -static int stm32lx_erase_sector(struct flash_bank *bank, int sector) -{ - struct target *target = bank->target; - struct stm32lx_flash_bank *stm32lx_info = bank->driver_priv; - int retval; - uint32_t reg32; - - /* - * To erase a sector (i.e. stm32lx_info->part_info.pages_per_sector pages), - * first unlock the memory, loop over the pages of this sector - * and write 0x0 to its first word. - */ - - retval = stm32lx_unlock_program_memory(bank); - if (retval != ERROR_OK) - return retval; - - for (int page = 0; page < (int)stm32lx_info->part_info.pages_per_sector; - page++) { - reg32 = FLASH_PECR__PROG | FLASH_PECR__ERASE; - retval = target_write_u32(target, - stm32lx_info->flash_base + FLASH_PECR, reg32); - if (retval != ERROR_OK) - return retval; - - retval = stm32lx_wait_until_bsy_clear(bank); - if (retval != ERROR_OK) - return retval; - - uint32_t addr = bank->base + bank->sectors[sector].offset + (page - * stm32lx_info->part_info.page_size); - retval = target_write_u32(target, addr, 0x0); - if (retval != ERROR_OK) - return retval; - - retval = stm32lx_wait_until_bsy_clear(bank); - if (retval != ERROR_OK) - return retval; - } - - retval = stm32lx_lock_program_memory(bank); - if (retval != ERROR_OK) - return retval; - - return ERROR_OK; -} - static inline int stm32lx_get_flash_status(struct flash_bank *bank, uint32_t *status) { struct target *target = bank->target; -- _______________________________________________ OpenOCD-devel mailing list [email protected] https://lists.sourceforge.net/lists/listinfo/openocd-devel
