在使用ARM DS-5 连接 board(或者PFGA)之前首先需要能够扫描到相应的硬件信息,比如对应的cpu的相关信息:coresight 相关组件信息,Cache信息等。
创建好工程项目后按照下图黄线的指示进行扫描操作(通常是完成扫描后才会去执行 “build platform
”):
如果更换平台之后,最好先进行 clean platfom 操作,然后再重新 build platform 操作。
在扫描完成后在DS-5的console中会打印相关的信息,扫描完成后的操作是进行连接操作(见图 1-1)。
通常我们会使用uart或者SPI来烧写镜像到flash,然后再从flash启动,这个过程在实际的debug场景中比较耗时,尤其是当串行时钟比较低的时候。所以我们可以直接使用DS-5通过JTAG
接口来烧写镜像到对应的 memory 中,然后再配置好 PC 指针,直接跳转过去既可以启动对应的固件。
图 1-1
上图 1-1 中对应的脚本代码如下:
# Filename: load_rtos_schan.py
import sys
import os
import time
from arm_ds.debugger_v1 import Debugger
from arm_ds.debugger_v1 import DebugException
debugger = 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中的代码主要时做循环检测外部接入信号
以写读 0x48000000 地址为例,如下代码:
# Filename: load_rtos_schan.py
import sys
import os
import time
from arm_ds.debugger_v1 import Debugger
from arm_ds.debugger_v1 import DebugException
debugger = 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 = 0x48000000
for 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 register
value = 0x1
else:
value = i * 4
ec.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
:0x46020004 32 1”
TIPS: "alt+/ " 调出 commands 栏 help命令说明:
通常芯片回来后软件同学需要做的第一件事就是完成寄存器扫描,保证系统及各个IP的寄存器可以正常写读,通常会按照各个Subsystem进行扫描,一般情况下每个 IP 都少扫描1-2个寄存器,按照先写再读的方式进行扫描。
扫描脚本首先需要保证以下几点:
下面给出了一个简单的DEMO, 该demo 使用的是Python 脚本完成的。
# Filename: DS5_Reg_Scan.py
import sys
import os
import time
from arm_ds.debugger_v1 import Debugger
from arm_ds.debugger_v1 import DebugException
debugger = 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 name
0x66004000, 0x55, "hrtimer0",
0x66004014, 0x55, "hrtimer1",
0x66004028, 0x55, "hrtimer2",
]
peri_subsys = [
# reg_adr write_val ip name
0x6c002004, 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 = 0xdeadbeef
list_len = len(subsys) / 3
print("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 value
ret = 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":
continue
else:
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":
continue
else:
return -1
return 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")
上篇文章:ARM Coresight DS-5 系列 3 - DS-5 断点设置及常用Debug 命令