LPC 1768 Flashing and Debugging

Hi and thanks for your patience.

I’m still trying to debug the Keil MCB1760 wit the Microcontroller LPC1768 properly.
I have got three probes at my disposal, one being the ULINK-ME, one being the Blackmagic Probe and one being the J-Link EDU Mini.

As weird stuff keeps on happening whenever I try to run any firmware other than one that contains the Mbed framework(debugs properly), I’m back at trying the ULINK-ME again.

PlatformIO.ini depending on the probe I use:

[env:lpc1768]
platform = nxplpc
board = lpc1768
;framework = mbed

; ULINK-ME Probe
build_flags = -D MCB1700
extra_scripts = extra_script.py
;
upload_protocol = custom
upload_flags =
    -f
    scripts/interface/cmsis-dap.cfg
    -f
    scripts/board/mcb1700.cfg
debug_tool = custom
debug_server =
    $PLATFORMIO_CORE_DIR/packages/tool-openocd/bin/openocd
    -f
    ../scripts/interface/cmsis-dap.cfg
    -f
    ../scripts/board/mcb1700.cfg


;J-Link Probe
upload_protocol = jlink-jtag
debug_tool = jlink


;Blackmagic Probe
extra_scripts = extra_script.py
upload_protocol = blackmagic
upload_port = /dev/cu.usbmodem79AC68971

debug_tool = custom
debug_port = /dev/cu.usbmodem79AC68971
debug_init_cmds =
  target extended-remote $DEBUG_PORT
  monitor swdp_scan
  attach 1
  set mem inaccessible-by-default off
  $INIT_BREAK
  $LOAD_CMDS

When flashing a basic firmware:
main.cpp


#include <LPC17xx/LPC17xx.h> 

#ifdef __cplusplus
extern "C" {
#endif

void delay_ms(unsigned int ms)
{
unsigned int i,j;
for(i=0;i<ms;i++)
for(j=0;j<6000;j++);
}


/* start the main program */
int main() 
{
    SystemInit();                    //Clock and PLL configuration 
    LPC_PINCON->PINSEL4 = 0x000000;  //Configure the PORT2 Pins as GPIO;
    LPC_GPIO2->FIODIR = 0xffffffff;  //Configure the PORT2 pins as OUTPUT;

    while(1)
    {
        LPC_GPIO2->FIOPIN = 0xffffffff;     // Make all the Port pins as high  
        delay_ms(100);

        LPC_GPIO2->FIOPIN = 0x00;           // Make all the Port pins as low  
        delay_ms(100);
    }
}

#ifdef __cplusplus
}
#endif

I’m getting this terminal output:

> Executing task: platformio run --target upload <

Processing lpc1768 (platform: nxplpc; board: lpc1768)
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Verbose mode can be enabled via `-v, --verbose` option
CONFIGURATION: https://docs.platformio.org/page/boards/nxplpc/lpc1768.html
PLATFORM: NXP LPC 4.4.0 > NXP mbed LPC1768
HARDWARE: LPC1768 96MHz, 64KB RAM, 512KB Flash
DEBUG: Current (custom) On-board (cmsis-dap) External (blackmagic, jlink)
PACKAGES: toolchain-gccarmnoneeabi 1.70201.0 (7.2.1)
LDF: Library Dependency Finder -> http://bit.ly/configure-pio-ldf
LDF Modes: Finder ~ chain, Compatibility ~ soft
Found 1 compatible libraries
Scanning dependencies...
Dependency Graph
|-- <LPC17xx>
Compiling .pio/build/lpc1768/src/main.o
Compiling .pio/build/lpc1768/libcb3/LPC17xx/core_cm3.o
Compiling .pio/build/lpc1768/libcb3/LPC17xx/startup_LPC17xx.o
Compiling .pio/build/lpc1768/libcb3/LPC17xx/system_LPC17xx.o
Archiving .pio/build/lpc1768/libcb3/libLPC17xx.a
Indexing .pio/build/lpc1768/libcb3/libLPC17xx.a
Linking .pio/build/lpc1768/firmware.elf
Building .pio/build/lpc1768/firmware.bin
Checking size .pio/build/lpc1768/firmware.elf
post_bin_file([".pio/build/lpc1768/firmware.bin"], [".pio/build/lpc1768/firmware.elf"])
==== Post building BIN file ====
Firmware path: .pio/build/lpc1768/firmware.bin
Memory Usage -> http://bit.ly/pio-memory-usage
DATA:    [          ]   0.2% (used 124 bytes from 65536 bytes)
PROGRAM: [          ]   0.1% (used 632 bytes from 524288 bytes)
Wrote checksum 0x2b6aa66 into binary.
Configuring upload protocol...
AVAILABLE: blackmagic, cmsis-dap, custom, jlink, mbed
CURRENT: upload_protocol = custom
Uploading .pio/build/lpc1768/firmware.bin
xPack OpenOCD, 64-bit Open On-Chip Debugger 0.10.0+dev (2019-07-17-15:21)
Licensed under GNU GPL v2
For bug reports, read
        http://openocd.org/doc/doxygen/bugs.html
