在K7系列FPGA的Master SPI配置模式下,FPGA通过CCLK(配置时钟)引脚向外部FLASH芯片提供时钟信号。这个时钟信号在配置阶段至关重要,它负责同步FPGA从FLASH中读取配置数据的整个过程。然而在实际项目中,很多开发者都会遇到一个棘手的问题:当FPGA完成初始配置后,CCLK信号会突然消失。
这个问题带来的直接影响就是——我们无法继续通过CCLK控制FLASH芯片。想象一下,你正准备通过远程接口向FLASH写入新的.bin文件,却发现时钟信号不见了,这就像准备开车时发现车钥匙不见了一样尴尬。我在实际项目中就遇到过这种情况,当时调试了整整两天才找到问题根源。
更具体地说,在Master SPI模式下,CCLK信号默认只在配置阶段有效。配置完成后,FPGA会释放对CCLK的控制权。这时候如果我们想对FLASH进行读写操作(比如远程更新),就必须重新获得对CCLK的控制。这就是为什么需要"接管"CCLK的根本原因。
STARTUPE2是Xilinx 7系列FPGA提供的一个特殊原语,它就像FPGA内部的一个"后门",让我们能够访问一些通常无法直接控制的信号。这个原语最强大的功能之一就是允许我们在配置完成后接管CCLK信号的控制权。
原语中最重要的几个信号包括:
我在多个项目中使用过这个原语,发现它的行为与官方文档描述有些细微差别。比如文档说CFGCLK在Master模式下会持续存在,但实测发现它只在配置阶段有效,之后就会变成高电平。这种细节差异往往就是项目中的"坑",需要特别注意。
时钟切换过程有三个关键时序点:
在实际调试中,我发现过渡阶段特别容易出问题。有一次项目就因为没处理好这个过渡,导致FLASH操作失败。后来通过ILA抓取信号才发现,在切换过程中出现了短暂的时钟不稳定现象。解决方法是确保用户时钟在切换前就已经稳定运行。
在开始编码前,首先要确保硬件连接正确。根据我的经验,很多问题其实都出在硬件上。需要重点检查:
我曾经遇到过一个案例,硬件工程师把CCLK接到了FLASH的CS引脚,结果自然是怎么调都不工作。这种低级错误往往最容易被忽视。
下面是经过实际项目验证的STARTUPE2实例化代码:
verilog复制STARTUPE2 #(
.PROG_USR("FALSE"), // 禁用编程接口
.SIM_CCLK_FREQ(0.0) // 仿真时钟频率
) STARTUPE2_inst (
.CFGCLK(), // 可以不连接
.CFGMCLK(), // 可以不连接
.EOS(eos), // 连接配置完成指示信号
.PREQ(),
.CLK(0),
.GSR(0),
.GTS(0), // 必须置0才能控制CCLK
.KEYCLEARB(1),
.PACK(1),
.USRCCLKO(usrcclk), // 用户自定义时钟
.USRCCLKTS(0), // 必须置0才能输出用户时钟
.USRDONEO(1), // 控制DONE引脚
.USRDONETS(0)
);
这个配置经过多次项目验证,稳定可靠。其中GTS和USRCCLKTS必须设为0,这是很多新手容易忽略的地方。
用户时钟的生成需要特别注意相位和频率。我推荐使用FPGA内部的MMCM或PLL来生成稳定的时钟信号。下面是一个典型的时钟生成模块:
verilog复制// 生成25MHz的用户时钟
clk_wiz_0 clk_gen (
.clk_out1(usrcclk), // 25MHz输出
.reset(1'b0),
.locked(locked),
.clk_in1(sys_clk) // 系统输入时钟
);
时钟切换的最佳时机是在EOS信号变高后的几个周期。这里分享一个实用的切换策略:
这种保守的策略虽然会引入少量延迟,但能确保时钟切换的稳定性。在高速系统中,可以根据实际情况调整等待周期数。
调试这类问题时,ILA(集成逻辑分析仪)是不可或缺的工具。我通常会抓取以下信号:
有一次调试时,我发现FLASH没有响应,通过ILA发现CS信号在操作期间有毛刺。最终发现是PCB布局问题导致信号完整性不佳。这个案例说明,FPGA设计不能只关注代码,硬件因素同样重要。
问题1:时钟切换后FLASH无响应
可能原因:
解决方案:
问题2:时钟切换过程中FPGA配置丢失
可能原因:
解决方案:
问题3:远程更新后新程序不生效
可能原因:
解决方案:
在实际项目中,我建议为远程更新功能设计完善的反馈机制。比如在写入FLASH后,增加读取验证步骤;或者在FPGA中实现心跳包机制,让远程端能够确认更新状态。这些额外的防护措施虽然会增加一些开发工作量,但能显著提高系统的可靠性。