SPI 发送模块
在这里,我们要在主机上建立,一个向从机写入数据的SPI 发送模块,首先我们先从C语言上了解几个主机在SPI 写操作上容易被疏忽的小细节:我们知道SPI 设备在传输都有一个规则,SCL 时钟信号在“上升沿”的时候是“锁存数据”,SCL 时钟信号在“下降沿”是“设置数据”。在这里我们SPI 主机(FPGA),写操作要干的工作就是在“拉高SCL 时钟信号之前”设置数据(移位数据),设置数据之后,再拉高时钟信号。但是我们常常会忽略了一些具体的细节。

上面有两个主机的SPI_Send 函数(写函数),左边的写法是最常用,但是也是最容易忽略小细节。相比右边的写法比较谨慎,在最低的程度上符合一写小细节。

再来,我们继续引用ST7565P 芯片的写入时序图,分析并且区分上边的两个写法。关于SCL 信号在空闲的时候总是处于高电平。当主机开始向从机写入数据,主机会先拉低CS 信号,再拉低SCL 信号,然后“设置”数据,亦即主机(FPGA)更新SI 的数据(主机数据移位操作),最后再拉高SCL 信号。同一时间,从机会因为SCL 的上升沿变化,从机(液晶资源)“锁存”(从机读取数据操作)SI 上的数据。很明显左边的写法没有符合这些细节,然而右边的写法却符合这些细节。无论是左边的写法还是右边的写法,都忽略了一个致命的细节,两种写法都无法确定SPI 时钟信号的时钟频率。
module spi_write_module
(
CLK,RSTn,Start_Sig,SPI_Data,Done_Sig,SPI_Out
);
input CLK;
input RSTn;
input Start_Sig;
output [9:0] SPI_Data;
output Done_Sig;
output [3:0]SPI_Out;//[3]CS,[2]A0 [1]CLK [0]D0
parameter T0P5US=4'd9;//0.5us
always@(posedge CLK or negedge RSTn)
if(!RSTn)
Count1<=4'd0;
else if(Count1==T0P5US)
Count1<4'd0;
else if(Start_Sig)
Count1<=Count1+1'b1;
else
Count1<=4'd0;
reg[4:0]i;
reg rCLK;
reg rDO;
reg isDone;
always@(posedge CLK or negedge RSTn)
if(!RSTn)
begin
i<=5'd0;
rCLK<=1'b1;
rDO<=1'b0;
isDone<=1'b0;
end
else if(Start_Sig)
case(i)
5'd0,5'd2,5'd4,5'd6,5'd8,5'd10,5'd12,5'd14:
if(Count1==T0P5US)begin rCLK<=1'b0;rDO<=SPI_Data[7-(i>>1)];i<=1+1'b1;end
5'd1,5'd3,5'd5,5'd7,5'd9,5'd11,5'd13,5'd15:
if(Count==T0P5US)begin rCLK<=1'b1;i<=i+1'b1;end
5'd16:
begin isDone<=1'b1;i<=i+1'b1;end
5'd17:
begin isDone<=1'b0;i<=5'd0;end
endcase
assign Done_Sig=isDone;
assign SPI_Out={SPI_Data[9],SPI_Data[8],rCLK,rDO};
endmodule
SCL 的时钟频率定义为1Mhz , 也就是说周期时间是1us ,半周期就是0.5us 。如果以20Mhz 来定时,那么计数的结果是10。在19 行定义了0.5us 的常量,第23~33 行是0.5us的定时器。但是比较不同的是,这个定时器平时不工作,当Start_Sig 拉高的时候才开始计数(第30 行)。第37~65 行是spi_write_module.v 的核心功能。i 寄存器表示操作步骤,rCLK 寄存器表示SCL 然而rDO 寄存器表示SI 。如同前面所述那样,SCL 时钟信号,处于空闲状态
时是出于高电平,所以rCLK 复位值是逻辑1(46 行)。
SPI_Data : 第9 位表示CS,第8 位表示A0,第7 .. 0 位表示一字节数据。
SPI_Out : 第3 位表示CS,第2 位表示A0,第1 位表示SCL,第0 位表示SI。
当Start_Sig 拉高的同时,定时器开始计数(30 行),该模块也开始执行(50 行)。
当第一个0.5us 定时产生的时候(54 行),也就是第一个时钟的前半周期,亦即下降沿,
rCLK 设置为逻辑0。根据SPI 传输的规则,下降沿的时候主机设置数据,rDO 赋予SPI_Data 信号的第7 位(SPI 传输是从最高位开始,最低位结束),最后i 递增以示下一个步骤。当i 等于1 的时候并且定时产生(56 行),这表示第一个时钟的后半周期,亦即上升沿,rCLK 设置为逻辑1。在SPI 传输的规则中上升沿的时候,从机锁存数据。然后i 递增以示下一个步骤。
上述的步骤会一直重复到第八次,直到一字节的数据发送完毕。最后会产生一个完成信号(59~63 行)。
这里有一个表达式需要说明一下:
i >> 1 : 表示i / 2。右移操作也代表了“i / j2”(j 是右移次数)。
假设8 >> 2 ,亦即8 / 22 等于2。8 >> 3, 亦即8 / 23 等于1。
最后还有一个重点就是SPI_Out 的驱动(70 行)。在上面我已经重复过SPI_Out 是占4 位的输出。而且每一个位都有意义。
SPI_Out 第3 位:表示了CS,所以直接由SPI_Data 的第9 位驱动。
SPI_Out 第2 位:表示了A0,同样也是直接由SPI_Data 的第8 位驱动。
SPI_Out 第1 位:表示了SCL,以寄存器rCLK 来驱动。
SPI_Out 第0 位:表示了SI,以寄存器rDO 来驱动。
这样的目的是简化连线的复杂度。我们知道Verilog HDL 语言的位操作是很强大。懂得善用,会对建模提到很大的帮助。