Info : auto-selecting first available session transport "swd". To override use 'transport select <transport>'.
Info : CMSIS-DAP: SWD  Supported
Info : CMSIS-DAP: JTAG Supported
Info : CMSIS-DAP: FW Version = 1.0
Info : CMSIS-DAP: Interface Initialised (SWD)
Info : SWCLK/TCK = 0 SWDIO/TMS = 1 TDI = 1 TDO = 1 nTRST = 0 nRESET = 1
Info : CMSIS-DAP: Interface ready
Info : clock speed 10 kHz
Info : SWD DPIDR 0x2ba01477
Info : lpc17xx.cpu: hardware has 6 breakpoints, 4 watchpoints
Info : Listening on port 3333 for gdb connections
target halted due to debug-request, current mode: Thread 
xPSR: 0x01000000 pc: 0x1fff0080 msp: 0x10001ffc
Info : High speed (adapter_khz 12500) may be limited by adapter firmware.
** Programming Started **
** Programming Finished **
** Verify Started **
** Verified OK **
** Resetting Target **
Info : SWD DPIDR 0x2ba01477
Error: lpc17xx.cpu -- clearing lockup after double fault
target halted due to debug-request, current mode: Handler HardFault
xPSR: 0x60000003 pc: 0x4b07b508 msp: 0xbf00b5d8
Polling target lpc17xx.cpu failed, trying to reexamine
Info : lpc17xx.cpu: hardware has 6 breakpoints, 4 watchpoints
shutdown command invoked
========================================================================================== [SUCCESS] Took 13.99 seconds ==========================================================================================

Terminal will be reused by tasks, press any key to close it.

And this debug terminal log:

Debug console log

Reading symbols from /Users/john/Documents/PlatformIO/Projects/Testing_MCB1768/.pio/build/lpc1768/firmware.elf...
done.
PlatformIO Unified Debugger -> http://bit.ly/pio-debug
PlatformIO: debug_tool = custom
PlatformIO: Initializing remote target...
xPack OpenOCD, 64-bit Open On-Chip Debugger 0.10.0+dev (2019-07-17-15:21)
Licensed under GNU GPL v2
For bug reports, read
	http://openocd.org/doc/doxygen/bugs.html
Info : auto-selecting first available session transport "swd". To override use 'transport select <transport>'.
Info : tcl server disabled
Info : telnet server disabled
Info : CMSIS-DAP: SWD  Supported
Info : CMSIS-DAP: JTAG Supported
Info : CMSIS-DAP: FW Version = 1.0
Info : CMSIS-DAP: Interface Initialised (SWD)
Info : SWCLK/TCK = 0 SWDIO/TMS = 1 TDI = 1 TDO = 1 nTRST = 0 nRESET = 1
Info : CMSIS-DAP: Interface ready
Info : clock speed 10 kHz
Info : SWD DPIDR 0x2ba01477
Info : lpc17xx.cpu: hardware has 6 breakpoints, 4 watchpoints
Info : accepting 'gdb' connection from pipe
0x00000000 in ?? ()
Temporary breakpoint 1 at 0x80ea: file src/main.cpp, line 18.
target halted due to debug-request, current mode: Thread 
xPSR: 0x01000000 pc: 0x1fff0080 msp: 0x10001ffc
target halted due to debug-request, current mode: Thread 
xPSR: 0x01000000 pc: 0x1fff0080 msp: 0x10001ffc
target halted due to debug-request, current mode: Thread 
xPSR: 0x01000000 pc: 0x1fff0080 msp: 0x10001ffc
Warn : keep_alive() was not invoked in the 1000ms timelimit. GDB alive packet not sent! (1992). Workaround: increase "set remotetimeout" in GDB
Info : High speed (adapter_khz 12500) may be limited by adapter firmware.
target halted due to debug-request, current mode: Thread 
xPSR: 0x01000000 pc: 0x1fff0080 msp: 0x10001ffc
Warn : keep_alive() was not invoked in the 1000ms timelimit. GDB alive packet not sent! (1974). Workaround: increase "set remotetimeout" in GDB
Info : High speed (adapter_khz 12500) may be limited by adapter firmware.
Loading section .init, size 0xc lma 0x8000
Loading section .text, size 0x22c lma 0x800c
Loading section .fini, size 0xc lma 0x8238
Loading section .rodata, size 0x4 lma 0x8244
Loading section .ARM.exidx, size 0x8 lma 0x8248
Loading section .eh_frame, size 0x4 lma 0x8250
Loading section .init_array, size 0x4 lma 0x18254
Loading section .fini_array, size 0x4 lma 0x18258
Loading section .data, size 0x60 lma 0x1825c
Info : Flash write discontinued at 0x00008254, next section at 0x00018254
Warn : offset 0x18254 breaks required alignment 0x100
Error: error writing to flash at address 0x00000000 at offset 0x00018254
target halted due to debug-request, current mode: Thread 
xPSR: 0x01000000 pc: 0x1fff0080 msp: 0x10001ffc
Warn : keep_alive() was not invoked in the 1000ms timelimit. GDB alive packet not sent! (1952). Workaround: increase "set remotetimeout" in GDB
.pioinit:16: Error in sourced command file:
Error finishing flash operation

