Skip to main content
欢迎来到PAWPAW技术文档网站了解更多信息

Code Debugging

本文中,我们针对代码编译过程中出现的一些报错,进行记录并提供参考的解决思路。

fl_copySpec未引用

执行cmake -B build -DCMAKE_TOOLCHAIN_FILE=xmos_cmake_toolchain/xs3a.cmake 时,出现如下错误。

Error: Undefined reference to 'fl_copySpec'

解决思路:

请使用最新的XTC软件版本(>= 15.2.1),该问题由sfdp 所引起,需要XTC对SFDP启用泛型支持。

xscope 环境变量为空

安装时,打印出现如下错误:

Set runtime path of "/opt/xmos/bin/xscope_host_endpoint" to ""

如下图:

image_dzsbia2sL

当你在linux类系统的root user权限下,执行make install 时,会出现环境变量无法配置的情况,所以为空(to " ")

解决思路:

  • 思路1:退出root mode,重新执行make install

  • 思路2:手动添加环境变量

    1. 使用编辑器(如nano)将配置添加进环境变量文件中。例如,使用以下命令打开.bashrc文件:

      nano ~/.bashrc
    2. 在文件的末尾添加环境变量:

      export PATH="/opt/xmos/bin:$PATH"

      这将在每次登录时将/opt/xmos/bin添加到PATH环境变量中。保存并关闭文件(在nano编辑器中,按下Ctrl+X,然后按Y确认保存,最后按Enter键关闭)。

    3. 重启终端或执行以下命令以使配置文件生效:

      source ~/.bashrc

      现在,无论何时登录到系统,/opt/xmos/bin目录都会自动添加到PATH环境变量中。 使用echo $PATH命令查看环境变量PATH,以验证更改已正确应用。

malloc_lock_object

malloc_lock_object 具体报错如下图:

image_QuJ-MmrbHW

解决思路: 在编译时添加-mcmodel=<model>选项

  1. 选择 memory modelsmalllarge,或 hybrid

  2. 在这里,我们进入项目的Makefile,向BUILD_FLAGS选项中添加-mcmodel=large

  3. 如果添加-mcmodel=large后仍有问题,在定义数组前一行添加预处理器指令:#pragma large_arrays

SetSampleRate -> OxEF000011

在驱动面板切换采样率时, 出现SaveSelectedSampleRate: TUSBAUDIO_SetSampleRate -> OxEF000011 image_RHCo_PwsKt

解决思路: 由于Audio线程没有及时的切换,在Audio中存在过多的延时。

  • 例如在AudioHwConfig()长时间delay就会出现此报错,应当减小延迟,以避免线程阻塞

no '<' before the end of file

执行命令:xburn --read --target-file XXX.xn

报错update.xml: error: no '<' before the end of file

解决思路: 在XN文件中存在网址,网址连接问题;将网络断开或修改最新的XMOS网址,再执行xburn命令即可。

FL_QUADDEVICE_DEFAULT

报错use of undeclared identifier 'FL_QUADDEVICE_DEFAULT'

解决思路: 版本检查只适用于XTC软件版本(>= 15.2.1),请使用最新的XTC软件版本。

大小端序问题

  • XCORE内存的存储方式是小端序(least significant byte at lowest address)

  • 通道 Channel的传输方式可以看作大端序 big endian(most significant byte sent first over the the channel)

  • 通过XTC编译器中包含的byterev()指令,可以翻转一个word内的bytes,从而允许高效地访问存储为big endian的数据。

使用extends时,提示无需在外部提供定义

在使用lib_i2c,自行添加extends api(例如extends client interface i2c_master_if)时,编译时出现找不到添加的extends api

Error: Undefined reference to '__i_i2c_master_if_user_init' (possible inline definition without external definition)

解决思路:

