前言:
鉴于一般ADI的AD、DA、时钟类的芯片应用的比较广泛,正好手上的一块板子上有三片ADI的芯片,都是SPI的接口。就想到设计一个比较通用的SPI Master,希望可以做到基本通用。
一、SPI的接口时序如下(摘自AD9517-3 datasheet)
1、 前16bit为Instruction Header,就是控制读/写、地址、长度(读/写)的。
2、后面跟的是读/写的数据。
说明:sdio是双向的,一般默认的就是双向的,所以sdo引脚可以不用。
二、设计SPI时序
SPI的时序很简单,就是一个时钟对应一个数据。通常SCLK的最高频率不超过25MHz。
对于低速的时序,我们可以在2倍或者4倍的系统下来控制输出的时序。如下图,clk是50MHz,输出的SCLK是25Mhz。这是一种时序控制的思想。
上图中,我们用到了一个计数器cnt,然后按照cnt的值来控制SCLK和高和低,以及SDIO上的数据。
部分verilog代码如下:
Case(cnt)
0: begin sclk <= 1; csb <= 0; cnt <= cnt + 1'b1; end(将csb信号拉低,对应图中cnt=1)
1: begin sclk <= 0; sdio <= instr_header[15]; cnt <= cnt + 1'b1; end(低电平送数据,保持一个周期,对应图中cnt=2,3)
2: begin sclk <= 1; sdio <= instr_header[15]; cnt <= cnt + 1'b1; end
3: begin sclk <= 0; sdio <= instr_header[14]; cnt <= cnt + 1'b1; end
4: begin sclk <= 1; sdio <= instr_header[14]; cnt <= cnt + 1'b1; end
5: begin sclk <= 0; sdio <= instr_header[13]; cnt <= cnt + 1'b1; end
6: begin sclk <= 1; sdio <= instr_header[13]; cnt <= cnt + 1'b1; end
7: begin sclk <= 0; sdio <= instr_header[12]; cnt <= cnt + 1'b1; end
8: begin sclk <= 1; sdio <= instr_header[12]; cnt <= cnt + 1'b1; end
……..
这样,一个完整的SPI总线“写操作”时序设计出来应该是这样子:
注:图中是8位的地址+8位的数据,所以SCLK共16个周期。如果是16位地址,应该共24个周期。
三、双向IO的控制
由于默认SDIO是双向的,所以这里再提一下双向IO的控制。
一般双向IO是这样定义的,先在模块中如下申明:
module spi_master(
…
inout sdio,
…
);
然后在程序中:
reg sdio_en = 0;
wire sdi;
reg sdo = 0;
assign sdio = (sdio_en) ? sdo : 1'bZ;
assign sdi = sdio;
sdio_en是使能双向端口的,sdio_en为1时输出,为0时输入。
sdo作为输出寄存器,sdi作为输入。
在程序中要输出的时候,要先把sdio_en置为1,同时将数据放入sdo寄存器。输入的时候,先将sdio_en置0,再从sdi上取数据。
未完,敬请期待。。。