When trying to debug with J-Link:
The upload doesn’t throw any errors, but debugging throws this here:

Reading symbols from /Users/john/Documents/PlatformIO/Projects/Testing_MCB1768/.pio/build/lpc1768/firmware.elf...
SEGGER J-Link GDB Server V6.50a Command Line Version

done.
PlatformIO Unified Debugger -> http://bit.ly/pio-debug
PlatformIO: debug_tool = jlink
PlatformIO: Initializing remote target...
JLinkARM.dll V6.50a (DLL compiled Aug 26 2019 10:26:25)

Command line: -singlerun -if SWD -select USB -device LPC1768 -port 2331
-----GDB Server start settings-----
GDBInit file:                  none
GDB Server Listening port:     2331
SWO raw output listening port: 2332
Terminal I/O port:             2333
Accept remote connection:      yes
Generate logfile:              off
Verify download:               off
Init regs on start:            off
Silent mode:                   off
Single run mode:               on
Target connection timeout:     0 ms
------J-Link related settings------
J-Link Host interface:         USB
J-Link script:                 none
J-Link settings file:          none
------Target related settings------
Target device:                 LPC1768
Target interface:              SWD
Target interface speed:        4000kHz
Target endian:                 little

Connecting to J-Link...
J-Link is connected.
Firmware: J-Link EDU Mini V1 compiled Aug 27 2019 09:26:01
Hardware: V1.00
S/N: 801015042
Feature(s): FlashBP, GDB
Checking target voltage...
Target voltage: 3.27 V
Listening on TCP/IP port 2331
Connecting to target...WARNING: T-bit of XPSR is 0 but should be 1. Changed to 1.
Connected to target
Waiting for GDB connection...Connected to 127.0.0.1
Reading all registers
0x4b07b508 in ?? ()
Temporary breakpoint 1 at 0x80ea: file src/main.cpp, line 18.
Received monitor command: halt
Halting target CPU...
...Target halted (PC = 0x4B07B508)
Received monitor command: reset
Resetting target
Resetting target
Loading section .init, size 0xc lma 0x8000
Loading section .text, size 0x22c lma 0x800c
Loading section .fini, size 0xc lma 0x8238
Loading section .rodata, size 0x4 lma 0x8244
Loading section .ARM.exidx, size 0x8 lma 0x8248
Loading section .eh_frame, size 0x4 lma 0x8250
Loading section .init_array, size 0x4 lma 0x18254
Loading section .fini_array, size 0x4 lma 0x18258
Loading section .data, size 0x60 lma 0x1825c
Start address 0x8074, load size 700
Writing register (PC = 0x    8074)
Transfer rate: 341 KB/sec, 77 bytes/write.
Received monitor command: halt
Halting target CPU...
...Target halted (PC = 0x00008074)
Received monitor command: reset
Resetting target
Resetting target
PlatformIO: Initialization completed
PlatformIO: Resume the execution to `debug_init_break = tbreak main`
PlatformIO: More configuration options -> http://bit.ly/pio-debug
Starting target CPU...
WARNING: T-bit of XPSR is 0 but should be 1. Changed to 1.
...Target halted (DBGRQ, PC = 0x4B07B508)
Reading all registers

Program
 received signal SIGTRAP, Trace/breakpoint trap.
0x4b07b508 in ?? ()
pio_reset_target
Received monitor command: reset
Resetting target
Resetting target
GDB closed TCP/IP connection

And with the blackmagic probe:
The flashing also seems to work, but the debugging part fails with a segmentation fault.

Reading symbols from /Users/john/Documents/PlatformIO/Projects/Testing_MCB1768/.pio/build/lpc1768/firmware.elf...
done.
PlatformIO Unified Debugger -> http://bit.ly/pio-debug
PlatformIO: debug_tool = custom
PlatformIO: Initializing remote target...
Target voltage: 3.3V
Available Targets:
No. Att Driver
 1      LPC17xx M3/M4
0x10000036 in ?? ()
Temporary breakpoint 1 at 0x80ea: file src/main.cpp, line 18.
Loading section .init, size 0xc lma 0x8000
Loading section .text, size 0x22c lma 0x800c
Loading section .fini, size 0xc lma 0x8238
Loading section .rodata, size 0x4 lma 0x8244
Loading section .ARM.exidx, size 0x8 lma 0x8248
Loading section .eh_frame, size 0x4 lma 0x8250
Loading section .init_array, size 0x4 lma 0x18254
Loading section .fini_array, size 0x4 lma 0x18258
Loading section .data, size 0x60 lma 0x1825c
Start address 0x8074, load size 700
Transfer rate: 770 bytes/sec, 77 bytes/write.
PlatformIO: Initialization completed
PlatformIO: Resume the execution to `debug_init_break = tbreak main`
PlatformIO: More configuration options -> http://bit.ly/pio-debug
Note: automatically using hardware breakpoints for read-only addresses.

Program
 received signal SIGSEGV, Segmentation fault.
0xfffffffe in ?? ()
1 Like

@valeros You might be able to help here?

1 Like

If I’m not mistaken, mbed framework patches the final binary in order to pass execution to the user code.

  • Some of the tools can succesfully upload your firmware, does it work after uploading? (According to your platformio.ini, you aren’t using any framework. Are you sure the firmware is correct?)
  • I see you configure the entire PORT2 as output. Are you sure there are no debug IO pins on this port?
  • Is there anything special in extra_script.py?

Thanks!

I need/want to work without the mbed framework.

the extra script contains a checksum patch, that maxgerhardt helped me with in another topic.

It does not matter what kind of port or whatever I run in my main function, as even a stupid while loop where some integers are being incremented is not debbugable at all, meaning it causes the same errors.

I can upload, but not debug the firmware at all. Uploading the code in the first post does not seem to blink any LEDs, so I guess it doesn’t work.

Is there a way to manually patch the binaries like mbed does. I explicitly need to work without the framework, only with the oem header files.
Thanks for your help.

Edit: found this here, but don’t know how to properly add it to platformIO: mbed-os/LPC.py at master · ARMmbed/mbed-os · GitHub

So probably your firmware is broken for some reason and the mcu simply crashes and enter HardFault handler. Are you sure flags, startup/linker files are correct for this target?

Edit: found this here, but don’t know how to properly add it to platformIO: mbed-os/tools/targets/LPC.py at master · ARMmbed/mbed-os · GitHub

I assume that’s the patch you use in your extra_script.py?

This is the current revision of the code that I’m using.
The patch script looks kind of different compared to the one I found on the Mbed framework.

Edit: Seems to be the same patch.

I don’t know about the linker/compiler flags, as I’m new to microcontroller programming.

Edit 2:
Using that patch script with the black magic probe throws an error:

post_bin_file([".pio/build/lpc1768/firmware.bin"], [".pio/build/lpc1768/firmware.elf"])
==== Post building BIN file ====
Firmware path: .pio/build/lpc1768/firmware.bin
Wrote checksum 0x2b6aa66 into binary.
Configuring upload protocol...
AVAILABLE: blackmagic, cmsis-dap, jlink, mbed
CURRENT: upload_protocol = blackmagic
Looking for BlackMagic port...
Use manually specified: /dev/cu.usbmodem79AC68971
Uploading .pio/build/lpc1768/firmware.bin
xPack OpenOCD, 64-bit Open On-Chip Debugger 0.10.0+dev (2019-07-17-15:21)
Licensed under GNU GPL v2
For bug reports, read
        http://openocd.org/doc/doxygen/bugs.html
openocd: invalid option -- n
*** [upload] Error 1

I couldn’t find any linker script in your repository and I’m not sure that the linker script shipped with ld is suitable for your project. IMO, first of all make sure your firmware is correct and you can successfully upload binary image and your board blinks. Only then you can proceed to debugging.

1 Like

I was kind of having the thought that platformIO does the building and linking part.
Guess I was mistaken.

Where does the linker script usually go into? libs, headers or src? or a custom directory?
I guess platformIO doesn’t automatically use the correct script.

How do I properly add the linker script into the platformio.ini?

PlatformIO does the building and linking part but you need to instruct linker where to place your code when linking. Usually, linker scripts are shipped with frameworks and since you don’t use any, you need to add custom one (for example in the root folder of your project) and then specify the path to it in build_flags field:

build_flags = -Wl,-T"ld_script.ld"
1 Like

I updated the repository and added a linker script found within the Mbed framework.

I’m using the ulink-me probe and I get this kind of error message:

Dependency Graph
|-- <LPC17xx>
Compiling .pio/build/lpc1768/src/main.o
Compiling .pio/build/lpc1768/libcb3/LPC17xx/core_cm3.o
Compiling .pio/build/lpc1768/libcb3/LPC17xx/startup_LPC17xx.o
Compiling .pio/build/lpc1768/libcb3/LPC17xx/system_LPC17xx.o
Archiving .pio/build/lpc1768/libcb3/libLPC17xx.a
Indexing .pio/build/lpc1768/libcb3/libLPC17xx.a
Linking .pio/build/lpc1768/firmware.elf
/Users/john/.platformio/packages/toolchain-gccarmnoneeabi/bin/../lib/gcc/arm-none-eabi/7.2.1/../../../../arm-none-eabi/bin/ld: warning: cannot find entry symbol Reset_Handler; defaulting to 0000000000000000
Building .pio/build/lpc1768/firmware.bin
Checking size .pio/build/lpc1768/firmware.elf
post_bin_file([".pio/build/lpc1768/firmware.bin"], [".pio/build/lpc1768/firmware.elf"])
==== Post building BIN file ====
Firmware path: .pio/build/lpc1768/firmware.bin
Wrote checksum 0x65f24ed2 into binary.
Memory Usage -> http://bit.ly/pio-memory-usage
DATA:    [          ]   0.1% (used 36 bytes from 65536 bytes)
PROGRAM: [          ]   0.0% (used 100 bytes from 524288 bytes)
Configuring upload protocol...
AVAILABLE: blackmagic, cmsis-dap, custom, jlink, mbed
CURRENT: upload_protocol = custom
Uploading .pio/build/lpc1768/firmware.bin
xPack OpenOCD, 64-bit Open On-Chip Debugger 0.10.0+dev (2019-07-17-15:21)
Licensed under GNU GPL v2
For bug reports, read
        http://openocd.org/doc/doxygen/bugs.html
Info : auto-selecting first available session transport "swd". To override use 'transport select <transport>'.
Info : CMSIS-DAP: SWD  Supported
Info : CMSIS-DAP: JTAG Supported
Info : CMSIS-DAP: FW Version = 1.0
Info : CMSIS-DAP: Interface Initialised (SWD)
Info : SWCLK/TCK = 0 SWDIO/TMS = 1 TDI = 1 TDO = 1 nTRST = 0 nRESET = 1
Info : CMSIS-DAP: Interface ready
Info : clock speed 10 kHz
Info : SWD DPIDR 0x2ba01477
Info : lpc17xx.cpu: hardware has 6 breakpoints, 4 watchpoints
Info : Listening on port 3333 for gdb connections
target halted due to debug-request, current mode: Thread 
xPSR: 0x01000000 pc: 0x1fff0080 msp: 0x10001ffc
Info : High speed (adapter_khz 12500) may be limited by adapter firmware.
** Programming Started **
** Programming Finished **
** Verify Started **
** Verified OK **
** Resetting Target **
Info : SWD DPIDR 0x2ba01477
Error: lpc17xx.cpu -- clearing lockup after double fault
target halted due to debug-request, current mode: Handler HardFault
xPSR: 0x60000003 pc: 0xf3af4804 msp: 0x4c05b4f0
Polling target lpc17xx.cpu failed, trying to reexamine
Info : lpc17xx.cpu: hardware has 6 breakpoints, 4 watchpoints
shutdown command invoked

This is the current code revision: GitHub - jxsl13/lpc1768_blinky_example at 54bc59319361fa7e947f551ca01e8edef755a409

/Users/john/.platformio/packages/toolchain-gccarmnoneeabi/bin/…/lib/gcc/arm-none-eabi/7.2.1/…/…/…/…/arm-none-eabi/bin/ld: warning: cannot find entry symbol Reset_Handler; defaulting to 0000000000000000

This warning in your log doesn’t seem OK to me. Probably there is some kind of incompatibility between your startup file and linker script. Are they both part of the same package? Where did you get them?

1 Like

Wow, I have now literally 4 LEDs glowing :smiley: (took me only 3 weeks, thanks)

I changed the startup file, that was seemingly from some third party and not the one from ARM to this one, which I found in the Mbed framework.

startup_LPC17xx.S
/* File: startup_ARMCM3.s
 * Purpose: startup file for Cortex-M3/M4 devices. Should use with 
 *   GNU Tools for ARM Embedded Processors
 * Version: V1.1
 * Date: 17 June 2011
 * 
 * Copyright (C) 2011 ARM Limited. All rights reserved.
 * ARM Limited (ARM) is supplying this software for use with Cortex-M3/M4 
 * processor based microcontrollers.  This file can be freely distributed 
 * within development tools that are supporting such ARM based processors. 
 *
 * THIS SOFTWARE IS PROVIDED "AS IS".  NO WARRANTIES, WHETHER EXPRESS, IMPLIED
 * OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE.
 * ARM SHALL NOT, IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR
 * CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER.
 */
    .syntax unified
    .arch armv7-m

