7.7 VDSP开发指南
基础调试指南
CPU侧开发
镜像加载卸载
S100系统在启动时默认不启动VDSP FW(Firmware),需要用户通过命令的形式手动加载和卸载FW,命令如下所示:
echo -n <firmware路径> > /sys/module/firmware_class/parameters/path
#S100 VDSP0
# 设置VDSP0 FW名称:
echo <firmware名称> > /sys/class/remoteproc/remoteproc_vdsp0/firmware
#VDSP0的FW加载:
echo start > /sys/class/remoteproc/remoteproc_vdsp0/state
#VDSP0的FW卸载:
echo stop > /sys/class/remoteproc/remoteproc_vdsp0/state
用户可通过以下命令修改FW路径(必须是绝对路径):
echo -n <firmware路径> > /sys/module/firmware_class/parameters/path
用户可根据自己命名的FW名称在加载之前进行调整:
#S100 VDSP0
echo <firmware名称> > /sys/class/remoteproc/remoteproc_vdsp0/firmware
用户需要修改原始镜像,配置init.rc,kernel启动后由init进程自动加载VDSP镜像。
#首先将编译出的FW镜像(如vdsp0)拷贝到/userdata 下
echo -n <firmware路径> > /sys/module/firmware_class/parameters/path
#S100 VDSP0
echo <firmware名称> > /sys/class/remoteproc/remoteproc_vdsp0/firmware
echo start > /sys/class/remoteproc/remoteproc_vdsp0/state
FW版本查看
#S100 VDSP0
cat /sys/class/remoteproc/remoteproc_vdsp0/version # for vdsp0
VDSP运行状态查看
#running表示已加载,offline表示未加载
#S100 VDSP0
cat /sys/class/remoteproc/remoteproc_vdsp0/state # for vdsp0
心跳监控
默认处于关闭状态,可通过下列命令打开或关闭;心跳监控、发送周期为100ms,监控到连续7次心跳被丢失就会上报诊断并reset VDSP。
# 打开心跳监控
echo Y > /sys/module/hobot_remoteproc/parameters/heartbeat_enable
# 关闭心跳监控
echo N > /sys/module/hobot_remoteproc/parameters/heartbeat_enable
通过函数接口形式操作vdsp
通过libvdsp.so动态链接库加载DSP程序,实现加载、启动、停止、复位、获取DSP状态等功能,API介绍可参考 VDSP启停控制接口。
消息连接和发送
目前用户只可使用系统预设的服务名称,可使用的服务名如下表所示:
| VDSP | 服务名称 | 作用 | 是否必须启动 | VDSP侧是否默认启动 |
|---|---|---|---|---|
| DSP0/1 | dcore0_device_op/dcore1_device_op | 系统软件内部对DSP的调试控制,系统软件已经使用,用户不可再次注册和使用 | 是 | 是 |
| DSP0/1 | dcore0_acore_heart/dcore1_acore_heart | 心跳机制使用,目前未使用,用户可用作其他用途 | 否 | 否 |
| DSP0/1 | dcore0_rpmsg_bpu/dcore1_rpmsg_bpu | BPU相关的控制,目前未使用,用户可用作其他用途 | 否 | 否 |
| DSP0/1 | dcore0_rpmsg_op/dcore1_rpmsg_op | 工具链算子相关的控制,目前未使用,用户可用作其他用途 | 否 | 否 |
| VDSP | 服务名称 | 作用 | 是否必须启动 | VDSP侧是否默认启动 |
|---|---|---|---|---|
| DSP0 | dcore0_device_op | 系统软件内部对DSP的调试控制,系统软件 已经使用,用户不可再次注册和使用 | 是 | 是 |
| DSP0 | dcore0_acore_heart | 心跳机制使用,目前未使用,用户可用作其他用途 | 否 | 否 |
| DSP0 | dcore0_rpmsg_bpu | BPU相关的控制,目前未使用,用户可用作其他用途 | 否 | 否 |
| DSP0 | dcore0_rpmsg_op | 工具链算子相关的控制,目前未使用,用户可用作其他用途 | 否 | 否 |
用户可使用的API可参考下表:
| 接口 | 功能 | 头文件 | 相关库 |
|---|---|---|---|
| hb_rpmsg_connect_server | 连接服务 | rpmsg_lib.h | librpmsg.so |
| hb_rpmsg_disconnect_server | 断开服务 | rpmsg_lib.h | librpmsg.so |
| hb_rpmsg_send | 发送消息 | rpmsg_lib.h | librpmsg.so |
| hb_rpmsg_recv | 接收消息 | rpmsg_lib.h | librpmsg.so |
其中,同一个服务通道,不支持多进程、多线程并发接收或发送。
heap相关开发
VDSP提供了动态分配释放heap接口,支持配置自定义内存对齐大小,以及支持查看当前heap状态,当VDSP端需要动态分配heap时,可以通过以下接口实现。
| 接口 | 功能 | 相关头文件 |
|---|---|---|
| hb_mem_heap_initialize | 初始化mem alloctor接口 | hb_mem_allocator.h |
| hb_mem_heap_deinitialize | 解初始化mem alloctor接口 | hb_mem_allocator.h |
| hb_mem_heap_alloc | 分配heap空间 | hb_mem_allocator.h |
| hb_mem_heap_free | 释放已分配的heap空间 | hb_mem_allocator.h |
| hb_mem_heap_get_status | 获取当前heap状态 | hb_mem_allocator.h |
VDSP侧开发
代码获取步骤如下:
(1)首先获取到发布包,解压后确认有vdsp源码。如果无,联系地瓜相关人员进行获取。
(2)在vdsp路径下可以获取到vdsp源码。
Linux环境搭建
获取build包建立编译环境。其中build包的获取请联系地瓜相关人员进行获取。
本文档仅提供Linux环境搭建及编译的说明介绍。对于文档中提到的xplorer中获取调试文档请联系地瓜相关人员进行获取。
Linux环境下安装build的命令:
tar -zxvf Vision_Q8_linux.tgz \
&& mv RI-2023.11-linux/Vision_Q8/ /opt/xtensa/XtDevTools/install/builds/RI-2023.11-linux/ \
&& rm -rf RI-2023.11-linux
/opt/xtensa/XtDevTools/install/builds/RI-2023.11-linux/Vision_Q8/install --xtensa-tools \
/opt/xtensa/XtDevTools/install/tools/RI-2023.11-linux/XtensaTools/
编译
获取代码后编译步骤如下:
(1)cd vdsp_fw
(2)bash make.sh
静态库生成在library目录
library/libvdsp0.a
二进制镜像生成在samples目录
samples/{subdir}/vdsp0
调试指南
日志查看
VDSP FW的日志会通过串口输出。
需要注意的是VDSP FW与其他模块共用一个串口,如BL31、optee,若VDSP FW输出日 志太多,可能会阻塞这些模块的日志输出,引起watchdog。 另外VDSP FW日志和kernel日志都输出到串口中,存在相互干扰的问题,用户可通过降低kernel日志等级来防止日志干扰:
echo 0 > /proc/sys/kernel/printk
当没有串口可用的情况下,用户可通过ssh登录板子,后台默认会启动hrut_remoteproc_log服务:
#S100 VDSP0 默认开机执行的启动命令,日志保存路径:/log/dsp0/message
hrut_remoteproc_log -b /sys/class/remoteproc/remoteproc_vdsp0/log -f /log/dsp0/message -r 2048 -n 200
同样的,VDSP FW的日志会写入Share memory中,由CPU侧log服务进程存入文件系统中。因此用户可通过以下路径下的文件查看日志,但是需要注意的是这里的日志并不是实时的。
#S100 VDSP0的日志路径:
/log/dsp0/message
/log/dsp0/archive/
#message是临时文件,存满之后会写入到archive/目录下,当该目录下的文件达到一定数量后,会删除时间较早产生的文件
日志打印接口
使用printf接口日志会通过串口输出。
推荐使用DSP_ERR、DSP_WARN、DSP_INFO、DSP_DBG接口,该接口除了将日志通过串口输出,还会将日志写入Share memory中,通过CPU侧的log服务将日志信息存入文件系统中。
DSP_*接口使用注意事项:
- 头文件
hb_vdsp_log.h - 接口使用示例。比如进入异常分支需要打印日志时,使用DSP_ERR接口,
DSP_ERR("Input parameter invalid.\n");
线程状态查看
通过以下命令可在串口中查看VDSP侧的线程状态。需要注意的是以下数据的统计和输出可能会影响VDSP的性能。
使用方法:首先需要代码中使能#define THREAD_STACK_CHECK (1),其次需要在新启动的线程前使能栈跟踪,如下所示:
(void)hb_enable_stack_track(dev_thread_stack, sizeof(dev_thread_stack)/sizeof(dev_thread_stack[0]));
#S100 VDSP0:
echo on > /sys/devices/virtual/misc/vdsp0/vdsp_ctrl/dspthread
echo off > /sys/devices/virtual/misc/vdsp0/vdsp_ctrl/dspthread
coredump查看
和coredump相关的系统软件初始化主要有两部分:注册异常和使能看门狗。
hb_wdt_on();
hb_enable_coredump();
目前xos能够处理的异常类型如下:
/* EXCCAUSE register values: */
/* General Exception causes (Bits 3:0 of EXCCAUSE register) */
/* No exception */
#define EXCCAUSE_NONE UINT32_C(0)
/* Instruction usage */
#define EXCCAUSE_INSTRUCTION UINT32_C(1)
/* Addressing usage */
#define EXCCAUSE_ADDRESS UINT32_C(2)
/* External causes */
#define EXCCAUSE_EXTERNAL UINT32_C(3)
/* Debug exception */
#define EXCCAUSE_DEBUG UINT32_C(4)
/* Syscall exception */
#define EXCCAUSE_SYSCALL UINT32_C(5)
/* Hardware failure */
#define EXCCAUSE_HARDWARE UINT32_C(6)
/* Memory management */
#define EXCCAUSE_MEMORY UINT32_C(7)
/* Coprocessor */
#define EXCCAUSE_CP_DISABLED UINT32_C(8)
/* Reserved 9-15 */
不应在 VQ8 上为异常原因 4(调试异常)/5(SYSCALL 异常)/8(协处理器异常)注册异常处理程序,为系统预留使用。 需要注意的是:9-15 为预留类型,也需要略过不注册。
离线调试方法如下: VDSP发生coredump时,Acore会把VDSP所有可能使用的memory空间(iram/dram0/dram1/reserved ddr)全部写入指定的文件系统中,路径如下:
#vdsp0
/log/coredump/
新建restore.script.sh脚本,4个memory dump文件的路径根据实际项目的存放路径设 置,把获得到的CPU寄存器复制到该脚本对应处,如下所示:
python import thread_aware_rtos
python thread_aware_rtos.k.rtos_support.dump_analysis_mode = True
b main
run
restore vdsp0_ddr_2024-05-06-02-50-03.hex binary 0xf0000000
restore vdsp0_iram_2024-05-06-02-50-03.hex binary 0x08080000
restore vdsp0_dram0_2024-05-06-02-50-03.hex binary 0x08000000
restore vdsp0_dram1_2024-05-06-02-50-03.hex binary 0x08040000
set $ar0 = 0xf00502a8
set $ar1 = 0xf3fdded0
set $ar2 = 0xf3fddd00
set $ar3 = 0x34
set $ar4 = 0x1b
set $ar5 = 0x5d
set $ar6 = 0x53
set $ar7 = 0x58
set $ar8 = 0xf0050192
set $ar9 = 0xf3fddeb0
set $ar10 = 0x4f
set $ar11 = 0xf3fddd00
set $ar12 = 0x0
set $ar13 = 0xf3fddee0
set $ar14 = 0xf3fddce0
set $ar15 = 0xf3fddd1b
set $ar16 = 0xf0065978
set $ar17 = 0xf3fddb60
set $ar18 = 0x4f
set $ar19 = 0xf002bea4
set $ar20 = 0x0
set $ar21 = 0xffffffb1
set $ar22 = 0x4f
set $ar23 = 0xffffffff
set $ar24 = 0x808100f
set $ar25 = 0xf3fddf00
set $ar26 = 0xf3fddf10
set $ar27 = 0x53113
set $ar28 = 0xf0050280
set $ar29 = 0xffffffff
set $ar30 = 0x0
set $ar31 = 0xf3fddf70
set $ps = 0x68
set $wb = 0x40000311
set $pc = 0xf0050057
python thread_aware_rtos.k.rtos_support.XOS_initialized = True
打开xt-gdb命令行(xplorer或者命令行模式均可),按照顺序执行如下操作:
xt-gdb vdsp0 (可执行文件的目标文件)
(xt-gdb) >> source restore.script.sh
(xt-gdb) >> run
ctrl+c //取消运行
(xt-gdb) >> stepi
(xt-gdb) >> info threads
(xt-gdb) >> bt
backtrace调试信息显示如下:
(xt-gdb) bt
#0 _RMCDump () at /vdsp/bsp_project/coredump/RegDump.S:90
#1 0xf0050192 in Exc_Dump_Regs () at bsp_project/coredump/Exc_Dump_Regs.c:110
#2 0xf00502a8 in dafault_exchandler (frame=0xf3fddf10) at bsp_project/coredump/coredump.c:125
#3 0x0808100f in _GeneralException (cause=..., exccause=...) at ./xos_vectors_xea3_v2.S
#4 0xf00504b8 in hb_platform_init () at bsp_project/driver/devcontrol/devcontrol.c:152
#5 0xf0030306 in main (argc=1, argv=0xf0073704) at main.c:68
Stack usage查看
Stack usage的说明建议阅读Xtensa® XOS Reference Manual Reference Manual:<VDSP安装路径>/xtensa/XtDevTools/downloads/<version>/docs/xos_rm.pdf。
MPU配置
目前部署的MPU主要两个作用,一是用来限制VDSP访问地址的范围,访问超过MPU允许的范围会报coredump错误,第二个作用是可以配置地址段的属性,详细介绍请参考Xtensa® System Software Reference Manual:<VDSP安装路径>/xtensa/XtDevTools/downloads/<version>/docs/xos_rm.pdf。
VDSP地址映射以及MPU保护部分如下图所示,访问MPU保护地址范围外会报coredump错误。