需要在i2c.h文件的最后,添加extends api所在的文件(如: #include"i2c_config_extends.h")

同时extern extends api到i2c_master_ext.xc文件当中,参考如下

extends client interface i2c_master_if : 
{
extern inline void i2c_config_user_init(client interface i2c_master_if i2c);
}

'clock'重新定义为不同类型的符号

错误:将'clock'重新定义为不同类型的符号clock_t _EXFUN(clock, (void));

具体重定义报错如下

/opt/xTIMEcomposer_14.3.3/target/include/time.h:47:19: error: redefinition of 'clock' as different kind of symbol
clock_t _EXFUN(clock, (void));
^
/opt/xTIMEcomposer_14.3.3/target/include/_ansi.h:75:30: note: expanded from macro '_EXFUN'
#define _EXFUN(name, proto) name proto
^
/opt/xTIMEcomposer_14.3.3/target/include/xccompat.h:198:18: note: previous definition is here
typedef unsigned clock;
^
1 error generated.

情况说明:当在USB-Audio-v6.15.2(原sw_usb_audio-[sw]_6.15.2)代码中,添加并使用某些最新的lib, 且使用旧的Community_14.x.x编译代码时,会出现如上报错。

路径:xTIMEcomposer_14.x.x/target/include/xccompat.h

需要人为修改xccompat.h文件,修改项如下

#ifndef _clock_defined
#define _clock_defined
typedef unsigned clock;
#endif /* _clock_defined */

修改后

#ifndef _clock_defined
#define _clock_defined

typedef unsigned xcore_clock_t;

#ifdef XCORE_USE_LEGACY_CLOCK_NAMING
typedef xcore_clock_t clock;
#endif // XCORE_USE_LEGACY_CLOCK_NAMING
#endif /* _clock_defined */

0x00080e10 fl_getNumSectors()

报错详情:

xrun: Program received signal ET_ARITHMETIC, Arithmetic exception.
0x00080e10 in fl_getNumSectors ()

使用情况:

  • 在对Flash进行读写操作(QSPI Mode)的时候,需要连接设备,并设定boot分区大小,连接Flash异常会出现上述的错误
连接Flash,并设定boot分区示例
#include <xs1.h>
#include <platform.h>

#include "quadflash.h"
#include "quadflashlib.h"

#define FLASH_PARTITION_SIZE (65536 /* 64K */ * 24) // Boot Partition size

#define FL_QUADDEVICE_UC25HQ16 \
{ \
0, /* UC25HQ16B_QSPI - Just specify 0 as flash_id */\
256, /* page size */\
8192, /* num pages */\
3, /* address size */\
4, /* log2 clock divider */\
0x9F, /* QSPI_RDID */\
0, /* id dummy bytes */\
3, /* id size in bytes */\
0xB36013, /* device id */\
0x20, /* QSPI_SE */\
4096, /* Sector erase is always 4KB */\
0x06, /* QSPI_WREN */\
0x04, /* QSPI_WRDI */\
PROT_TYPE_SR, /* Protection via SR */\
{{0x3C,0x00},{0,0}}, /* QSPI_SP, QSPI_SU */\
0x02, /* QSPI_PP */\
0xEB, /* QSPI_READ_FAST */\
1, /* 1 read dummy byte */\
SECTOR_LAYOUT_REGULAR, /* mad sectors */\
{4096,{0,{0}}}, /* regular sector sizes */\
0x05, /* QSPI_RDSR */\
0x01, /* QSPI_WRSR */\
0x01, /* QSPI_WIP_BIT_MASK */\
}

on tile[0]: fl_QSPIPorts QspiPort =
{
PORT_SQI_CS, /* XS1_PORT_1B */
PORT_SQI_SCLK, /* XS1_PORT_1C */
PORT_SQI_SIO, /* XS1_PORT_4B */
XS1_CLKBLK_1
};

fl_QuadDeviceSpec flash_devices0[1] = {FL_QUADDEVICE_UC25HQ16};

fl_connectToDevice(QspiPort, flash_devices0, 1); /* 连接Flash */
fl_setBootPartitionSize(FLASH_PARTITION_SIZE); /* 设定 Boot分区的大小,其余的是 Data分区 */

问题点: 运行例程时,Flash描述文件spec中,device id与实际的器件不匹配;

解决方式:

  • 通过以下命令获取正确的device id
xflash --spi-read-id 0x9f --target=XCORE-AI-EXPLORER

打印结果

Response to SPI ID command on tile[0]: 0xb3, 0x60, 0x15, 0x0.

将示例的FL_QUADDEVICE_UC25HQ16宏,修改设定的device id,0xB36013修改为0xB36015,就可以正常连接到设备并设定Boot分区

未定义'fl_connectToDevice'

报错详情:

   Error: Undefined reference to 'fl_connectToDevice'
Error: Undefined reference to 'fl_getDataPartitionSize'
Error: Undefined reference to 'fl_setBootPartitionSize'

使用情况:

  • 通过QSPI Mode,对Flash进行读写操作

    在XC或C文件中添加了#include "quadflash.h"#include "quadflashlib.h",实际调用fl_connectToDevice出现了未定义的错误

解决方式: 在Makefile文件,找到BUILD_FLAGS或XCC_FLAGS变量定义,在变量的值中添加-lquadflash参数

这个参数是用来链接quadflash库,它可能包含了操作quad SPI flash的函数和定义。添加这个参数后,编译器会在链接时包含这个库,使得项目能够使用库中定义的资源。

   BUILD_FLAGS += -lquadflash
// XCC_FLAGS += -lquadflash

I2C 控制:计时器数值越界问题

在修改了 lib_i2c 库的行为后,观察到以下不正确的行为,如图所示:

  • 在标识 (1)-(2) 之间,时间间隔为 21 秒,I2C_CLK 和 I2C_SDA 被强制置为 "0"(或出现不可控的行为)。
  • 在标识 (2)-(3) 之间,时间间隔为 21 秒,I2C 时钟和数据线正常工作,且 I2C 正常运作的时间也为 21 秒。

如下图所示,这两种行为轮替交替出现: image-20240110145733769

现象分析

  • timerafter 函数将计时器的计数值视为具有两个不同的范围,如下图所示: image-20240110150907517

    所有在范围 (time231time1)(\text{time} - 2^{31} \ldots \text{time} - 1) 之间的值都被视为在 time 之前发生,而范围 (time+1time+2321,0time231)(\text{time} + 1 \ldots \text{time} + 2^{32} - 1, 0 \ldots \text{time} - 2^{31}) 之间的值则被视为之后发生。如果两个输入的值之间的间隔可以在 31 位数值内表示,则可以保证 timerafter 函数的正确行为。否则,可能由于数值溢出而导致不正确的行为。也就是说,计时器可以用来测量的最长时间为 231/10000000002^{31}/1000000000 秒,即 21 秒。

    一个常见的编程错误是在输入新的时间时,没有将其转换为无符号类型,而是忽略了类型,如下所示:

    t when timerafter(time) :> time;

    由于处理器并不是在时间到达后立即完成输入,这个操作实际上会在 time 上增加一小段额外的时间。这个小的增量在循环中累积,最终导致信号偏移,并与接收器不同步。time 的时间越界不符合要求,因此每次需要将 time 重新赋值为 0。

解决方案

  • 在 I2C 的 start_bit 中,存在对 fall_time 重新赋值的操作。将这段代码恢复即可解决问题;或者,在使用 I2C 之前,调用以下的 time_init 函数来初始化时间:
static void time_init(unsigned &fall_time)
{
timer tmr;
tmr :> fall_time;
}