/* Memory Model
   The HEAP starts at the end of the DATA section and grows upward.
   
   The STACK starts at the end of the RAM and grows downward.
   
   The HEAP and stack STACK are only checked at compile time:
   (DATA_SIZE + HEAP_SIZE + STACK_SIZE) < RAM_SIZE
   
   This is just a check for the bare minimum for the Heap+Stack area before
   aborting compilation, it is not the run time limit:
   Heap_Size + Stack_Size = 0x80 + 0x80 = 0x100
 */
    .section .stack
    .align 3
#ifdef __STACK_SIZE
    .equ    Stack_Size, __STACK_SIZE
#else
    .equ    Stack_Size, 0xc00
#endif
    .globl    __StackTop
    .globl    __StackLimit
__StackLimit:
    .space    Stack_Size
    .size __StackLimit, . - __StackLimit
__StackTop:
    .size __StackTop, . - __StackTop

    .section .heap
    .align 3
#ifdef __HEAP_SIZE
    .equ    Heap_Size, __HEAP_SIZE
#else
    .equ    Heap_Size, 0x800
#endif
    .globl    __HeapBase
    .globl    __HeapLimit
__HeapBase:
    .space    Heap_Size
    .size __HeapBase, . - __HeapBase
__HeapLimit:
    .size __HeapLimit, . - __HeapLimit
    
    .section .isr_vector
    .align 2
    .globl __isr_vector
__isr_vector:
    .long    __StackTop            /* Top of Stack */
    .long    Reset_Handler         /* Reset Handler */
    .long    NMI_Handler           /* NMI Handler */
    .long    HardFault_Handler     /* Hard Fault Handler */
    .long    MemManage_Handler     /* MPU Fault Handler */
    .long    BusFault_Handler      /* Bus Fault Handler */
    .long    UsageFault_Handler    /* Usage Fault Handler */
    .long    0                     /* Reserved */
    .long    0                     /* Reserved */
    .long    0                     /* Reserved */
    .long    0                     /* Reserved */
    .long    SVC_Handler           /* SVCall Handler */
    .long    DebugMon_Handler      /* Debug Monitor Handler */
    .long    0                     /* Reserved */
    .long    PendSV_Handler        /* PendSV Handler */
    .long    SysTick_Handler       /* SysTick Handler */

    /* External interrupts */
    .long   WDT_IRQHandler              /* 16: Watchdog Timer               */
    .long   TIMER0_IRQHandler           /* 17: Timer0                       */
    .long   TIMER1_IRQHandler           /* 18: Timer1                       */
    .long   TIMER2_IRQHandler           /* 19: Timer2                       */
    .long   TIMER3_IRQHandler           /* 20: Timer3                       */
    .long   UART0_IRQHandler            /* 21: UART0                        */
    .long   UART1_IRQHandler            /* 22: UART1                        */
    .long   UART2_IRQHandler            /* 23: UART2                        */
    .long   UART3_IRQHandler            /* 24: UART3                        */
    .long   PWM1_IRQHandler             /* 25: PWM1                         */
    .long   I2C0_IRQHandler             /* 26: I2C0                         */
    .long   I2C1_IRQHandler             /* 27: I2C1                         */
    .long   I2C2_IRQHandler             /* 28: I2C2                         */
    .long   SPI_IRQHandler              /* 29: SPI                          */
    .long   SSP0_IRQHandler             /* 30: SSP0                         */
    .long   SSP1_IRQHandler             /* 31: SSP1                         */
    .long   PLL0_IRQHandler             /* 32: PLL0 Lock (Main PLL)         */
    .long   RTC_IRQHandler              /* 33: Real Time Clock              */
    .long   EINT0_IRQHandler            /* 34: External Interrupt 0         */
    .long   EINT1_IRQHandler            /* 35: External Interrupt 1         */
    .long   EINT2_IRQHandler            /* 36: External Interrupt 2         */
    .long   EINT3_IRQHandler            /* 37: External Interrupt 3         */
    .long   ADC_IRQHandler              /* 38: A/D Converter                */
    .long   BOD_IRQHandler              /* 39: Brown-Out Detect             */
    .long   USB_IRQHandler              /* 40: USB                          */
    .long   CAN_IRQHandler              /* 41: CAN                          */
    .long   DMA_IRQHandler              /* 42: General Purpose DMA          */
    .long   I2S_IRQHandler              /* 43: I2S                          */
    .long   ENET_IRQHandler             /* 44: Ethernet                     */
    .long   RIT_IRQHandler              /* 45: Repetitive Interrupt Timer   */
    .long   MCPWM_IRQHandler            /* 46: Motor Control PWM            */
    .long   QEI_IRQHandler              /* 47: Quadrature Encoder Interface */
    .long   PLL1_IRQHandler             /* 48: PLL1 Lock (USB PLL)          */
    .long   USBActivity_IRQHandler      /* 49: USB Activity                 */
    .long   CANActivity_IRQHandler      /* 50: CAN Activity                 */

    .size    __isr_vector, . - __isr_vector

    .text
    .thumb
    .thumb_func
    .align 2
    .globl    Reset_Handler
    .type    Reset_Handler, %function
