硅农预备役2024
这个问题确实很经典,SPI Master看着简单,但想写稳健了不容易。核心就两点:一是SCLK生成和系统时钟的跨时钟域处理,二是数据对齐要干净。
我的做法是,绝对不用分频出来的SCLK去驱动FPGA内部的逻辑。所有逻辑都在主时钟域(比如clk_100m)里完成,用计数器生成SCLK的使能信号。比如分频系数是N,那我就计数到N/2和N-1时产生两个使能脉冲,一个用于SCLK翻转,一个用于数据准备或采样。这样SCLK本质上只是一个根据使能信号翻转的输出寄存器,所有逻辑都在单一时钟域,彻底避免异步问题。
对于CPOL和CPHA,其实就是调整数据输出和采样相对于SCLK边沿的位置。我会定义几个参数化的偏移值,在状态机里(状态机其实不冗长,几个状态就够)根据计数器的值和这些偏移值,在精确的时钟周期去操作MOSI和MISO的采样寄存器。
关键点:输出信号(MOSI, SCLK)都用寄存器直接驱动,不要有任何组合逻辑。这样就能从根源上消除毛刺。代码结构上,一个always块处理计数器和状态机,另一个always块根据当前状态和计数器值,在时钟上升沿更新输出寄存器。这样写出来既清晰又可靠。
