Hi,

I get a flash_init() failed trying to program an LPC55S69. Any Ideas?

Best,
Rolf


I: Launching gdb-server: openocd -c "gdb_port 50000" -c "tcl_port 50002" -c 
"telnet_port 50004" -s /usr/local/share/openocd/scripts -c "set 
FLASH_API_ADDRESS 0x030010f0" -f 
/Users/rolf/.vscode/extensions/onethinx.cortex-gdb-1.0.2/support/openocd-helpers.tcl
 -f interface/cmsis-dap.cfg -f target/lpc55xx.cfg -c "transport select swd" -c 
"adapter_khz 1000"



I:     Please check TERMINAL tab (gdb-server) for output from openocd



I: Finished reading symbols from objdump: Time: 210 ms



S: Open On-Chip Debugger 0.12.0+dev-00461-g6c7521591-dirty (2025-04-28-23:17)



S: Licensed under GNU GPL v2



S: For bug reports, read



S: http://openocd.org/doc/doxygen/bugs.html



S: 0x030010f0



S: CDLiveWatchSetup



S: Info : auto-selecting first available session transport "swd". To override 
use 'transport select <transport>'.


S: adapter speed: 1000 kHz


S: Info : Listening on port 50002 for tcl connections


S: Info : Listening on port 50004 for telnet connections


I: Finished reading symbols from nm: Time: 310 ms


S: Info : CMSIS-DAP: SWD supported


S: Info : CMSIS-DAP: Atomic commands supported


S: Info : CMSIS-DAP: FW Version = 1.10


S: Info : CMSIS-DAP: Serial# = 1402B011


S: Info : CMSIS-DAP: Interface Initialised (SWD)


S: Info : SWCLK/TCK = 1 SWDIO/TMS = 0 TDI = 0 TDO = 0 nTRST = 0 nRESET = 1


S: Info : CMSIS-DAP: Interface ready


S: Info : clock speed 1000 kHz


S: Info : SWD DPIDR 0x6ba02477


S: Info : [lpc55xx.cpu] Cortex-M33 r0p3 processor detected


S: Info : [lpc55xx.cpu] target has 8 breakpoints, 4 watchpoints


S: Info : [lpc55xx.cpu] Examination succeed


S: Info : starting gdb server for lpc55xx.cpu on 50000


S: Info : Listening on port 50000 for gdb connections


S: Info : accepting 'gdb' connection on tcp/50000


S: Warn : [lpc55xx.cpu] target was in unknown state when halt was requested


S: Info : SWD DPIDR 0x6ba02477

S: Info : [lpc55xx.cpu] external reset detected


S: [lpc55xx.cpu] halted due to debug-request, current mode: Thread


S: xPSR: 0x41000000 pc: 0x00019e02 psp: 0x20003ae8


S: Error: flash_init() failed


Op 25 mrt 2024, om 21:53 heeft ger...@openocd.org het volgende geschreven:

This is an automated email from Gerrit.

"Paul Fertser <fercer...@gmail.com>" just uploaded a new patch set to Gerrit, 
which you can find at https://review.openocd.org/c/openocd/+/8189

-- gerrit

commit 7f1e8bd108cbd5ac686bf502d9665dd8544a664e
Author: Paul Fertser <fercer...@gmail.com>
Date:   Wed Feb 7 14:02:23 2024 +0300

   flash: nor: lpc55xx support

   Tested on LPC55S36 LPCXpresso board.

   Valgrind-clean.

   Signed-off-by: Paul Fertser <fercer...@gmail.com>
   Change-Id: Ifc73d5774838bf0455e4422d5a63b19eab949646

diff --git a/doc/openocd.texi b/doc/openocd.texi
index 6b71fe869d..a7f381bf07 100644
--- a/doc/openocd.texi
+++ b/doc/openocd.texi
@@ -7158,6 +7158,25 @@ lpc2900 secure_jtag 0
@end deffn
@end deffn

