大侠好,欢迎来到FPGA技术江湖。本系列将带来FPGA的系统性学习,从最基本的数字电路基础开始,最详细操作步骤,最直白的言语描述,手把手的“傻瓜式”讲解,让电子、信息、通信类专业学生、初入职场小白及打算进阶提升的职业开发者都可以有系统性学习的机会。
系统性的掌握技术开发以及相关要求,对个人就业以及职业发展都有着潜在的帮助,希望对大家有所帮助。本次带来Vivado系列,RTC实时时钟系统设计。话不多说,上货。
实时时钟系统设计
RTC(real time clock)实时时钟,在电脑、手机等电子产品中都有,应用较多。它的主要作用就是,在产品断电之后,时间还可以继续走数。这样我们在重新使用电子产品时,时间仍然正确。芯片本身可以通过纽扣电池供电,接下来我们一起学习一下RTC的驱动。
此次,RTC用到的主芯片为DS1302,优点为控制简单,接下来我们一起了解一下芯片的特性以及控制。
一、芯片特征
在官方文档中,给出了以下重要特点描述:
1、实时时钟系统可以计数时、分、秒、日、月、星期、区分闰年平年的年份等,最多支持2100年。 2、有31*8bit的存储容量的RAM。 3、实时时钟系统或者RAM的读写,可以单字节或者多字节(突发模式)进行数据传输。 在芯片计时过程中,可以准确的计出时分秒等,还有每个月各有多少天。有30、31、28、29天的区分,年份有闰年平年的区分。小时有12小时制和24小时制。有AM和PM的区分。 芯片的控制是通过CE、I/O(data line)和SCLK。数据线可以一次传输1字节或者31字节。
二、端口
图中的MCU在此时是指的我们的FPGA,那么,FPGA与芯片进行数据交互时,是通过三个串行线进行的,并且I/O为双端口类型。芯片的端口中,除了三个主控端口(CE、I/O、SCLK)外,还有X1和X2。 这两个端口为晶振接口,芯片需要一个外挂晶振来提供时钟,以便用来计时。VCC1和VCC2为两路电源,其中VCC2为板卡提供的电源,VCC1为纽扣电池供电。供电关系会在下面的管脚说明里面进行讲解。 GND为电源地。
三、管脚说明
四、命令格式
下图展示了命令字节,一个命令字节由数据的发送者决定。最高位必须为1,如果是0,将禁止向芯片写数据。bit6如果是0将与实时时钟系统通信,如果是1将与RAM通信。bit1到bit5为寄存器地址;bit0如果为0为写操作,1为读操作。
五、读写控制
首先是写操作,在8个SCLK时钟周期内,主机发送一个写命令字节,数据输入在接下来的8个SCLK时钟的上升沿,数据开始为bit0,也就是说,数据在发送时,从低位开始发送。
数据读操作,在8个SCLK时钟周期内,主机发送一个读命令,数据输出在接下来的8个SCLK时钟下降沿。第一个数据bit出现在命令字节最后一个bit被写入之后的第一个下降沿。通常数据传输需要在CE为高时。读数据时,也是从低位开始。
六、接口协议
基于芯片的读写方式,我们可以使用SPI协议进行数据读写,那么接下来我们介绍一下SPI协议。 SPI协议有四种模式,如下图:
SPI的四种模式是按照其时钟极性(CPOL)和时钟相位(CPHA)共同决定的,CPOL=0,即SCLK=0,表示SCLK时钟信号线在空闲状态时的电平为低电平,因此有效状态为高电平。CPHA=0,即表示在时钟的第一个岩信号进行采样。CPOL和CPHA共有四种组合,固有四种通信模式。
SPI为主从模式,在通信线上,需要4通信线: CS – 从设备使能信号,由主设备控制 SCL – 时钟信号,由主设备产生 MISO – 主设备数据输入,从设备数据输出 MOSI – 主设备数据输出,从设备数据输入 但是,一般为了节省资源,会使用3跟通信线,分别为CE、SCL、SDA。其中SDA为双端口。数据的输出和输入都使用这条线。 在我们的DS1302时序图中,读写时序跟SPI的第一种模式一样,所以我们在写代码的时候可以使用SPI协议去写。
接下来我们开始新建工程写代码。
新建文件,按照写时序,通过线性序列机写出写模块。
代码如下:
同样的方式,新建文件读模块以及控制模块,代码如下:
在读写模块中,按照框架设计,计数器必须在使能有效的条件下进行,所以,在写计数器时,必须判断使能信号。
控制模块如下:
在控制模块中,我们前三个状态要把时间的初值写进芯片,比如我们写入时分秒,那么我们需要按照手册给出相应的命令。
在这里我们需要解释一下小时的数据格式。BIT7如果为0代表使用的是24小时制,如果为1代表使用的是12小时制。BIT6恒为0。BIT5,如果是12小时制,0代表上午,1代表下午,如果是24小时制,BIT5和BIT4共同组成了小时的十位。BIT3到BIT0为小时的个位。
顶层模块代码如下:
在这里需要大家注意的是三态门的编写。
作为输入时,将数据线置为高祖态。
仿真图如下:
前三个状态,分别写入了时分秒等数据,3 4 5三个状态分别是读时分秒的状态,最后一个状态是做的延时,在一秒时间内,读出的数据是没有变化的,因此我们可以减少读操作的频率来降低工作频率。在rd_done信号拉高时,可以看到时分秒都有数据被赋值,及读出正常。
|