报错log如下图所示,错误地址为0x0,表示访问了不允许访问的地址:

目前对于VDSP地址的属性配置,主要包括三个部分:
(1)对于ION空间的属性配置: XTHAL_MEM_WRITEBACK
(2)对于两个共享内存区域的属性配置:XTHAL_MEM_NON_CACHEABLE
(3)对于除(1)(2)外其他段的属性配置:XTHAL_MEM_WRITEBACK
Cadence文档路径位置
安装Xplorer后,可通过如下位置<VDSP安装路径>/xtensa/XtDevTools/downloads/RI-2023.11/docs查看已下载的文档路径。
FAQ
VDSP侧耗时统计方式有哪些?
用户可使用gettimeofday()直接获取时间,也可通过XT_RSR_CCOUNT()获取count个数来换算时间,前者需要包含#include <sys/time.h>头文件。建议使用后者来统计时间,更精确,且不建议在耗时要求较高的场景下打印日志。
此外用户还可参考Xtensa® Software Development Toolkit User's Guide:<VDSP安装路径>/xtensa/XtDevTools/downloads/<version>/docs/sw_dev_toolkit_ug.pdf。
LSP如何修改?
(1)拷贝一份模板lsp
(2)编辑memmap.xmm
(3)重新生成memmap,执行命令:xt-genldscripts -b custom_lsp/q8-min-rt/
调试使用xos工具时,提示找不到工具链,先确认xos build环境是否建立。
如果建立,配置环境变量,比如配置临时环境变量export PATH=$PATH:[*]/XtensaTools/bin
CPU侧start加载和stop卸载FW时提示不成功?
可能是stop时服务根本没启动,或者start时服务已启动。
VDSP侧如何增加用户线程?
示例代码如下:
ret = xos_thread_create(&dev_thread_tcb, 0, dev_thread_func, 0, "dev_control", dev_thread_stack, STACK_SIZE_1, TRACE_THREAD_PRIO, 0, 0);
其中dev_thread_func表示创建的线程函数,用来实现用户想要在线程函数中处理的功能。dev_thread_stack表示指向线程栈的首地 址(由用户分配)。STACK_SIZE_1表示栈的大小。TRACE_THREAD_PRIO表示线程优先级,取值范围在0~15,数值越小优先级越高。
VDSP侧如何获取设备id?
可以使用xthal_get_prid()。
VDSP侧idma使用哪个库?

