背景说明
前期基本实现PS端的CAN总线功能,现阶段的主要目的是实现PL端的CAN总线功能,需要采用CAN IP。
1PL系统搭建
PL外设时钟源
搭建完vivado系统后,需要在sdk编程。但是在配置PL-CAN时,意识到CAN时钟值不清楚,于是检查zynq系统,发现PL-CAN外设的时间来自于FCLK-CLK0。这个时钟值与CAN外设的关系是可以在block design看到的。配置表显示FCLK-CLK0为50Mhz,编程可以按照这个值。
下载失效:
再次出现下载程序,zynq开发板没有反应的情况。下载的程序是LED,以前应用时也没有特别的问题。考虑到explorer包含大多的应用工程,于是删除了无关的工程,重新实现特定的功能。
run as program FPGA配置
前期下载程序时,有时program FPGA无法点击。这可能也是下载程序不成功的原因,可以考虑从这个现象入手。
XCan_GetMode error
运行以下程序时,发现XCan_SelfTes无法获得配置模式。因此需要定位外设到底哪里出现问题。
if (XCan_GetMode(InstancePtr) != XCAN_MODE_CONFIG) {
print("test1\r\n");
return XST_FAILURE;
}
定位问题到XCan_GetMode,获得状态码为normal mode而不是configuration mode。 其中,xil_printf能够进入参数化输出,print无法实现。这说明模块本身就出现问题,无法在重置后,顺利进入配置模式。
#define XCAN_MODE_CONFIG 0x00000001 /**< Configuration mode */
#define XCAN_MODE_NORMAL 0x00000002 /**< Normal mode */
#define XCAN_MODE_LOOPBACK 0x00000004 /**< Loop Back mode */
#define XCAN_MODE_SLEEP 0x00000008 /**< Sleep mode */
/*
* The device should enter Configuration Mode immediately after the
* reset above is finished. Now check the mode and return error code if
* it is not Configuration Mode.
*/
if (XCan_GetMode(InstancePtr) != XCAN_MODE_CONFIG) {
value = XCan_GetMode(InstancePtr);
xil_printf("getmode error:\r\n");
xil_printf("getMode:%d\r\n",value);
return XST_FAILURE;
}
即使在重置函数后添加EnterMode函数,也无法顺利进入**配置模式。面对这种问题,感觉远处着手。
/* Reset device first */
XCan_Reset(InstancePtr);
XCan_EnterMode(InstancePtr, XCAN_MODE_CONFIG);
/*
* The device should enter Configuration Mode immediately after the
* reset above is finished. Now check the mode and return error code if
* it is not Configuration Mode.
*/
if (XCan_GetMode(InstancePtr) != XCAN_MODE_CONFIG) {
print("get mode error\n\r");
return XST_FAILURE;
}
由于这是一个新的工程,我选择先测试自己编写代码,测试一下PS-CAN外设。在这个基础上,慢慢定位PL-CAN的问题。在初始化PS-CAN时,selftest功能正常,这说明问题主要出现在CAN控制器外部。想到以前在microblaze平台测试CAN IP功能,是通过【学习了自动补全功能,alt+/感觉不错】
在编写CAN发送程序时,需要了解CAN帧的发送信息结构。按照其CAN帧的库函数逻辑,编写如下代码。可惜,逻辑分析仪现象如前期一样,单个CAN帧周期,却出现多个CAN的解码。虽然可能是波特率较小所致,但是调整波特率为80K时,仍然无法解析。编码值全为1,而且整个解码的长度是跟单个CAN帧周期的长度是一致。换言之,可能在没有CAN收发器的情况下,逻辑分析仪的接收波特率都变小的。虽然实际配置的波特率为500K。~虽然可以利用跳线使用野火开发板的CAN收发器,但是实际没有效果,不知道什么环节出现问题。
//测试can 功能自测
status = XCanPs_SelfTest(&Can);
print("self test point\r\n");
if(status != XST_SUCCESS)
{
print("self test error\n\r");
}
//配置波特率
XCanPs_EnterMode(&Can, XCANPS_MODE_CONFIG);
XCanPs_SetBaudRatePrescaler(&Can,3);
XCanPs_SetBitTiming(&Can,3,2,15);
//发送CAN数据
XCanPs_EnterMode(&Can,XCANPS_MODE_NORMAL);
while(XCanPs_GetMode(&Can) != XCANPS_MODE_NORMAL)
{
print("normal mode error\r\n");
sleep(1);
};
//装填Can帧数据
TxFrame[0] = (u32)XCanPs_CreateIdValue((u32)2000,0,0,0,0);
TxFrame[1] = (u32)XCanPs_CreateDlcValue((u32)8);
FramePtr = (u8*)(&TxFrame[2]);
for(i = 0;i<8;i++)
{
*FramePtr++ = (u8)8;
}
//CAN发送
while(XCanPs_IsTxFifoFull(&Can) == TRUE)
{
print("IsTxFifoFull error\r\n");
};
XCanPs_Send(&Can,TxFrame);
重新开始
由于上篇文章已经解决PS-CAN帧发送问题,因此本文在此系统基础上实现相关的功能。上篇文章主要实现EMIO的CAN0发送功能,后面首先实现MIO的CAN1帧发送功能,其次实现PL-CAN发送功能,然后添加多个PL-CAN外设。
基本复制PS-CAN0的配置程序,PS-CAN1也成功发送CAN帧。但是与CAN0一样,CAN1发送的数据后面就不正常了,不是全部为预期的3。在两个CAN都发送CAN帧的情况下,CAN0和CAN1发送的CAN帧数据都存在问题,只有ID是没有问题的。
PL引脚约束-分歧点
由于ZYNQ的引脚特性比较多样,并非所有引脚都能任意使用。在引脚约束中,需要清楚特殊功能引脚、BANK区、内存组等是否影响CAN引脚功能。7020引脚约束文件
选择如下四个引脚,通过测试可以判断出内存组和AD特殊功能是否影响CAN引脚外设功能。
M19 IO_L7P_T1_AD2P_35 1 35 NA NA HR plcan0rx
M20 IO_L7N_T1_AD2N_35 1 35 NA NA HR plcan0tx
H15 IO_L19P_T3_35 3 35 NA NA HR plcan1rx
F16 IO_L6P_T0_35 0 35 NA NA HR plcan1tx
G17 IO_L16P_T2_35 2 35 NA NA HR pscanrx
G18 IO_L16N_T2_35 2 35 NA NA HR pscantx
此外,CAN IP中包含一个时钟接口。目前忽略不用,使用内部的时钟看看是否影响CAN外设功能。
CAN CLK外部时钟设置
IO规划错误,两个CAN时钟引脚没有约束,导致比特流生成错误。PG096 CANIP
CAN数据手册中提出,CAN的两个IP都是可用的。在使用内部的AXI总线时钟时,似乎必须使用CAN CLK,而非我原先以为的不用关注。
2PL-CAN功能实现
检查xparameters.h等文件,确认硬件工程没有问题。首先在前面工程基础上,直接添加CAN-PL的自测功能。结果出现无法进入config模式错误。这意味着,无法进入回环模式、配置模式和正常模式问题都碰到了。GetMode函数返回的状态说明,此时CAN0处于回环模式。
无法进入config模式
实验结果表明,PL-CAN经过重置后,会进入到回环模式。这与一般直接进入配置模式不同。前面遇到的问题是,如何在顺利进入到配置模式以及配置参数后,进入到正常模式 。现在则直接是无法进入配置模式,这是比较奇怪的。前期解决问题的关键是在模式跳转中增加一个延时函数,从而规避外设本身的初始化缺陷。现在则需要通过调试,了解程序初始化时,内部寄存器的状态。
在调试过程,出现程序指针进入PS-CAN逻辑以及Memory显示为红色。为了更好定位程序逻辑错误,先注释PS-CAN外设初始化程序。
在观察CAN0寄存器状态时,发现memory数值状态异常。如上图所示,大量的数值为0,包含SR状态寄存器。通过SR寄存器数值打印,这个内存的内容确实存在问题。
//can0内存变量声明
p= (u32 *)0x43C00018;
//重置调试--内存打印
XCan_Reset(&Can0);
sleep(1);
xil_printf("can0 SR register11:%d\r\n",*p);
XCan_EnterMode(&Can0, XCAN_MODE_CONFIG);
xil_printf("can0 SR register11:%d\r\n",*p);
sleep(1);
XCan_EnterMode(&Can0, XCAN_MODE_NORMAL);
xil_printf("can0 SR register:%d\r\n",*p);
CAN IP文档中SR寄存器结构如下。不同的模式状态位会相应标记为1,但是如果所有状态位都为0,则说明CAN外设进入异常状态,猜想CAN外设没有时钟进入正常状态。此贴简要说明了一种状态寄存器全为0的情况,但是与我的情况不符。
此外,vitisBSP配置无法进入,猜想是特定底层硬件出现问题。以上问题只有通过三个方面来切入:1针对前面提到的引脚约束, 将引脚修改为G17和G18。2针对CAN外设本身问题,判断外设是否激活,比如外设时钟是否作用等。3开发平台本身问题,切换平台为2018vivado。只用添加CAN IP即可,定位问题。
外设时钟关系
回顾CAN CLK外设时钟输入和前期microblaze CAN外设测试,说明CAN IP确实需要一个外设时钟输入。此贴提醒我,ZYNQ的FCLK-CLK0本身就是提供给PL的时钟。因此直接点出FCLK-CLK1,生成新的一路时钟接入CAN就可,不用Clock wizard单独生成。甚至调整FCLK-CLK0的值为180,processor system reset模块的命名也相应变化。说明这种时钟配置是与PL的模块生成是对应的。
下图可知,microblaze通过clock wizard提供各种时钟。二年前,我一定尝试过引脚一路时钟线接入CAN-CLK。此贴也默认添加CAN-CLK。
结果,串口数据表明CAN外设重置后直接进入正常模式。为了判断是否FCLK时钟工作,再引出一路FCLK2,用逻辑分析仪测出频率。结果,逻辑分析仪无法获得信号。似乎表明这个引出的FCLK2是没有用的。
FCLK2无法检测
为了检测此时钟端口信号,选择ILA来分析。刚开始认为ILA只能在Vivado使用,而zynq需要SDK软件才能运行,担心这个操作不可行。小梅哥视频中指出,在SDK下载好程序之后,还是可以继续打开vivado的hardware manager。因此这种担忧是没有意义的。【在定位问题时,面对一个复杂系统,问题偏向于将所有能够观测的对象都检查一遍。】
中间出现问题,发现没有正常在vitis更新硬件。
ILA正常工作后,测得实际信号。问题是,这些信号没有时间刻度。此贴说明每个刻度实际就是ILA输入时钟的周期时,即图中的32-33-34等实际为20ns【50Mhz频率倒数】。图中数据间隔似乎为3个时间刻度,即60ns。但是按理来说,FCLK2为1MHz,周期应该为1us。这两者相差百来倍了。这似乎是说,FCLK2有时钟信号,但是数值存在问题。
由于这种情况的存在,不得不直接采用clock wizard来进入测试。主要想法是添加两路时钟输出信号,一路直接输出到PL GPIO,一路输出到ILA。它的时钟输入是FCLK_CLK0,预期时钟频率为50Mhz。这种操作的好处在于,能够通过硬件逻辑分析仪和软件逻辑分析仪的结果共同判断FCLK时钟是否工作。
令人困惑的是,实现阶段出现两个奇怪错误。错误1指出无法找到clk-wiz**,错误2指出ila的probe1没有连接通道。这两个编译错误都与事实不符,因为BD图中两者都是满足的。
其中,set-property问题是由于信号大小写造成的,vivado编译文件是大小写敏感的。在修改BD图中的信号大小写后,发现SDC自动生成的文件存在同步问题。要么没有删除过去的文件,要么没有刚修改的信号也没有同步。
出现时序问题,怀疑是资源太多,无法平衡。于是准备先按照调整芯片速度等级的方式修改。
芯片等级修改,出现错误。即使BD图没有问题,编译时也无法进入下去。
擅自修改芯片类型
设置中包含器件修改选项,修改这个参数后,就发生一系列连锁问题。为了彻底解决这个问题,又不想直接新搭建一个工程,于是不得不相着删除BD图中的ZYNQ。
为了减少其它模块对BD工作的影响,只留下串口和PL-GPIO模块。结果显示,程序运行正常。在配置系统的过程中,发现自己容易忽略DDR、时钟等环节。此外,在检查系统过程中,发现BSP设置在此时可以打开并修改参数。可是前面搭建好系统后,却无法达到这个目的。这个现象让人怀疑,BSP设置异常可能与系统编译问题等相关。
添加PL-CAN外设后,仍然出现之间的问题,即重置CAN外设后无法进入配置模式。由于GetMode函数是通过读取状态寄存器值来获得外设模式状态,且如果其它状态都不符合就会默认为回环模式,即这跟状态寄存器全为0的现象是一致的。
u8 XCan_GetMode(XCan *InstancePtr)
{
u32 Value;
Xil_AssertNonvoid(InstancePtr != NULL);
Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
Value = XCan_GetStatus(InstancePtr);
if (Value & XCAN_SR_CONFIG_MASK) { /* Configuration Mode */
return XCAN_MODE_CONFIG;
}
else if (Value & XCAN_SR_SLEEP_MASK) { /* Sleep Mode */
return XCAN_MODE_SLEEP;
}
else if (Value & XCAN_SR_NORMAL_MASK) { /* Normal Mode */
return XCAN_MODE_NORMAL;
}
else { /* If this line is reached, the device is in Loop Back Mode. */
return XCAN_MODE_LOOPBACK;
}
}
因此整个问题又回到CAN外设是否正常工作的猜想上,即CAN-CLK是否接收到FCLK2的时钟信号。
此贴指出自己的问题在于引脚的电容将时钟信号耦合掉了。但是我将时钟频率降低为1Mhz,是否也会受到小梅哥板子影响?于是不得不考虑ILA的使用。按照原先的思路,添加ILA和Clock Wizard,编译过后还是看到时序要求无法满足。
WHS时序要求无法满足
时序值有四个:WNS TNS WHS THS等,含义此文有解释。
此帖提到修改set false path,但是这个选项中还有两个对象。一个对象会出现错误,另一个对象会触发timing constrains页面,但是不知道如何操作。
此贴指出可以阅读文档【UG906】,并且对这个问题提出了细节的解决方案,但是对于WHS较小没有帮助。换言之, 期望一般化的解决方案,但是里面都是大量的细节化说明。可以看到,在一个BD工作中添加ILA和clock wizard会造成不小的时序问题。为了减少这个问题的复杂度,考虑先删除ILA的逻辑,直接采用Clock wizard来观察情况。毕竟,以上所有的操作目的都是为了判断FCLK2是否有时钟信号。
结果是,逻辑分析仪没有检测到clk-out任何输出。为了确保逻辑分析仪本身没有问题,修改GPIO引脚和输出,其也能观测到。由于FCLK0时钟是提供PL的时钟源,PL-GPIO能够正常工作,说明这个时钟是没有问题。换言之,无法做到通过逻辑分析仪的方法观测时钟输出
stack overflow 和CSDN求助
无计可施,于是不得不在外面平台上寻求帮助。发现这种求助也是可以的,算是一种新的体验。
CSDN上也发布了问题,但是回答基本是AI,没有参考性,我自己就有ChatGPT能用.不过这种回答方式倒是一种新的趋势.以后可以取消这种求助方式,发布找个做过相关内容的人,并且提供一定的酬劳就好.
四种选择
- 单独测试CAN IP核是否工作,尤其是通过example相关的工具[可行3]
- microbalze平台测试CAN IP功能,因为以前实际用过,觉得没有问题[可行2]
- 切换个平台,使用vivado2018看看效果,避免平台影响软核功能[可行1]
- 测试FCLK0接入clock wizard输出16Mhz频率,看看CAN IP的反应.[不可]
vivado2018版本系统
重新看看这个版本系统是否能够解决问题.搭建系统过程中,发现SDK的同步性比较差,BSP的更新时间总是出现问题.原来9-41更新的系统,但是一直处于上一个更新周期.[其中wrapper文件总是无法快速更新,需要点击Create HDL wrapper]
再者,修改zynq时钟配置时,只能在advanced clocking里面修改.即使修改内容,也无法完全同步,可以看到下图中FCLK1的要求时钟是50,而实际时钟为60Mhz.为了应对这种同步性问题,有必要在每次在SDK开发时,先看看hdf文件以及html文件是否已经更新的内容.
结果刚download进入比特流,开发板就没有反应,让人困惑.进入调试模式,发现程序停留在这个地方 b -16 ; addr=0xffffff20 .此贴提出在debug as时,需要测试相关参数,尤其是application选项中的CPU.
Application is not specified for ‘ps7_cortexa9_0’.
此外,在debug as的配置中,可以提到点出ps7-cortexa9-0时,左上角会出现错误符号.这个错误就是导致右下角无法点出debug选项的原因.此贴提出几个workspace的操作.
不过修改设置之后,又发生一些奇怪变化,比如run as和debug as中造成的选项都变为linux agent.这个选项往往无法正常工作,让人困惑.
将工程配置修改为原来内容后,仍然是这个问题.甚至出现右下角的no operation问题.为了不陷入这个问题之中,准备重新搭建一个新的工程.
搭建新的工程–interface overidden问题
搭建新的工程,发现有趣的点.本来在basic clocking无法直接修改FCLK值,但是新的工程中却可以.这说明vivado系统的稳定性不足,适当搭建新的系统有得解决一些稳定性问题.
此次为了谨慎,特定又看了编译报告,发现了大量的warning错误.其中the interface pin is being overridded by the user vivado让人在意,因为这个问题与CAN 外设直接相关.此贴指出了这个问题,但是没有说明修改办法,或者这个回答我没有看懂.总之,直接引出整个接口,再连接单个接口信号还是会报错.
不小心删除工程,人裂开.准备重新搭建一个新的工程,看看效果.想到直接在wrapper文件添加信号,接入特定的对象.从新的工程对象来看,突然多了一个can-phy-rx-0就可以看出vivado的同步更新机制非常烂.
由于overridden和同步问题的存在,打算通过wrapper来实现特定信号之间的连接.aasign语句可以帮助连接两个wire信号,即将右边时钟信号转递到左边的CAN-CLK中.
wire FCLK_CLK1_0;
wire FIXED_IO_ddr_vrn;
wire FIXED_IO_ddr_vrp;
wire [53:0]FIXED_IO_mio;
wire FIXED_IO_ps_clk;
wire FIXED_IO_ps_porb;
wire FIXED_IO_ps_srstb;
assign CAN_INTERFACE_0_clk = FCLK_CLK1_0;
can2018225 can2018225_i
(.CAN_INTERFACE_0_clk(CAN_INTERFACE_0_clk),
.CAN_INTERFACE_0_rx(CAN_INTERFACE_0_rx),
.CAN_INTERFACE_0_tx(CAN_INTERFACE_0_tx),
.DDR_addr(DDR_addr),
.DDR_ba(DDR_ba),
.DDR_cas_n(DDR_cas_n),
.DDR_ck_n(DDR_ck_n),
但是没有效果,出现如下错误.assign语句不行,又尝试连接module输入和输出的信号,但是仍然没有效果,具体是通过RTL图的信号判断出现的.这也提醒我,虽然vivado的同步问题比较大,但是可以在整个流程中通过多个环节判断是否修改得到同步,RTL层也是比较重要的一个层面.RTL原理图基本比较直观得反映一个信号的输入输出流.
can2018225 can2018225_i
(.CAN_INTERFACE_0_clk(FCLK_CLK1_0), 这里
.CAN_INTERFACE_0_rx(CAN_INTERFACE_0_rx),
.CAN_INTERFACE_0_tx(CAN_INTERFACE_0_tx),
.DDR_addr(DDR_addr),
.DDR_ba(DDR_ba),
.DDR_cas_n(DDR_cas_n),
.DDR_ck_n(DDR_ck_n),
.DDR_ck_p(DDR_ck_p),
.DDR_cke(DDR_cke),
.DDR_cs_n(DDR_cs_n),
.DDR_dm(DDR_dm),
.DDR_dq(DDR_dq),
.DDR_dqs_n(DDR_dqs_n),
.DDR_dqs_p(DDR_dqs_p),
.DDR_odt(DDR_odt),
.DDR_ras_n(DDR_ras_n),
.DDR_reset_n(DDR_reset_n),
.DDR_we_n(DDR_we_n),
.FCLK_CLK1_0(FCLK_CLK1_0),和这里
.FIXED_IO_ddr_vrn(FIXED_IO_ddr_vrn),
.FIXED_IO_ddr_vrp(FIXED_IO_ddr_vrp),
.FIXED_IO_mio(FIXED_IO_mio),
.FIXED_IO_ps_clk(FIXED_IO_ps_clk),
.FIXED_IO_ps_porb(FIXED_IO_ps_porb),
.FIXED_IO_ps_srstb(FIXED_IO_ps_srstb));
endmodule
发现这层的文件修改也没有效果,于是又打算在下图中的can2018225层进行修改,可是这个文件是可读的.为了修改这个文件,此贴提出了一种操作,但是我没有看到相关的选项.这些尝试让人困惑.
为了对问题有个整体的判断,预想把相关的错误都过一遍,了解一般的warning的情况是什么.
write bitstream显示的以下错误表明,似乎可能是如下错误导致的CAN 外设问题.因为corruption ~~red values when the set/reset is asserted会让人觉得与CAN外设重置下状态寄存器全为0的现象直接相关.
[DRC REQP-1839] RAMB36 async control check: The RAMB36E1 can2018225_i/can_0/U0/core_options.cantop_i/CANCORE_LOGIC_I/ol/memrx/genbram_v6.V6_U1 has an input control pin can2018225_i/can_0/U0/core_options.cantop_i/CANCORE_LOGIC_I/ol/memrx/genbram_v6.V6_U1/ADDRARDADDR[6] (net: can2018225_i/can_0/U0/core_options.cantop_i/CANCORE_LOGIC_I/ol/memrx/RX_BRAM_RADDR[0]) which is driven by a register (can2018225_i/can_0/U0/core_options.cantop_i/CANCORE_LOGIC_I/ol/rxf/RXF_READ_ADDR_LOW_reg[0]) that has an active asychronous set or reset. This may cause corruption of the memory contents and/or read values when the set/reset is asserted and is not analyzed by the default static timing analysis. It is suggested to eliminate the use of a set/reset to registers driving this RAMB pin or else use a synchronous reset in which the assertion of the reset is timed by default.
总之越看越混乱,让人不知道到底是哪里问题.不过当前的所有操作都是基于前面的四个选择判断,即在2018版本系统中尝试不同的可能性.后来,我调整了修改思路,注释掉了** //wire CAN_INTERFACE_0_clk;**这个信号.然后再查看原理图,发现RTL图中确实出现了相关信号的连接
果然,回到2018版本后,又能够看到正常的run as配置.
成功!开心!果然换个系统工程是可以的!
成功22-12
总结问题
- PS-CAN功能失效的主要原因是引脚约束和驱动稳定性,这两个方面都是过去没有注意以及重视的方面。与之相对,PL-CAN功能失效的原因是CAN-CLK信号引入。此信号需要在wrapper文件中修改,从而避免出现接口信号overridden问题。
- vivado和SDK等软件的同步问题比较大,需要在每个流程中引入检查机制,从而避免出现修改硬件参数但是没有同步的情况。在vivado中,如果修改BD图,wrapper文件、RTL文件、综合实现等都是需要检查的环节;在SDK中,xparameters.h以及html文件等也是检查的对象。其中wrappper文件是过去没有重视,现在觉得有必要关注的环节。换言之,vivado流程检查要求比较细致。
- 问题盲点:表面上看,许多问题没有解决办法,只是认识处于盲区。换个角度,或者换个方式,往往可以获得问题的新的思路。
3其它问题
编译顺序
如果出现编译错误,更改BD文件后,无法直接generate ouput product。因为这个操作本身是处于synthesis环节,report页面只有synthesis和implementation两个环节。如果出现编译错误,需要先点击左边的synthesis操作。这个操作无误后,才方便进行generate ouput product**操作,再进入生成比特流操作。此外GOP操作主要针对IP,修改引脚这种简单操作,report的时间值不一定改变。
快捷操作
在vitis编程时,往往需要在各个文件中跳跃以及查阅变量声明。过去,总是通过鼠标操作,效率低下。针对这个情况,减少鼠标使用,尽量使用快捷键,可以显著提升效率。尤其是那些比较常用的操作,例如F3打开声明或者定位到特定行。
资料引用
xilinx confluence平台提供新的的驱动文件内容。