由于引导 ROM,在 LPC4088 上上传和调试二进制文件时出现问题

Problems uploading and debugging binaries on LPC4088 because of Boot ROM

我正在尝试上传这个简单的汇编程序:

    .global _start
    .text

reset:                  b _start
undefined:              b undefined
software_interrupt:     b software_interrupt
prefetch_abort:         b prefetch_abort
data_abort:             b data_abort
                        nop
interrupt_request:      b interrupt_request
fast_interrupt_request: b fast_interrupt_request

_start:

    mov r0, #0
    mov r1, #1

increase:

    add r0, r0, r1
    cmp r0, #10
    bne increase

decrease:

    sub r0, r0, r1
    cmp r0, #0
    bne decrease
    b increase 


stop:   b stop

到我的 LPC4088 (我正在使用 Embedded artists LPC4088 QSB) 通过 SEGGER 的 JLink,这样我以后可以使用 GDB 对其进行调试。


首先,我使用 GCC 工具链编译了带有所有调试符号的源代码:

  1. arm-none-eabi-as -g -gdwarf-2 -o program.o program.s
  2. arm-none-eabi-ld -Ttext=0x0 -o program.elf program.o
  3. arm-none-eabi-objcopy -O binary program.elf program.bin

但是将二进制 program.bin 上传到 LPC4088 是不成功的。然后用户@old_timer 在评论中提醒我,LPC4088 的引导 ROM 会在每次重置后执行 校验和测试 ,如 LPC4088 user manual 的第 876 页所述:

所以我很确定我的二进制文件会通过 校验和测试 按照描述的步骤 here。所以我先创建了一个C源文件checksum.c:

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

int main(int argc, char **argv) {
    int fw, count, crc;
    char buf[28];

    fw = open(argv[1], O_RDWR);
    // read fist 28 bytes
    read(fw, &buf, 28);

    // find 2's complement of entries 0 to 6
    for (count=0, crc=0; count < 7; count++) {
            crc += *((int*)(buf+count*4));
    }
    crc = (~crc) + 1;

    // write it at offset 0x0000001C 
    lseek(fw, 0x0000001C, SEEK_SET);
    write(fw, &crc, 4);
    close(fw);

    return 0;
}

使用 gcc -o checksum.bin checksum.c 编译它,然后我将原始的 program.bin 作为参数提供给它 ./checksum.bin program.bin。所以我得到了一个修改过的 program.bin ,它确实在 0x1C 处修改了值!这是原始的比较:

和修改后的版本:

所以0x1C处的值由0xFEFFFFEA修改为0x0400609D。从图像中可以看出,这就是所有修改的内容。


然后我打开了终端应用程序 JLinkExe,它显示了一个提示。在提示我:

  1. 使用 power on
  2. 在我的板上供电
  3. 使用命令 connect
  4. 连接到 LPC4088
  5. 使用命令 h
  6. 停止了 MCPU
  7. 已使用命令 erase
  8. 擦除整个闪存
  9. 已将我修改后的二进制文件上传到 FLASH loadbin program.bin 0x0
  10. 设置程序计数器从开头开始SetPC 0x4
  11. 开始使用 s 进入程序。

当我在第一步开始进入程序时,出现了一些错误,可以在 JLinkExe 提示符中的过程结束时看到:

SEGGER J-Link Commander V6.30a (Compiled Jan 31 2018 18:14:21)
DLL version V6.30a, compiled Jan 31 2018 18:14:14

Connecting to J-Link via USB...O.K.
Firmware: J-Link V9 compiled Jan 29 2018 15:41:50
Hardware version: V9.30
S/N: 269300437
License(s): FlashBP, GDB
OEM: SEGGER-EDU
VTref = 3.293V


Type "connect" to establish a target connection, '?' for help
J-Link>connect
Please specify device / core. <Default>: LPC4088
Type '?' for selection dialog
Device>
Please specify target interface:
  J) JTAG (Default)
  S) SWD
TIF>
Device position in JTAG chain (IRPre,DRPre) <Default>: -1,-1 => Auto-detect
JTAGConf>
Specify target interface speed [kHz]. <Default>: 4000 kHz
Speed>
Device "LPC4088" selected.