Reset_Handler:
/*     Loop to copy data from read only memory to RAM. The ranges
 *      of copy from/to are specified by following symbols evaluated in 
 *      linker script.
 *      _etext: End of code section, i.e., begin of data sections to copy from.
 *      __data_start__/__data_end__: RAM address range that data should be
 *      copied to. Both must be aligned to 4 bytes boundary.  */

    ldr    r1, =__etext
    ldr    r2, =__data_start__
    ldr    r3, =__data_end__

.Lflash_to_ram_loop:
    cmp     r2, r3
    ittt    lt
    ldrlt   r0, [r1], #4
    strlt   r0, [r2], #4
    blt    .Lflash_to_ram_loop

    ldr    r0, =SystemInit
    blx    r0
    ldr    r0, =_start
    bx    r0
    .pool
    .size Reset_Handler, . - Reset_Handler
    
    .text
/*    Macro to define default handlers. Default handler
 *    will be weak symbol and just dead loops. They can be
 *    overwritten by other handlers */
    .macro    def_default_handler    handler_name
    .align 1
    .thumb_func
    .weak    \handler_name
    .type    \handler_name, %function
\handler_name :
    b    .
    .size    \handler_name, . - \handler_name
    .endm

    def_default_handler    NMI_Handler
    def_default_handler    HardFault_Handler
    def_default_handler    MemManage_Handler
    def_default_handler    BusFault_Handler
    def_default_handler    UsageFault_Handler
    def_default_handler    SVC_Handler
    def_default_handler    DebugMon_Handler
    def_default_handler    PendSV_Handler
    def_default_handler    SysTick_Handler
    def_default_handler    Default_Handler

    .macro    def_irq_default_handler    handler_name
    .weak     \handler_name
    .set      \handler_name, Default_Handler
    .endm
 
    def_irq_default_handler     WDT_IRQHandler
    def_irq_default_handler     TIMER0_IRQHandler
    def_irq_default_handler     TIMER1_IRQHandler
    def_irq_default_handler     TIMER2_IRQHandler
    def_irq_default_handler     TIMER3_IRQHandler
    def_irq_default_handler     UART0_IRQHandler
    def_irq_default_handler     UART1_IRQHandler
    def_irq_default_handler     UART2_IRQHandler
    def_irq_default_handler     UART3_IRQHandler
    def_irq_default_handler     PWM1_IRQHandler
    def_irq_default_handler     I2C0_IRQHandler
    def_irq_default_handler     I2C1_IRQHandler
    def_irq_default_handler     I2C2_IRQHandler
    def_irq_default_handler     SPI_IRQHandler
    def_irq_default_handler     SSP0_IRQHandler
    def_irq_default_handler     SSP1_IRQHandler
    def_irq_default_handler     PLL0_IRQHandler
    def_irq_default_handler     RTC_IRQHandler
    def_irq_default_handler     EINT0_IRQHandler
    def_irq_default_handler     EINT1_IRQHandler
    def_irq_default_handler     EINT2_IRQHandler
    def_irq_default_handler     EINT3_IRQHandler
    def_irq_default_handler     ADC_IRQHandler
    def_irq_default_handler     BOD_IRQHandler
    def_irq_default_handler     USB_IRQHandler
    def_irq_default_handler     CAN_IRQHandler
    def_irq_default_handler     DMA_IRQHandler
    def_irq_default_handler     I2S_IRQHandler
    def_irq_default_handler     ENET_IRQHandler
    def_irq_default_handler     RIT_IRQHandler
    def_irq_default_handler     MCPWM_IRQHandler
    def_irq_default_handler     QEI_IRQHandler
    def_irq_default_handler     PLL1_IRQHandler
    def_irq_default_handler     USBActivity_IRQHandler
    def_irq_default_handler     CANActivity_IRQHandler
    def_irq_default_handler     DEF_IRQHandler

    .end

How do I have to change the extra_script.py, so that it also works with either the Blackmagic probe or the J-Link Edu Mini?

extra_script.py
Import("env", "projenv")

from struct import unpack, pack


# from https://github.com/basilfx/lpc_checksum/blob/master/lpc_checksum.py by Bas Stottelaar
# removed intelhex dependency like https://github.com/ARMmbed/mbed-os/blob/master/tools/targets/LPC.py
BLOCK_START = 0
BLOCK_COUNT = 7
BLOCK_SIZE = 4
BLOCK_TOTAL = (BLOCK_COUNT * BLOCK_SIZE)