请使用libidma-os或者libidma-debug-os,因为我们使用xos。
int64_t/uint64_t/float类型的变量打印出错?
如果int64_t/uint64_t/float定义的变量在打印时输出异常的值,而在使用时(如进行大小比较等操作)是正常的。
这是因为xtensa/xtutil.h头文件会将printf、vsnprintf等函数替换为xt_printf,xt_vsnprintf,用户需要将xtutil.h头文件注释掉,使用原生的printf、vsnprintf接口。
标准C库的printf等函数,无法在中断handler中使用,否则会卡死。
VDSP在运行过程中出现卡住问题
需要排查变量指针的地址是否是对齐:
(1)(int64_t *)类型的变量指针的地址需要八字节对齐
(2)(int32_t *)类型的变量指针的地址需要四字节对齐
(3)(int16_t *)类型的变量指针的地址需要二字节对齐
确认在中断handler是否使用了标准C库的printf等函数,目前中断handler不支持使用。
使用sim软仿时出现seg段溢出问题
需要更改sim的xmm文件,路径:xtensa/xtensa/XtDevTools/install/builds/RI-2023.11-win32/Vision_Q8/xtensa-elf/lib/sim/memmap.xmm, 将相应的溢出段的值改大,在xplorer下打开cmd:

进到xtensa-elf/lib路径下:

执行xt-genldscripts -b sim,如下提示表明成功:

再次编译vdsp工程,进行sim软仿。
Idma搬运过程中出现异常停止问题
出现此情况可以查看idma init函数中,是否有设置运行时间,置0可以关闭时间限制:

在windows环境编译出的镜像提示dcore0_rpmsg_op server not start
需要手动在Build Properties中添加CONFIG_TEST_CASE:
