原创 Verilog学习笔记3- 综合练习-基于SF-EP1V2的SMG接口设计- SPI发送模块

2010-5-14 20:05 2303 7 8 分类: FPGA/CPLD

SPI发送模块<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />


设计思路:


学习过单片机的朋友估计对SPI不陌生吧。想象一下74HC595 的传输方式相似与SPI传输方式,不同之点就是多了一个STCP(锁存信号)出来。



点击看大图



上面的示意图表示了SPI Module是一个主设备,而SMG Display是一个从设备,而且SPI Module8位数据的输入,串行时钟和串行数据输出,串行数据传出是一个字节。在示意图中还表示了,除了数据的传输是上升沿有效之外,SPI Module 还有 Start Signal 和 Done Signal. Start Signal 是用来启动 SPI Module ,而 Done Signal 是反馈给更上一层的“东西”。



Verilog设计思路:


 


1.module spi_module


2.(


3. RST, CLK, Send_Sig, Done_Sig, DI, SDO, SCL


4.);



5. input RST;


6. input CLK;


7. input [7:0]DI;


8. input Send_Sig;


9. output SDO;


10. output SCL;


11. output Done_Sig;


12.


13. /*****************************************/



14. wire isStart = Send_Sig;



15. /*****************************************/


16.


17. reg [9:0]Counter;


18.


19. always @ ( posedge CLK or negedge RST )


20.    if( !RST )


21.       Counter <= 10'd0;


22.    else if( Counter == 500 )


23.       Counter <= 10'd0;


24.    else if( isStart )


25.       Counter <= Counter + 1'd1;


26.    else


27.       Counter <= 10'd0;


28.


29. /*****************************************/



30. reg [4:0]j;


31.


32. always @ ( posedge CLK or negedge RST )


33.     if( !RST )


34.        j <= 5'd0;


35.   else if( Counter == 500 ) 


36.        j <= j + 1'd1;


37.    else if( j == 18 )


38.     j <= 5'd0;


39.   else if( !isStart )


40.     j <= 5'd0;



41. /*****************************************/



42. reg rSCL;


43.


44. always @ ( posedge CLK or negedge RST )


45.    if( !RST )


46.       rSCL <= 1'b1;


47.    else if( isStart )


48.       case ( j )


49.


50.          0:


51.       rSCL <= 1'b1;


52.


53.      1, 3, 5, 7,  9, 11, 13, 15:


54.         rSCL <= 1'b0;


 


55.      2, 4, 6, 8, 10, 12, 14, 16:


56.      rSCL <= 1'b1;


57.


58. endcase


59.


60. assign SCL = rSCL;


61.


62. /*****************************************/


63.


64. reg rDO;


65. reg isDone;


66. reg [7:0]rData;


67.


68. always @ ( posedge CLK or negedge RST )


69.    if( !RST )


70.       begin


71.          rDO <= 1'b0;


72.          rData <= 8'd0;


73.          isDone <= 1'b0;


74.       end


75.    else if( isStart )


76.       case ( j )


77.          8'd0: rData <= DI;


78.          8'd1: rDO <= rData[7]; 


79.          8'd3: rDO <= rData[6];


80.          8'd5: rDO <= rData[5];


81.          8'd7: rDO <= rData[4];


82.          8'd9: rDO <= rData[3];


83.          8'd11: rDO <= rData[2];


84.          8'd13: rDO <= rData[1];


85.          8'd15: rDO <= rData[0];


86.          8'd17: isDone <= 1'b1;


87.       endcase


88.    else


89.       begin


90.          rData <= 8'd0;


91.          rDO <= 1'b0;


92.          isDone <= 1'b0;


93.       end


94.


95. assign SDO = rDO;


96. assign Done_Sig = isDone;


97.


98. /*****************************************/



99.endmodule



 


(为了使代码更整洁,我不加注释了。Quartes II 对中文的支持不够友好... (╯▽╰)╭)


 




1. 1行到11行是一如既往熟悉的定义,自己看着明白吧。


 


2. 14行声明了Start_Sig 是 Send_Sig 同一个连接的。


 


3. 15行到29行定义了对SCL(串行时钟信号)的延迟。“Counter == 500” 中的 500是随


  意取的。目的就是为了延迟SCL的时钟周期。


 

  注意点:"Counter == 500" 应该更改为 “ Counter == 10 'd500”。


 


4. 30行到41行定义了j计数器。j计数器它就伟大了,它的工作就是记录SCL信号的时间周


   期。


 


5. 42行到60行这个就重要了。rSCL是用来驱动SCL的触发器。


   在等于 的时候,用来初始化rData数据寄存器(77行)。


   而j >= 1 的奇数,都是SCL信号半时钟周期的低电平(53)。凡是j1~15(奇数),都是


   用来设置rDO 寄存器。


 



在这里我们先暂停一下,回顾一下SPI一些概念:



SPI的传输都是从MSB开始。


SPI主设备为从设备写入数据设计到几个概念就是“设置”和“采样”。



设置:发生在低电平,主设备将输出数据更新。


采样:发生在高电平,从设备读取数据信号的值。



  


对于主设备的设计,我们只关系到“设置”,而j1~15(奇数)都是“设置”的动作。(78行到86行)


  j等于1的时候:将rDO设置为rData[7]的值。


  ......


  j等于15的时候:将rDO设置为rData[0]的值。


 


6. 55行与地53行的动作悄悄是相反,凡是j2~16(偶数),都是将SCL信号的半时钟周


   期设置为高电平。


 


7. j如此将SCL信号一上一下,就完成了8个有效的上升沿的SCL信号,传输8位的数据。


 


8. j等于17时使isDone寄存器置一(86行),为了就是反馈更高一层的“东西”,表示完


   成一个字节的数据传输( 96)


 