def patch(filename):
    """
    Calculate the checksum of a given binary image. The checksum is written
    back to the file and is returned. When read_only is set to True, the file
    will not be changed.
    filename  -- firmware file to checksum
    format    -- input file format (bin or hex, default bin)
    read_only -- whether to write checksum back to the file (default False)
    """

    with open(filename, 'r+b') as bin:
        # Read entries 0 through 6 (Little Endian 32bits words)
        vector = [unpack('<I', bin.read(BLOCK_SIZE))[BLOCK_START] for _ in range(BLOCK_COUNT)]

        # location 7 (offset 0x1C in the vector table) should contain the 2's
        # complement of the check-sum of table entries 0 through 6
        bin.seek(0x1C)
        result = (~sum(vector) + 1) & 0xFFFFFFFF
        bin.write(pack('<I', result))
        return result

def is_patched(bin_path):
    with open(bin_path, 'rb') as bin:
        # The checksum of the first 8 table entries should be 0
        return (sum([unpack('<I', bin.read(BLOCK_SIZE))[BLOCK_START] for _ in range(BLOCK_COUNT +1)]) & 0xFFFFFFFF) == 0

def post_bin_file(source, target, env):
    print("==== Post building BIN file ====")
    target_firmware_bin = str(target[0])
    #print(source, target, env)
    print("Firmware path: %s" % target_firmware_bin)
    checksum = patch(target_firmware_bin)
    print("Wrote checksum 0x%x into binary." % checksum)
    assert is_patched(target_firmware_bin), "The file is not patched correctly!"
    

# fix checksum
env.AddPostAction("$BUILD_DIR/${PROGNAME}.bin", post_bin_file)
# fix openocd target 
platform = env.PioPlatform()
env.Prepend(
    UPLOADERFLAGS=["-s", platform.get_package_dir("tool-openocd") or ""]
)
env.Append(
    UPLOADERFLAGS=["-c", "program {$SOURCE} verify reset; shutdown"]
)
env.Replace(
    UPLOADER="openocd",
    UPLOADCMD="$UPLOADER $UPLOADERFLAGS"
)
``
1 Like

How do I have to change the extra_script.py, so that it also works with either the Blackmagic probe or the J-Link Edu Mini?

Debug still doesn’t work?

Debugging with the ULink-Me works perfectly!
I just wanted to to get those running as well, as I paid tons of money for them to be now lying around :cactus:

I could not find any custom usage examples(platformio.ini) and the script seems to cause some errors in combination with upload_protocol = blackmagic or upload_protocol = j-link.

Simply removing the last few lines seems to have done the job perfectly.

extra_script.py for LPC1768
Import("env", "projenv")

from struct import unpack, pack


# from https://github.com/basilfx/lpc_checksum/blob/master/lpc_checksum.py by Bas Stottelaar
# removed intelhex dependency like https://github.com/ARMmbed/mbed-os/blob/master/tools/targets/LPC.py
BLOCK_START = 0
BLOCK_COUNT = 7
BLOCK_SIZE = 4
BLOCK_TOTAL = (BLOCK_COUNT * BLOCK_SIZE)

def patch(filename):
    """
    Calculate the checksum of a given binary image. The checksum is written
    back to the file and is returned. When read_only is set to True, the file
    will not be changed.
    filename  -- firmware file to checksum
    format    -- input file format (bin or hex, default bin)
    read_only -- whether to write checksum back to the file (default False)
    """

    with open(filename, 'r+b') as bin:
        # Read entries 0 through 6 (Little Endian 32bits words)
        vector = [unpack('<I', bin.read(BLOCK_SIZE))[BLOCK_START] for _ in range(BLOCK_COUNT)]

        # location 7 (offset 0x1C in the vector table) should contain the 2's
        # complement of the check-sum of table entries 0 through 6
        bin.seek(0x1C)
        result = (~sum(vector) + 1) & 0xFFFFFFFF
        bin.write(pack('<I', result))
        return result

def is_patched(bin_path):
    with open(bin_path, 'rb') as bin:
        # The checksum of the first 8 table entries should be 0
        return (sum([unpack('<I', bin.read(BLOCK_SIZE))[BLOCK_START] for _ in range(BLOCK_COUNT +1)]) & 0xFFFFFFFF) == 0

def post_bin_file(source, target, env):
    print("==== Post building BIN file ====")
    target_firmware_bin = str(target[0])
    #print(source, target, env)
    print("Firmware path: %s" % target_firmware_bin)
    checksum = patch(target_firmware_bin)
    print("Wrote checksum 0x%x into binary." % checksum)
    assert is_patched(target_firmware_bin), "The file is not patched correctly!"
    

# fix checksum
env.AddPostAction("$BUILD_DIR/${PROGNAME}.bin", post_bin_file)

Here is the finished raw blinky without any framework. Thanks a lot!

2 Likes