> 文章列表 > ARM Coresight 及 DS-5 介绍 5 - ARM Cortex-M DS-5 加载 ELF 文件运行

ARM Coresight 及 DS-5 介绍 5 - ARM Cortex-M DS-5 加载 ELF 文件运行

ARM Coresight 及 DS-5 介绍 5 - ARM Cortex-M DS-5 加载 ELF 文件运行

文章目录

      • 1.1.1 DS-5 工程创建
      • 1.1.2 DS-5 加载 ELF 脚本创建
      • 1.1.3 DS-5 脚本读写 Memory
      • 1.1.4 DS-5 扫描脚本

1.1.1 DS-5 工程创建

在使用ARM DS-5 连接 board(或者PFGA)之前首先需要能够扫描到相应的硬件信息,比如对应的cpu的相关信息:coresight 相关组件信息,Cache信息等。

创建好工程项目后按照下图黄线的指示进行扫描操作(通常是完成扫描后才会去执行 “build platform”):
在这里插入图片描述

如果更换平台之后,最好先进行 clean platfom 操作,然后再重新 build platform 操作。

在扫描完成后在DS-5的console中会打印相关的信息,扫描完成后的操作是进行连接操作(见图 1-1)。

1.1.2 DS-5 加载 ELF 脚本创建

通常我们会使用uart或者SPI来烧写镜像到flash,然后再从flash启动,这个过程在实际的debug场景中比较耗时,尤其是当串行时钟比较低的时候。所以我们可以直接使用DS-5通过JTAG接口来烧写镜像到对应的 memory 中,然后再配置好 PC 指针,直接跳转过去既可以启动对应的固件。
在这里插入图片描述

图 1-1

上图 1-1 中对应的脚本代码如下:

# Filename: load_rtos_schan.pyimport sys
import os
import time
from arm_ds.debugger_v1 import Debugger
from arm_ds.debugger_v1 import DebugExceptiondebugger = Debugger()
ec = debugger.getCurrentExecutionContext()
#value = ec.getRegisterService().getValue('PC')
#print("The PC is %s" %value)# 下面是对对板子做reset 操作
os.system("D:\\\\demo\\\\USBRelay\\\\CommandApp_USBRelay.exe QAAMZ open 1")
os.system   ("D:\\\\demo\\\\USBRelay\\\\CommandApp_USBRelay.exe QAAMZ close 1")
time.sleep(1)
print ec.executeDSCommand('stop')print ec.executeDSCommand("load X:\\\\demo_soc\\\\rtos\\\\rt-thread\\\\rt-thread\\\\bsp\\\\\\\\demo_soc\\\\demo_soc_fpga\\\\rtthread.elf")
print ec.executeDSCommand('run')

创建 rtos 加载脚本时需要注意以下几点:
1)需要先固件启动汇编部分的 data 段的 copy 部分 注释掉,因为 DS-5 去加载 elf 文件时会自动根据 elf 符号表data 段加载到对应的地址,例如我们当前是将 data 段放到 DTCM中的,再加载 elf 时 DS-5 会将 data 段数据 load 到对应的 DTCM 地址,所以再编译的时候就需要将启动汇编阶段的 data 段的 copy操作去掉。

2)为了保证硬件内容的 “干净”, 在执行 DS-5 脚本的时候会先进行SoC reset 操作,reset之后系统会自动从bootrom重启,DS-5接入,然后执行 stop 命令,再 load elf(会自动解析 entry point) ,然后再执行 run 命令即可。

bootrom中的代码主要时做循环检测外部接入信号

1.1.3 DS-5 脚本读写 Memory

以写读 0x48000000 地址为例,如下代码:

# Filename: load_rtos_schan.pyimport sys
import os
import time
from arm_ds.debugger_v1 import Debugger
from arm_ds.debugger_v1 import DebugExceptiondebugger = Debugger()
ec = debugger.getCurrentExecutionContext()
#value = ec.getRegisterService().getValue('PC')
#print("The PC is %s" %value)os.system("D:\\\\demo\\\\USBRelay\\\\CommandApp_USBRelay.exe QAAMZ open 1")
os.system   ("D:\\\\demo\\\\USBRelay\\\\CommandApp_USBRelay.exe QAAMZ close 1")
time.sleep(1)
print ec.executeDSCommand('stop')
#ec.getExecutionService().stop()print ec.executeDSCommand("load X:\\\\demo_soc\\\\rtos\\\\rt-thread\\\\rt-thread\\\\bsp\\\\demo\\\\demo_soc\\\\demo_soc_fpga\\\\rtthread.elf")
print ec.executeDSCommand('run')
#ec.getExecutionService().resetTarget()print "######## read and write memory test #######"
#base_adr = 0x56020000
base_adr = 0x48000000for i in range(0, 5):print('i=%d, addr=0x%x, default value:0x%x'  %(i, base_adr + i*4, ec.getMemoryService().readMemory32(base_adr + i*4, {})))if base_adr == 0x56020000: #ipcm source registervalue = 0x1else:value = i * 4ec.getMemoryService().writeMemory32(base_adr + i*4, value, {'width': 32, 'verify': 0})print('i=%d, addr=0x%x, write value:0x%x'  %(i, base_adr + i*4, ec.getMemoryService().readMemory32(base_adr + i*4, {})))#print ec.getMemoryService().readMemory32(base_adr + i*4, {})#ec.getExecutionService().resume()

对于 write only 外设寄存器地址需要加上 flag “verify=0” ,命令行的话可以使用 “memory set <verify=0>:0x46020004 32 1”

TIPS: "alt+/ " 调出 commands 栏 help命令说明
在这里插入图片描述

1.1.4 DS-5 扫描脚本

通常芯片回来后软件同学需要做的第一件事就是完成寄存器扫描,保证系统及各个IP的寄存器可以正常写读,通常会按照各个Subsystem进行扫描,一般情况下每个 IP 都少扫描1-2个寄存器,按照先写再读的方式进行扫描。
扫描脚本首先需要保证以下几点:

  • 各个模块供电正常;
  • 各个模块 clk 正常;
  • 在扫描过程中如果出现有的寄存器有问题可以先跳过。

下面给出了一个简单的DEMO, 该demo 使用的是Python 脚本完成的。

# Filename: DS5_Reg_Scan.pyimport sys
import os
import time
from arm_ds.debugger_v1 import Debugger
from arm_ds.debugger_v1 import DebugExceptiondebugger = Debugger()
ec = debugger.getCurrentExecutionContext()
#value = ec.getRegisterService().getValue('PC')
#print("The PC is %s" %value)
# TO DO: reset SoC     
time.sleep(1) # wait bootrom start
ec.executeDSCommand('stop')def read32(addr):return ec.getMemoryService().readMemory32(addr)def write32(addr, val):return ec.getMemoryService().writeMemory32(addr, val, {'width': 32, 'verify': 0})demo_aon_subsystem = [
#       reg_adr         write_val       ip name0x66004000,     0x55,           "hrtimer0",0x66004014,     0x55,           "hrtimer1",0x66004028,     0x55,           "hrtimer2",]
peri_subsys = [
#       reg_adr          write_val      ip name0x6c002004,      0xdf,          "uart0",0x60011010,      0x1,           "uar1",0x60009004,      0x11,          "spi1",0x60008000,      0x55,          "spi2",0x60008014,      0x55,          "spi3",0x60008028,      0x55,          "spi4",]def demo_subsys_scan(subsys, subsys_name, mode):ret = 0xdeadbeeflist_len = len(subsys) / 3print("Total Registers:%d in %s" %(list_len, subsys_name))for i in range(0, int(list_len)):addr = subsys[i*3]val = subsys[i*3 + 1]name = subsys[i*3 + 2]try:write32(addr, val)if mode == 0: # write-only registers no check return valueret = read32(addr)if ret != val:print("DS-5 Scan %s reg:0x%x failed!!!, read:0x%x" %(name, addr, ret))if subsys_name == "demo_peri_subsystem" or subsys_name == "demo_aon_subsystem":continueelse:return -1# else if mode == 1:except DebugException, e:print("Excetpion: DS-5 Scan %s reg:0x%x failed!!!, read:0x%x" %(name, addr, ret))if subsys_name == "demo_peri_subsystem" or subsys_name == "demo_aon_subsystem":continueelse:return -1return 0# demo_aon_subsystem scan
ret = demo_subsys_scan(demo_aon_subsystem, "demo_aon_subsystem", 0)
if ret == 0:print("#######  demo_aon_subsystem scan test finished ######\\n")
else:print("demo_aon_subsystem scan failed !!!\\n")# peri_subsys scan
ret = demo_subsys_scan(peri_subsys, "demo_peri_subsystem", 0)
if ret == 0:print("#######  peri_subsys scan test finished ######\\n")
else:print("demo_peri_subsystem scan failed !!!\\n")