Connecting to target via JTAG
TotalIRLen = 4, IRPrint = 0x01
JTAG chain detection found 1 devices:
 #0 Id: 0x4BA00477, IRLen: 04, CoreSight JTAG-DP
Scanning AP map to find all available APs
AP[1]: Stopped AP scan as end of AP map has been reached
AP[0]: AHB-AP (IDR: 0x24770011)
Iterating through AP map to find AHB-AP to use
AP[0]: Core found
AP[0]: AHB-AP ROM base: 0xE00FF000
CPUID register: 0x410FC241. Implementer code: 0x41 (ARM)
Found Cortex-M4 r0p1, Little endian.
FPUnit: 6 code (BP) slots and 2 literal slots
CoreSight components:
ROMTbl[0] @ E00FF000
ROMTbl[0][0]: E000E000, CID: B105E00D, PID: 000BB00C SCS-M7
ROMTbl[0][1]: E0001000, CID: B105E00D, PID: 003BB002 DWT
ROMTbl[0][2]: E0002000, CID: B105E00D, PID: 002BB003 FPB
ROMTbl[0][3]: E0000000, CID: B105E00D, PID: 003BB001 ITM
ROMTbl[0][4]: E0040000, CID: B105900D, PID: 000BB9A1 TPIU
ROMTbl[0][5]: E0041000, CID: B105900D, PID: 000BB925 ETM
Cortex-M4 identified.
J-Link>h
PC = 000001B2, CycleCnt = 825F97DB
R0 = 00000000, R1 = 20098038, R2 = 2009803C, R3 = 000531FB
R4 = 00000000, R5 = 00000000, R6 = 12345678, R7 = 00000000
R8 = 6C2030E3, R9 = 0430DB64, R10= 10000000, R11= 00000000
R12= 899B552C
SP(R13)= 1000FFF0, MSP= 1000FFF0, PSP= 6EBAAC08, R14(LR) = 00000211
XPSR = 21000000: APSR = nzCvq, EPSR = 01000000, IPSR = 000 (NoException)
CFBP = 00000000, CONTROL = 00, FAULTMASK = 00, BASEPRI = 00, PRIMASK = 00

FPS0 = 93310C50, FPS1 = 455D159C, FPS2 = 01BA3FC2, FPS3 = E851BEED
FPS4 = D937E8F4, FPS5 = 82BD7BF6, FPS6 = 8F16D263, FPS7 = B0E8C039
FPS8 = 302C0A38, FPS9 = 8007BC9C, FPS10= 9A1A276F, FPS11= 76C9DCFE
FPS12= B2FFFA20, FPS13= B55786BB, FPS14= 2175F73E, FPS15= 5D35EC5F
FPS16= 98917B32, FPS17= C964EEB6, FPS18= FEDCA529, FPS19= 1703B679
FPS20= 2F378232, FPS21= 973440E3, FPS22= 928C911C, FPS23= 20A1BF55
FPS24= 4AE3AD0C, FPS25= 4F47CC1E, FPS26= C7B418D5, FPS27= 3EAB9244
FPS28= 73C795D0, FPS29= A359C85E, FPS30= 823AEA80, FPS31= EC9CBCD5
FPSCR= 00000000
J-Link>erase
Erasing device (LPC4088)...
J-Link: Flash download: Only internal flash banks will be erased.
To enable erasing of other flash banks like QSPI or CFI, it needs to be enabled via "exec EnableEraseAllFlashBanks"
Comparing flash   [100%] Done.
Erasing flash     [100%] Done.
Verifying flash   [100%] Done.
J-Link: Flash download: Total time needed: 3.357s (Prepare: 0.052s, Compare: 0.000s, Erase: 3.301s, Program: 0.000s, Verify: 0.000s, Restore: 0.002s)
Erasing done.
J-Link>loadbin program.bin 0x0
Downloading file [program.bin]...
Comparing flash   [100%] Done.
Erasing flash     [100%] Done.
Programming flash [100%] Done.
Verifying flash   [100%] Done.
J-Link: Flash download: Bank 0 @ 0x00000000: 1 range affected (4096 bytes)
J-Link: Flash download: Total time needed: 0.076s (Prepare: 0.056s, Compare: 0.001s, Erase: 0.000s, Program: 0.005s, Verify: 0.000s, Restore: 0.012s)
O.K.
J-Link>SetPC 0x4
J-Link>s

