From 993c74bef471657981467fe312dfcee45d9da44d Mon Sep 17 00:00:00 2001 From: Ben Tober Date: Thu, 22 Jul 2021 09:49:38 -0400 Subject: [PATCH] lpc: Fix bugs related to flash on LPC MCUs - A previous comment in lpc546xx.c was incorrect - one cannot rely on resetting the target to leave the main clock set to the 12MHz FRO. - A comparison in lpc_common.c was incorrect causing flash erase not to work. - The IAP API status field was not being explicitly initialized. If somehow an API call didn't execute properly (for example if it caused an exception), we might not notice. This is fixed by initializing the status to a value that the API would never return. --- src/target/lpc546xx.c | 15 +++++++++++++-- src/target/lpc_common.c | 1 + 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/src/target/lpc546xx.c b/src/target/lpc546xx.c index 3b395d4..5a7e896 100644 --- a/src/target/lpc546xx.c +++ b/src/target/lpc546xx.c @@ -40,6 +40,11 @@ #define LPC546XX_WDT_PERIOD_MAX 0xFFFFFF #define LPC546XX_WDT_PROTECT (1 << 4) +#define LPC546XX_MAINCLKSELA 0x40000280 +#define LPC546XX_MAINCLKSELB 0x40000284 +#define LPC546XX_AHBCLKDIV 0x40000380 +#define LPC546XX_FLASHCFG 0x40000400 + #define IAP_RAM_SIZE LPC546XX_ETBAHB_SRAM_SIZE #define IAP_RAM_BASE LPC546XX_ETBAHB_SRAM_BASE @@ -280,13 +285,19 @@ static int lpc546xx_flash_init(target *t) { /* Reset the chip. It's unfortunate but we need to make sure the ROM bootloader is no longer mapped to 0x0 or flash blank check won't work after - erasing that sector. Resetting will also set the main clock back to default - 12MHZ FRO; that value is required for some IAP routines. */ + erasing that sector. Additionally, the ROM itself may increase the + main clock frequency during its own operation, so we need to force + it back to the 12MHz FRO to guarantee correct flash timing for + the IAP API */ lpc546xx_reset_attach(t); /* Deal with WDT */ lpc546xx_wdt_set_period(t); + target_mem_write32(t, LPC546XX_MAINCLKSELA, 0); // 12MHz FRO + target_mem_write32(t, LPC546XX_MAINCLKSELB, 0); // use MAINCLKSELA + target_mem_write32(t, LPC546XX_AHBCLKDIV, 0); // Divide by 1 + target_mem_write32(t, LPC546XX_FLASHCFG, 0x1a); // recommended default return 0; } diff --git a/src/target/lpc_common.c b/src/target/lpc_common.c index fac7bf9..f348672 100644 --- a/src/target/lpc_common.c +++ b/src/target/lpc_common.c @@ -110,6 +110,7 @@ enum iap_status lpc_iap_call(struct lpc_flash *f, void *result, enum iap_cmd cmd struct flash_param param = { .opcode = ARM_THUMB_BREAKPOINT, .command = cmd, + .status = 0xdeadbeef, // to help us see if the IAP didn't execute }; /* Pet WDT before each IAP call, if it is on */