FPGA基础回顾:从内部结构到开发流程
各位同学,咱们开始第一节课。说实话,每次带新人入门FPGA,我都会先问一个问题:你真的了解FPGA内部长什么样吗?很多人会用过,但说不清LUT和FF的区别。今天咱们就把这些基础夯实。
FPGA内部结构:四大金刚
FPGA说白了就是一块可以无限次重新配置的芯片。它不像ASIC那样出厂就定死了功能。我当年第一次接触FPGA时,觉得这东西简直像魔法——逻辑功能居然能像软件一样改来改去。
FPGA内部主要由四种资源构成,我习惯叫它们「四大金刚」:
| 资源类型 | 全称 | 核心作用 | 我的经验 |
|---|---|---|---|
| LUT | 查找表 | 实现组合逻辑 | 6输入LUT最常见,别浪费 |
| FF | 触发器 | 存储状态、实现时序 | 每个LUT后面基本都跟着FF |
| BRAM | 块RAM | 存储数据、FIFO、ROM | 比分布式RAM省面积 |
| DSP | 数字信号处理单元 | 乘法、累加、MAC运算 | 运动控制中算PID全靠它 |
重点记忆:LUT负责「算」,FF负责「存」,BRAM负责「大容量存」,DSP负责「高速算」。运动控制中,DSP和BRAM是核心。
我在做高速点位运动控制项目时,遇到过一个问题:用LUT搭乘法器,结果资源爆了。后来改用DSP48E1,不仅省了70%的LUT,速度还翻了一倍。所以啊,选对资源比写对代码更重要。
Verilog基础语法:够用就行
很多初学者喜欢把Verilog当C语言写。千万别!Verilog是描述硬件的,不是写软件的。我见过最离谱的代码,有人用for循环嵌套了8层,综合出来一个超级大的状态机——跑都跑不动。
咱们做运动控制,常用的语法其实就这几类:
- assign:连续赋值,描述组合逻辑。比如
assign led = btn; - always @(posedge clk):时序逻辑,描述寄存器。比如计数器、状态机。
- if-else / case:条件判断,用在always块里。
- reg / wire:数据类型。reg不一定生成寄存器,wire不一定只是连线——这个坑我踩过。
小技巧:写Verilog时,先想清楚你要生成什么电路,再动笔。我习惯在纸上画个框图,标清楚哪些是组合逻辑、哪些是时序逻辑。这样写出来的代码,综合结果基本和预期一致。
举个例子,一个简单的计数器:
module counter (
input clk,
input rst_n,
output reg [7:0] cnt
);
always @(posedge clk or negedge rst_n) begin
if (!rst_n)
cnt <= 8'd0;
else
cnt <= cnt + 1'b1;
end
endmodule
这段代码综合出来就是一个8位计数器,带异步复位。嗯,这里要注意:复位最好用异步复位、同步释放,不然容易出时序问题。
开发流程:仿真-综合-实现
FPGA开发流程,说白了就是三步走:仿真验证对不对,综合看看用多少资源,实现检查能不能跑起来。
这张图我画了很多次了。你想想看,仿真没通过就直接综合,等于盖楼不打地基。我曾经有个项目,仿真跑了一万次都OK,结果上板子就死机。最后发现是仿真时没加时序约束,综合后路径延迟超标了。
避坑指南:我曾经在综合后直接跳过了「实现」步骤,想省时间。结果bitstream下载后,FPGA完全没反应。后来发现布局布线时,关键路径的时序违例了。记住:实现这一步不能省,时序报告必须看。
常用IP核介绍:别重复造轮子
FPGA厂商提供了大量IP核,说白了就是别人写好的、经过验证的模块。咱们做运动控制,最常用的IP核有这些:
- FIFO Generator:异步FIFO,跨时钟域传输数据必备。我习惯用独立时钟的FIFO,读写时钟不同步时特别好用。
- Block Memory Generator:生成BRAM,可以配置成单口、双口、ROM。存运动轨迹数据时,我一般用双口RAM,一边写一边读。
- DSP48 Macro:直接调用DSP单元做乘加运算。算PID控制量时,一个时钟周期就能完成乘法+累加。
- Clocking Wizard:时钟管理,生成不同频率的时钟。注意:时钟抖动会影响运动控制的精度,尽量用PLL输出。
我的习惯:能用IP核就别自己写。比如FIFO,自己写很容易漏掉空满标志的时序。但要注意,IP核的配置要仔细看手册,特别是延迟参数和复位方式。我见过有人把FIFO的复位配成了异步,结果跨时钟域时数据丢了。
好了,这一章的内容就这些。记住:FPGA基础不牢,后面做运动控制会非常痛苦。下一章咱们开始讲高速点位运动的核心——加减速算法。到时候会用到今天讲的DSP和BRAM,别掉队。
公众号:蓝海资料掘金营,微信deep3321