**************************
WARNING: T-bit of XPSR is 0 but should be 1. Changed to 1.
**************************

J-Link>s

****** Error: Failed to read current instruction.
J-Link>s

****** Error: Failed to read current instruction.
J-Link>s

****** Error: Failed to read current instruction.
J-Link>

所以这段代码一定来自某个地方,它可能是 LPC4088 的引导 ROM,它在引导时被重新映射到 0x0,如 LPC4088 user manual 第 907 页所述:


您是否知道如何解决这个 Boot ROM 和校验和问题,以便我可以正常调试我的程序?


过了一会儿我发现警告:

**************************
WARNING: T-bit of XPSR is 0 but should be 1. Changed to 1.
**************************

实际上是在说我正在尝试在只有 Thumb 的 Cortex-M4 上执行 ARM 指令!警告中提到的这个 T 位在 ARMv7-M architecture reference manual 的第 100 页上有描述:

这正是用户@old_timer所说的。

您正在尝试在 cortex-m4 上 运行 arm 指令(0xExxxxxxxx 是一个很大的赠品,更不用说异常 table 是很多 0xEAxxxxxx 指令)。 cortex-m 以不同方式启动(vector table 而不是 executable 指令)并且只是拇指(armv7-m 中的 thumb2 扩展也是......只是拇指,不要被那个混淆,什么thumb2 扩展确实很重要,但 early/original thumb 是 portable 所有这些)。因此,无论您是否需要一个额外的校验和,例如基于 ARM7TDMI 的旧 NXP 芯片,以便引导加载程序允许 user/application 代码为 运行,您首先需要一些将 运行皮层-m4.

从这个开始,是的,我知道你有一个 cortex-m4,现在使用 cortex-m0。

so.s

.cpu cortex-m0
.thumb
.thumb_func
.globl _start
_start:
stacktop: .word 0x20001000
.word reset
.word hang
@ ...

.thumb_func
hang: b hang
.thumb_func
reset:
   mov r1,#0
outer:
   mov r0,#0xFF
inner:
   nop
   nop   
   add r1,#1
   sub r0,#1
   bne inner
   nop
   nop
   b outer

建造

arm-none-eabi-as so.s -o so.o
arm-none-eabi-ld -Ttext=0 so.o -o so.elf
arm-none-eabi-objdump -D so.elf > so.list
arm-none-eabi-objcopy so.elf -O binary so.bin

检查 so.list 以确保向量 table 正确。

00000000 <_start>:
   0:   20001000    andcs   r1, r0, r0
   4:   0000000f    andeq   r0, r0, pc
   8:   0000000d    andeq   r0, r0, sp

0000000c <hang>:
   c:   e7fe        b.n c <hang>

0000000e <reset>:
   e:   2100        movs    r1, #0

00000010 <outer>:
  10:   20ff        movs    r0, #255    ; 0xff

00000012 <inner>:
  12:   46c0        nop         ; (mov r8, r8)
  14:   46c0        nop         ; (mov r8, r8)
  16:   3101        adds    r1, #1
  18:   3801        subs    r0, #1
  1a:   d1fa        bne.n   12 <inner>
  1c:   46c0        nop         ; (mov r8, r8)
  1e:   46c0        nop         ; (mov r8, r8)
  20:   e7f6        b.n 10 <outer>

重置入口点为 0x00E,在向量 table 中偏移量 0x4 处正确指示为 0x00F。您可以将其闪存到 0x000,然后重置并查看它是否有效(需要一个调试器来停止它以查看它是否正在单步执行该代码)。

从 sram 到 运行 这里没有任何位置依赖性,因此您可以按原样将 .bin 加载到 0x20000000 并从 0x2000000E 执行(或您的工具链最终为重置入口点创建的任何地址) .

或者您可以删除矢量 table

.cpu cortex-m0
.thumb
.thumb_func
reset:
   mov r1,#0
outer:
   mov r0,#0xFF
inner:
   nop
   nop   
   add r1,#1
   sub r0,#1
   bne inner
   nop
   nop
   b outer

并且link使用-Ttext=0x20000000,然后下载到sram并在0x20000000用调试器开始执行。

你应该看到 r0 计数一些,r1 应该一直计数然后翻转并继续计数所以如果你停止它检查寄存器,恢复,停止等你应该看到 activity.