logo资料库

SPI协议的Verilog_实现.pdf

第1页 / 共10页
第2页 / 共10页
第3页 / 共10页
第4页 / 共10页
第5页 / 共10页
第6页 / 共10页
第7页 / 共10页
第8页 / 共10页
资料共10页,剩余部分请下载后查看
SPISPISPISPI 通信 � 原理 Spi接口是一种外围串行接口,主要由四根线组成:SDI(数据输入),SDO(数据输出), SCK(时钟),CS(片选)。 (1)SDO主机输出/ 从机输入。 (2)SDI主机输入/ 从机输出 。 (3)SCK – 时钟信号,由主设备产生。 (4)CS – 从设备使能信号,由主设备控制。 在一个基于SPI的设备中,至少有一个主控设备。与普通的串行通讯不同,普通的串行 通讯一次连续传送至少8位数据,而SPI允许数据一位一位的传送,甚至允许暂停,因为SPI 的数据输入和输出线独立,所以允许同时完成数据的输入和输出。在点对点的通信中, SPI 接口不需要进行寻址操作,且为全双工通信,工作简单高效。然而SPI接口也有缺点:没有 指定的流控制,没有应答机制确认是否接收到数据。 SPI通讯是通过数据交换完成的。在主机提供的时钟脉冲SCK下,SDI,SDO完成数据传 输。数据输出通过 SDO线,在SCK时钟上升沿或下降沿时改变,在紧接着的下降沿或上升 沿被从机读取,完成一位数据传输。输入情况同理。因此,在至少8次时钟信号的改变(上 沿和下沿为一次),可以完成8位数据的传输。 SPI总线有四种工作方式可以选择,根据外设工作要求,其输出串行同步时钟极性和相 位可以进行配置,时钟极性(CPOL)对传输协议没有重大的影响。如果 CPOL=0,串行同 步时钟的空闲状态为低电平;如果CPOL=1,串行同步时钟的空闲状态为高电平。时钟相位 (CPHA)能够配置用于选择两种不同的传输协议之一进行数据传输。如果CPHA=0,在串 行同步时钟的第一个跳变沿(上升或下降)数据被采样;如果CPHA=1,在串行同步时钟的 第二个跳变沿(上升或下降)数据被采样。SPI主\从设备时钟相位和极性应该一致。本次实 践采用第一种工作方式,具体情况将在之后的仿真波形中分析介绍。 � SPI—MOSI代码 (见附录) � 仿真及分析 1
数据发送: 图 1、数据发送 如图 1 所示,传输时钟 SCK 由 busy 信号控制,在 busy 信号有效期间产生八个周期的 主从设备交换数据时钟信号,在每一个周期内完成一位数据的发送和接收。测试中,待发送 数据为 10101001。经过数据线 SDO 发送后,在 SCK 的第一个跳边沿进行数据采样,在每 个 sck 下降沿完成一位数据的交换。由上图可知,在一个 busy 信号有效期内,sdo 发送的数 据为 10101001,与待发送数据一致。 而 busy 信号的产生,与片选信号 cs、写信号 wr 和地址信号 addr 有关。在 busy 信号为 低电平时,只有片选有效,且当前为写状态,才能由 addr 决定是否使能 busy 信号,开始数 据发送。而在 busy 信号使能时,只有片选有效,才能进行数据发送,当片选无效则暂停下 一位数据发送。当然,每发送完 8bit 数据,busy 信号会自动关闭使能状态,等待命令…… 2
数据接收: 图 2、数据接收 数据接收与数据发送使用同一个时钟信号 SCK 和片选信号 CS。其工作情况大致如下:在 每个 SCK 时钟的上升沿对接收数据进行采样。由图 2 可知,在一个 busy 信号使能阶段,采 到的数据为 10110111,即十进制 183。在 busy 信号关闭使能后,只有片选使能且处于允许 读状态,接收到的数据才会被存储,否则丢弃。 Chipscope 数据抓取 DataPort[5]-DataPort[0] : busy、sdo、addr、cs、wr、rd DataPort[21]-DataPort[14] :待发送 8bit 数据 DataPort[13]-DataPort[6] : 接收的 8bit 数据 3
� 总结 完成时间:12.4--12.12 前期:该阶段主要是熟悉 SPI 工作原理,进一步掌握和认识 SPI 通信协议。Chipscore 的使 用之前未曾接触,在这一阶段,我先通过简单编程结合开发板抓取数据进行分析达到 对其的基本掌握。 中期:在熟悉 SPI 的工作原理之后,开始尝试编写代码。写了两三次代码,效果均不理想, 很多问题在编写代码的时候没有考虑清楚,导致到了仿真阶段结果与预期有所差距, 且代码冗长复杂。参考了一些资料,效果也不是很好,特别是数据传输暂停部分,很 多都省略了。不过借鉴别人写的代码也让我收获了不少编写的经验,有些情况下,运 用不同的逻辑思维可以让代码更简洁、更具有健壮性。当然期间也遇到了一些自己无 法解决的问题,非常感谢福星学长耐心的指导,让我学到了不少知识和经验。 后期:该阶段主要是对代码进行再修改、波形仿真以及抓数据调试。 问题及分析: 小问题遇到不少,不过大多都通过 error 的提示,或者上网搜索,找到了问题的原因, 并予以解决。也有软件上的原因,比如:第一次装 ISE 的时候可能没有安装好,上板调试的 时候,cable 不能识别。经过测试分析发现 ISE 里的 drive 没有装上。考虑到这样一个问题的 出现可能还会附带有一些软件上的漏洞,重装了一遍 ISE,问题解决。 使用 chipscope 的时候,芯片配置不对连接失败,查阅该电路板的资料,重新配置,问 题解决。在 chipscope 里面有些触发信号找不到,经分析是被优化了,通过简单修改代码避 免它被优化后,问题解决。运行 chipscope 后发现 waveform 始终没反应,经过一番分析,认 为时钟线的引脚配置有问题,重换一个时钟信号线 I/O 引脚,问题解决。解决后发现抓取的 波形没有明显的高低跳变,经分析可能是参考时钟选取不对,重选后问题解决。 附录: 流程图 4
代码: ////////////////////////////////////////////////////////////////////////////////// module spi_mosi(addr,rd,wr,cs,clk,sdi,sdo,sck,spi_bps,data); input wire addr; input wire rd; input wire wr; input wire cs; input wire clk; output[size:1] data; input sdi; inout sdo; inout sck; inout spi_bps; reg[size:1] out_data=0; reg sck_buffer = 0; reg sdo_buffer = 0; reg busy = 0; reg [size:1] in_buffer = 0; reg [size:1] out_buffer = 0; reg [6:0] reg [7:0] reg reg[12:0] reg[size:1] in_data=8'b10101001; spi_bps_reg=0; clk_cnt; count = 0; clkcount = 0; 5
parameter size=8; parameter parameter para=6400; para_half=3200; assign data=out_data; assign sck = sck_buffer; assign sdo = sdo_buffer; assign spi_bps=spi_bps_reg; ////////////////////////////////////////////////////////////////////////////////// ////////////// ///////////// //////////// //////////////////////////////////////////////////////////////////////////////// always@(posedge clk) begin 分频模块 ////////////////////////////////////// ////////////////////////////////////// ////////////////////////////////////// if((clk_cnt>=0)&&(clk_cnt=para_half)&&(clk_cnt
begin case(addr) 1'b0: begin in_buffer = in_data; busy = 1'b1; end //待发数据存入缓存区, 1'b1: begin busy = 1'b0;end endcase end 转入工作状态 end else begin if(cs) begin clkcount = clkcount + 1'b1; if(clkcount >= 8'b10) begin clkcount = 0; if((count % 2) == 0) //控制 SCK 周期 // 发送数据 begin sdo_buffer = in_buffer[8]; in_buffer = in_buffer << 1; end if(count > 0 && count < 17) //在未达到 8 个 sck 周期时,每次触发 条件满足,信号反转一次 begin sck_buffer = ~sck_buffer; end count = count + 1'b1; if(count > 17) begin count = 0; busy = 1'b0; end end end end end always@(posedge sck_buffer) begin out_buffer = out_buffer << 1; out_buffer[1] = sdi; end endmodule //接收从机发送过来的数据 7
触发信号控制部分: module spi_mem(spi_bps,rd,wr,cs,sdi,addr); input output output output output output spi_bps; rd; wr; cs; sdi; addr; reg reg reg reg reg rd_reg; wr_reg; cs_reg; sdi_reg; addr_reg; assign rd=rd_reg; assign wr=wr_reg; assign cs=cs_reg; assign sdi=sdi_reg; assign addr=addr_reg; parameter size=8; cnt_set; reg[size:1] reg[size:1] cnt_sdi; always@(posedge spi_bps) begin if(cnt_set<8'd250) begin cnt_set<=cnt_set+1'b1;end else begin cnt_set<=8'd0;end end always@(posedge spi_bps) begin if(cnt_sdi<8'd9) begin cnt_sdi<=cnt_sdi+1'b1;end else begin cnt_sdi<=8'd0;end end always@(posedge spi_bps) begin if(cnt_sdi<8'd5) begin sdi_reg<=1'b1;end 8
分享到:
收藏