+@deffn {Flash Driver} {lpc55xx}
+This the flash driver using ROM API functions provided by NXP LPC55xx family
+MCUs.
+
+The @var{lpc55xx} driver defines one mandatory parameter, the address of the
+flash API ROM table. If 0 is passed the driver will try to auto-detect based on
+device ID.
+
+The MCU will appear unresponsive when the first flash sector doesn't contain
+valid firmware header (e.g. when the flash is blank), to attach to the target
+@code{lpc55xx_start_debug_session} procedure is offered by the target config.
+
+Sector protection is not implemented.
+
+@example
+flash bank $_FLASHNAME lpc55xx 0 0 0 0 0 0
+@end example
+@end deffn
+
@deffn {Flash Driver} {mdr}
This drivers handles the integrated NOR flash on Milandr Cortex-M
based controllers. A known limitation is that the Info memory can't be
diff --git a/src/flash/nor/Makefile.am b/src/flash/nor/Makefile.am
index 534a7a804e..23012e3c10 100644
--- a/src/flash/nor/Makefile.am
+++ b/src/flash/nor/Makefile.am
@@ -39,6 +39,7 @@ NOR_DRIVERS = \
%D%/lpc2000.c \
%D%/lpc288x.c \
%D%/lpc2900.c \
+ %D%/lpc55xx.c \
%D%/lpcspifi.c \
%D%/max32xxx.c \
%D%/mdr.c \
diff --git a/src/flash/nor/driver.h b/src/flash/nor/driver.h
index a63b72c8fa..3851058f36 100644
--- a/src/flash/nor/driver.h
+++ b/src/flash/nor/driver.h
@@ -267,6 +267,7 @@ extern const struct flash_driver kinetis_ke_flash;
extern const struct flash_driver lpc2000_flash;
extern const struct flash_driver lpc288x_flash;
extern const struct flash_driver lpc2900_flash;
+extern const struct flash_driver lpc55xx_flash;
extern const struct flash_driver lpcspifi_flash;
extern const struct flash_driver max32xxx_flash;
extern const struct flash_driver mdr_flash;
diff --git a/src/flash/nor/drivers.c b/src/flash/nor/drivers.c
index 3157bd3292..fa1d4be554 100644
--- a/src/flash/nor/drivers.c
+++ b/src/flash/nor/drivers.c
@@ -44,6 +44,7 @@ static const struct flash_driver * const flash_drivers[] = {
&lpc2000_flash,
&lpc288x_flash,
&lpc2900_flash,
+ &lpc55xx_flash,
&lpcspifi_flash,
&max32xxx_flash,
&mdr_flash,
diff --git a/src/flash/nor/lpc55xx.c b/src/flash/nor/lpc55xx.c
new file mode 100644
index 0000000000..7138bffe8a
--- /dev/null
+++ b/src/flash/nor/lpc55xx.c
@@ -0,0 +1,288 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+/***************************************************************************
+ * Copyright (C) 2024  Transcelestial Technologies PTE LTD                 *
+ * Paul Fertser <fercer...@gmail.com>                                      *
+ ***************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "imp.h"
+#include <helper/binarybuffer.h>
+#include <target/algorithm.h>
+#include <target/arm_opcodes.h>
+#include <target/armv7m.h>
+
+/**
+ * @file
+ * Flash programming support for NXP LPC55xx series (tested on LPC55S36 1B)
+ */
+
+#define LPC55XX_DEVICEID_REG 0x40000ff8
+#define LPC55XX_DIEID_REG 0x40000ffc
+
+#define API_FLASH_INIT 1
+#define API_FLASH_ERASE 2
+#define API_FLASH_PROGRAM 3
+#define API_FLASH_VERIFY_ERASE 4
+
+#define BANK_WA_SIZE 1024
+
+struct lpc55xx_flash_bank {
+ bool probed;
+ uint32_t flash_api_table;
+ struct working_area *wa;
+};
+
+FLASH_BANK_COMMAND_HANDLER(lpc55xx_flash_bank_command)
+{
+ struct lpc55xx_flash_bank *lpc55xx_info;
+
+ if (CMD_ARGC < 7)
+ return ERROR_COMMAND_SYNTAX_ERROR;
+
+ lpc55xx_info = calloc(1, sizeof(struct lpc55xx_flash_bank));
+
+ bank->driver_priv = lpc55xx_info;
+ lpc55xx_info->probed = false;
+ COMMAND_PARSE_NUMBER(uint, CMD_ARGV[6], lpc55xx_info->flash_api_table);
+
+ return ERROR_OK;
+}
+
+static int lpc55xx_api_call(struct flash_bank *bank, unsigned int func, int 
regs, struct reg_param reg_params[])
+{
+ struct lpc55xx_flash_bank *lpc55xx_info = bank->driver_priv;
+ struct target *target = bank->target;
+ struct armv7m_algorithm armv7m_info;
+ uint32_t func_addr;
+ uint32_t status;
+
+ if (!lpc55xx_info->wa) {
+ if (target_alloc_working_area(target, BANK_WA_SIZE, &lpc55xx_info->wa) != 
ERROR_OK) {
+ LOG_ERROR("No working area specified, can not use flash API");
+ return ERROR_FAIL;
+ }
+
+ /* We'll be using this as LR target to halt after API function call */
+ target_write_u32(target, lpc55xx_info->wa->address, ARMV5_T_BKPT(0));
+ }
+
+ target_read_u32(target, lpc55xx_info->flash_api_table + 4 * func, &func_addr);
+
+ /* we have bkpt #0 there in the beginning of wa */
+ init_reg_param(&reg_params[0], "lr", 32, PARAM_OUT);
+ buf_set_u32(reg_params[0].value, 0, 32, lpc55xx_info->wa->address | 1);
+ /* TODO what to set SP to?.. Can we count on "reset init" to leave it in 
suitable state? */
+ /*
+ init_reg_param(&reg_params[1], "sp", 32, PARAM_OUT);
+ buf_set_u32(reg_params[1].value, 0, 32, lpc55xx_info->wa->address + 
BANK_WA_SIZE);
+ */
+ /* dummy set to keep the count */
+ init_reg_param(&reg_params[1], "r0", 32, PARAM_OUT);
+ buf_set_u32(reg_params[1].value, 0, 32, 0);
+ init_reg_param(&reg_params[2], "r0", 32, PARAM_IN_OUT);
+ buf_set_u32(reg_params[2].value, 0, 32, lpc55xx_info->wa->address + 4);
+
+ armv7m_info.common_magic = ARMV7M_COMMON_MAGIC;
+ armv7m_info.core_mode = ARM_MODE_THREAD;
+ target_run_algorithm(target, 0, NULL, regs, reg_params, func_addr - 1, 0, 
10000, &armv7m_info);
+
+ status = buf_get_u32(reg_params[2].value, 0, 32);
+ LOG_DEBUG("API call %d status 0x%8.8" PRIx32, func, status);
+
+ for (int i = 0; i < regs; i++)
+ destroy_reg_param(&reg_params[i]);
+
+ return status;
+}
+
+static int lpc55xx_erase(struct flash_bank *bank, unsigned int first,
+ unsigned int last)
+{
+ struct reg_param reg_params[6];
+ size_t sectors_size = 0;
+ int api_status;
+
+ for (size_t i = first; i <= last; i++)
+ sectors_size += bank->sectors[i].size;
+
+ init_reg_param(&reg_params[3], "r1", 32, PARAM_IN_OUT);
+ buf_set_u32(reg_params[3].value, 0, 32, bank->base + 
bank->sectors[first].offset);
+ init_reg_param(&reg_params[4], "r2", 32, PARAM_IN_OUT);
+ buf_set_u32(reg_params[4].value, 0, 32, sectors_size);
+ init_reg_param(&reg_params[5], "r3", 32, PARAM_IN_OUT);
+ buf_set_u32(reg_params[5].value, 0, 32, 'k' << 24 | 'e' << 16 | 'f' << 8 | 
'l');
+
+ api_status = lpc55xx_api_call(bank, API_FLASH_ERASE, ARRAY_SIZE(reg_params), 
reg_params);
+
+ return api_status == 0 ? ERROR_OK : ERROR_FLASH_OPERATION_FAILED;
+}
+
+static int lpc55xx_erase_check(struct flash_bank *bank)
+{
+ struct reg_param reg_params[5];
+ int retval = ERROR_OK;
+ int api_status;
+
+ for (size_t i = 0; i < bank->num_sectors; i++) {
+ init_reg_param(&reg_params[3], "r1", 32, PARAM_IN_OUT);
+ buf_set_u32(reg_params[3].value, 0, 32, bank->base + bank->sectors[i].offset);
+ init_reg_param(&reg_params[4], "r2", 32, PARAM_IN_OUT);
+ buf_set_u32(reg_params[4].value, 0, 32, bank->sectors[i].size);
+
+ api_status = lpc55xx_api_call(bank, API_FLASH_VERIFY_ERASE, 
ARRAY_SIZE(reg_params), reg_params);
+
+ if (api_status == 0) {
+ bank->sectors[i].is_erased = true;
+ } else if (api_status == 105) {
+ bank->sectors[i].is_erased = false;
+ } else {
+ retval = ERROR_FLASH_OPERATION_FAILED;
+ break;
+ }
+ }
+
+ return retval;
+}
+
+static int lpc55xx_write(struct flash_bank *bank, const uint8_t *buffer, 
uint32_t offset, uint32_t count)
+{
+ struct working_area *download_area;
+ struct target *target = bank->target;
+ struct reg_param reg_params[6];
+ const size_t download_size = 8192;
+ int retval = ERROR_OK;
+ int api_status;
+
+ if (target_alloc_working_area(target, download_size, &download_area) != 
ERROR_OK) {
+ LOG_ERROR("Failed to allocate working area for write buffer");
+ return ERROR_FAIL;
+ }
+
+ while (count != 0) {
+ size_t bytes_to_write = MIN(count, download_size);
+
+ retval = target_write_buffer(target, download_area->address, bytes_to_write, 
buffer + offset);
+ if (retval != ERROR_OK) {
+ retval = ERROR_FLASH_OPERATION_FAILED;
+ goto end;
+ }
+
+ init_reg_param(&reg_params[3], "r1", 32, PARAM_IN_OUT);
+ buf_set_u32(reg_params[3].value, 0, 32, offset);
+ init_reg_param(&reg_params[4], "r2", 32, PARAM_IN_OUT);
+ buf_set_u32(reg_params[4].value, 0, 32, download_area->address);
+ init_reg_param(&reg_params[5], "r3", 32, PARAM_IN_OUT);
+ buf_set_u32(reg_params[5].value, 0, 32, bytes_to_write);
+
+ api_status = lpc55xx_api_call(bank, API_FLASH_PROGRAM, 
ARRAY_SIZE(reg_params), reg_params);
+ if (api_status != 0) {
+ LOG_ERROR("Error writing flash");
+ retval = ERROR_FLASH_OPERATION_FAILED;
+ goto end;
+ }
+
+ count -= bytes_to_write;
+ offset += bytes_to_write;
+ }
+
+end:
+ target_free_working_area(target, download_area);
+
+ return retval;
+}
+
+
+static int lpc55xx_probe(struct flash_bank *bank)
+{
+ struct lpc55xx_flash_bank *lpc55xx_info = bank->driver_priv;
+ uint32_t device_id, sector_size, ver, base;
+ struct target *target = bank->target;
+ struct reg_param reg_params[3];
+ uint32_t last_sector_size;
+ int api_status;
+
+ target_read_u32(target, LPC55XX_DEVICEID_REG, &device_id);
+ LOG_DEBUG("Device ID: 0x%8.8" PRIx32, device_id);
+ target_read_u32(target, LPC55XX_DIEID_REG, &ver);
+ LOG_DEBUG("Chip revision ID and Number (DIEID): 0x%8.8" PRIx32, ver);
+
+ if (lpc55xx_info->flash_api_table == 0) {
+ uint32_t rom_api_table;
+
+ if ((device_id & 0xff0ffff0) == 0x500a11a0) { /* LPC553x */
+ rom_api_table = 0x1302fc00;
+ /* the datasheet has table address but no information about
+ * device ID */
+ /*} else if (device_id == XXXX) */ /* LPC55S6x/LPC55S2x/LPC552x */ /*{
+ rom_api_table = 0x130010f0;*/
+ } else {
+ LOG_ERROR("Unknown LPC55xx variant and ROM API table address not specified");
+ return ERROR_FAIL;
+ }
+
+ target_read_u32(target, rom_api_table + 4, &ver);
+ LOG_DEBUG("ROM API version: 0x%8.8" PRIx32, ver);
+ target_read_u32(target, rom_api_table + 0x10, &lpc55xx_info->flash_api_table);
+ }
+
+ target_read_u32(target, lpc55xx_info->flash_api_table, &ver);
+ LOG_DEBUG("Flash API version: 0x%8.8" PRIx32, ver);
+
+ api_status = lpc55xx_api_call(bank, API_FLASH_INIT, ARRAY_SIZE(reg_params), 
reg_params);
+ if (api_status != 0) {
+ LOG_ERROR("flash_init() failed");
+ return ERROR_FLASH_OPERATION_FAILED;
+ }
+
+ target_read_u32(target, lpc55xx_info->wa->address + 4, &base);
+ if (base != bank->base) {
+ LOG_ERROR("Flash bank address mismatch: API reported 0x%8.8" PRIx32, base);
+ return ERROR_FAIL;
+ }
+
+ target_read_u32(target, lpc55xx_info->wa->address + 8, &bank->size);
+ target_read_u32(target, lpc55xx_info->wa->address + 0x14, &sector_size);
+
+ free(bank->sectors);
+
+ bank->num_sectors = bank->size / sector_size;
+ last_sector_size = bank->size % sector_size;
+ if (last_sector_size != 0)
+ bank->num_sectors++;
+ bank->sectors = alloc_block_array(0, sector_size, bank->num_sectors);
+ if (!bank->sectors)
+ return ERROR_FAIL;
+ if (last_sector_size != 0)
+ bank->sectors[bank->num_sectors - 1].size = last_sector_size;
+
+ target_read_u32(target, lpc55xx_info->wa->address + 0x10, 
&bank->write_start_alignment);
+ bank->write_end_alignment = bank->write_start_alignment;
+
+ lpc55xx_info->probed = true;
+
+ return ERROR_OK;
+}
+
+static int lpc55xx_auto_probe(struct flash_bank *bank)
+{
+ struct lpc55xx_flash_bank *lpc55xx_info = bank->driver_priv;
+ if (lpc55xx_info->probed)
+ return ERROR_OK;
+ return lpc55xx_probe(bank);
+}
+
+const struct flash_driver lpc55xx_flash = {
+ .name = "lpc55xx",
+ .flash_bank_command = lpc55xx_flash_bank_command,
+ .erase = lpc55xx_erase,
+ .write = lpc55xx_write,
+ .read = default_flash_read,
+ .probe = lpc55xx_probe,
+ .auto_probe = lpc55xx_auto_probe,
+ .erase_check = lpc55xx_erase_check,
+ .free_driver_priv = default_flash_free_driver_priv,
+};
diff --git a/tcl/target/lpc55xx.cfg b/tcl/target/lpc55xx.cfg
new file mode 100644
index 0000000000..829f2081aa
--- /dev/null
+++ b/tcl/target/lpc55xx.cfg
@@ -0,0 +1,68 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+source [find target/swj-dp.tcl]
+
+adapter speed 1000
+
+if { [info exists CHIPNAME] } {
+ set _CHIPNAME $CHIPNAME
+} else {
+ set _CHIPNAME lpc55xx
+}
+
+if { [info exists CPUTAPID] } {
+ set _CPUTAPID $CPUTAPID
+} else {
+ # Cortex-M33 SWD DPIDR
+ set _CPUTAPID 0x6ba02477
+}
+
+swj_newdap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id 
$_CPUTAPID
+dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu
+
+set _TARGETNAME $_CHIPNAME.cpu
+target create $_TARGETNAME cortex_m -endian little -dap $_CHIPNAME.dap
+
+# Reserved RAM regions for ROM functions
+# 0x14000000 -- 0x14003fff
+# 0x30001000 -- 0x30007fff
+#
+# Use 16 KiB of SRAM2 (on LPC553x) for working area
+if { [info exists WORKAREASIZE] } {
+ set _WORKAREASIZE $WORKAREASIZE
+} else {
+ set _WORKAREASIZE 0x4000
+}
+$_TARGETNAME configure -work-area-phys 0x20008000 \
+ -work-area-size $_WORKAREASIZE -work-area-backup 0
+
+if { [info exists FLASH_API_ADDRESS] } {
+ set _FLASH_API_ADDRESS $FLASH_API_ADDRESS
+} else {
+ set _FLASH_API_ADDRESS 0
+}
+
+# Using SRST is not recommended as that also resets the debug domain
+if {![using_hla]} {
+ cortex_m reset_config sysresetreq
+}
+
+proc init_reset { mode } {
+ if { $mode ne "run" } {
+ halt
+ wp 0x50000040 4 r
+ resume
+ }
+}
+$_TARGETNAME configure -event reset-end { catch { rwp 0x50000040 } }
+
+# Run this to initiate a debug session with a target that doesn't have
+# valid firmware on flash
+proc lpc55xx_start_debug_session { } {
+ global _CHIPNAME
+ $_CHIPNAME.dap apreg 2 0 0x21
+ $_CHIPNAME.dap apreg 2 4 7
+ $_CHIPNAME.cpu arp_examine
+}
+
+flash bank $_TARGETNAME.flash lpc55xx 0x00000000 0 0 0 0 $_FLASH_API_ADDRESS

--




Reply via email to