9. 最后就是isStart 这个wire型数据,它的定义是等价于 Start_Sig ( 14)的。当isStart为高电


   平的时候,24行)Counter计数器开始奇数,rSCL和 rDO寄存器才开始工作(47行,75


   行)。相反的当isStart为低电平,rSCLrDO寄存器就不工作,而且j计数器也一直清零


  (39行),为了就是双层保障。


 


10. 再谈谈初始化的故。我们知道SPI的时钟信号为上升沿有效,所以rSCL寄存器都必须初始


    化为高电平46行)。有一个现象很微妙,当j奇数到18的时候(37)rSCL的值会是高


    电平。啊哈!除此之外rData rDO的初始化都是0值(71~72行),而且一旦它们使用


    完后都必须恢复为0值(90~91行)。





 


   (故事还没有结束O(_)O)


 


11. isDone寄存器,是用于驱动Done_Sig96行)。它的地位很重要,因为它是唯一联系上


    一层“东西”的信号。isDone寄存器初始化值为073行),而j计数器为17的时候被设


   置为高电平(86行),而使用过后isDone寄存器恢复为0值(92行)。 



 


仿真:


Testbench代码:



1.`timescale 1 ns/ 1 ns


2.module spi_module_vlg_tst();


3.


4. reg CLK;


5. reg [7:0] DI;


6. reg RST;


7. reg Send_Sig;


8.   


9. wire SCL;


10. wire SDO;


11. wire Done_Sig;


12.                    


13. spi_module i1 


14. (


15.    .CLK(CLK), .DI(DI), .RST(RST), .SCL(SCL), .SDO(SDO),


16.    .Send_Sig(Send_Sig), .Done_Sig( Done_Sig )


17. );


18.


19. initial


20. begin RST = 0; #100; RST = 1; end


21.


22. initial 


23. begin CLK = 0;  forever #10 CLK = ~CLK; end


24.


25. initial


26. begin DI = 8'h8e; Send_Sig = 1; end


27.                                     


28.endmodule






 


 


Modelsim仿真载图:


 

点击看大图


 

 


问题和答案:


 

1. Modelsim仿真的时候,当传输一个字节完毕后,为什么Done_Sig 一直居高不下?


答:这是因为isStart的缘故,在Verilog 代码中 39行,87行到93行中,isDone寄存器被置零是


   发生在isStart  == 0 的条件下,而Testbench中,Send_Sig 由始至终都是置一的关系。多


   以才会产生以上的现象。



 


2. 继问题1, 这样做有什么好处?


答:你要知道Send_SigDone_Sig 是给予上一层作于通行使用,好处就是简化了底层模块


    的设计。又或者说,底层的模块和上一层的模块之间“你做你的,我做我的”。



 


3. Counter == 500”的特别意义?


答:这也没什么特别意义,为了就是降低SCL的频率。SCL的频率必须小于源时钟频率。


 


总结:


 

这是最底层的模块了,所以在某种程度上是最重要的。在结论上是没有什么话好所,或许还有很多地方我没有详细说明清楚,故都是一些小细节,自己看着办吧。


 


源码下载:


https://static.assets-stash.eet-china.com/album/old-resources/2010/5/14/5e84a716-5648-4932-9ef4-9ba4f3b06b1d.rar

PARTNER CONTENT

文章评论1条评论)

登录后参与讨论

用户410992 2011-10-26 18:29

旧日志都看不了图片了呀,这个一定经典,希望博主有空重贴一下。谢谢!

用户1373959 2010-5-18 21:27

nice

gujunyi1_407560534 2010-4-28 21:05

今天去ADI面试问到这方面的题了,竟然忘了,真是郁闷至极,看来还是要多复习!
相关推荐阅读
用户1609127 2011-10-22 18:26
Verilog的私私细语 - 时钟化和信号的长度
目录 第2章 时钟化和信号的长度 2.01 一个时钟一块数据的概念 2.02 信号时钟化 2.03 深入了解模块的沟通 2.04 电平检测模块的整合(即时事件在时序上的不和谐)      实验八:电...
用户1609127 2011-09-08 12:47
瞎搞Time Quest 和无责任的笔记 第二章
最近整合篇的第二章的构思和灵感都累积不少了,应该是时候开工了。恰好手头上还有一本笔记还没有写完,就是这本瞎搞TimeQuest的第二章。目录笔者也懒得贴了,看过第一章的同学多少也会猜到第二章的内容是什...
用户1609127 2011-08-29 18:21
瞎搞Time Quest 和无责任的笔记 第一章
哎呀 ... 潜水了都有一段时间了,这是最近研究的成果和目标。 话说TimeQuest这个东西真的很搞怪呀,做得笔者不得不从其他的方向去研究它。 好了还是切入正题,TimeQuest用作静态时序的工具...
用户1609127 2011-07-06 17:43
Verilog的私私细语 - 整合的概念
目录         02  第1章  整合的概念          1.01  源码上的整合                   实验一:字面上的整合          1.02  时钟和步骤的定...
用户1609127 2011-06-22 10:18
VerilogHDL那些事儿 - 建模篇v4 + 时序篇v1
VerilogHDL那些事儿 - 建模篇v4 ====== v4 ====== 主要是修改了大量用法上的BUG和极限的精简内容 https://docs.google.com/leaf?id=0B...
用户1609127 2011-06-10 13:19
Verilog HDL的礼物 - Verilog HDL扫盲文
目录 02第0章 Verilog HDL语言扫盲文 030.01 各种的HDL语言 030.02 HDL语言的层次 03 0.03 RTL级和组合逻辑级 040.04 Verilog HDL语言真的那...
EE直播间
更多
我要评论
1
7
关闭 站长推荐上一条 /3 下一条