利用SPI驱动12864液晶相关推荐

  1. 联盛德 HLK-W806 (十一): 软件SPI和硬件SPI驱动ST7567液晶LCD

    目录 联盛德 HLK-W806 (一): Ubuntu20.04下的开发环境配置, 编译和烧录说明 联盛德 HLK-W806 (二): Win10下的开发环境配置, 编译和烧录说明 联盛德 HLK-W ...

  2. 联盛德 HLK-W806 (九): 软件SPI和硬件SPI驱动ST7789V液晶LCD

    目录 联盛德 HLK-W806 (一): Ubuntu20.04下的开发环境配置, 编译和烧录说明 联盛德 HLK-W806 (二): Win10下的开发环境配置, 编译和烧录说明 联盛德 HLK-W ...

  3. 洋桃技术支持0001:GPIO驱动12864液晶屏需要注意哪些事项?

    [提问]请问洋桃1号开发板的GPIOB端口要使用的话,硬件上和软件上需要注意什么?我想用STM32上的GPIOB端口控制点亮一个20口的12864液晶屏? 解答: [方法论] 1,解决这个问题的方法是 ...

  4. 51单片机三线串行驱动12864液晶

    以前写12864的液晶程序都是用的并行的方式,这种方式焊接起来很麻烦,而且占用的IO口比较多. 今天尝试使用串行方式来驱动该模块. 本程序是基于STC89C52的12864串行模式的程序,硬件电路连接 ...

  5. 联盛德 HLK-W806 (八): 4线SPI驱动SSD1306/SSD1315 128x64 OLED液晶屏

    目录 联盛德 HLK-W806 (一): Ubuntu20.04下的开发环境配置, 编译和烧录说明 联盛德 HLK-W806 (二): Win10下的开发环境配置, 编译和烧录说明 联盛德 HLK-W ...

  6. 12864液晶驱动源码,独创中英文混合输出

    12864液晶驱动源码,独创中英文混合输出 51单片机学习笔记:ST7920控制器的12864液晶使用总结 转载于:https://www.cnblogs.com/LittleTiger/p/4724 ...

  7. ESP32驱动LCD液晶屏选型、262K什么意思?SPI写LCD的GRAM时序、MCU液晶屏驱动IC的寄存器功能

    最近转战ESP32,ESP32-D0WDQ6 型号的GPIO只有那么20个左右,且还有几个GPIO只能做输入,非常捉襟见肘.所以如果要驱动LCD液晶屏,绝大多数都会选择SPI接口的MCU屏. 为了编写 ...

  8. STM32驱动ST7920的12864液晶(串行方式)

    /****************************************************************************************** * 文件名称 : ...

  9. 基于s3c2440的12864液晶驱动

    基于s3c2440的12864液晶驱动 12864是12864点阵液晶模块的点阵数简称,业界约定俗成的简称. 一.液晶显示模块概述 12864A-1 汉字图形点阵液晶显示模块,可显示汉字及图形,内置 ...

最新文章

  1. 基于Windows 2008 R2 Core的SQL Server 2008 R2 Cluster部署(Step by Step)
  2. python中torch模块下载,Python qtorch包_程序模块 - PyPI - Python中文网
  3. C++ multimap 的插入,遍历,删除
  4. 数字通信介绍(4) OFDM为何如此热门?
  5. 指针04 - 零基础入门学习C语言44
  6. 黑客演化史:从20世纪60年代至今
  7. linux ftp验证指令,linux FTP常用指令说明
  8. cygwin-1.7 离线安装包_.NET Framework所有版本微软官方下载地址
  9. html旅途模版,HTML黄色欧美形式探险旅途指南网页模板代码
  10. Stream介绍及简单操作!
  11. int.Parse(),int.TryParse(),Convert.ToInt32(), (int)转换为数字类型方法简介
  12. [python]python生成md5
  13. 利用wireshark分析Voip语音RTP协议
  14. java 打印字间距 行距_[图片问答]LODOP打印的行间距字间距
  15. labelme打开不了jpg格式和其他一些格式的图片
  16. OpenWrt之DNS域名解析系统(/etc/resolv.conf)
  17. 全方面对比流行报表开发工具,哪一个才是你的菜?
  18. 计算机 睡眠 无法打印,台式机睡眠后打不开怎么办
  19. PayPal 如何付款
  20. GIS概念介绍和对webgis的理解

热门文章

  1. 事件分类及正则表达式
  2. 自动填充空白单元格_使用自动填充插入或删除单元格
  3. 英文pdf的划词翻译阅读方法
  4. Redis3.0.0集群一键脚本 -by古斌
  5. 人在江湖,以“核”为贵
  6. python列表切片习题(一)
  7. 【ACWing】1176. 消息的传递
  8. 专题地图的编制——整理复习
  9. iOS 开发者账号总结
  10. python inputs[:,::2,::2,:]