一,写在前面
SPI协议网上很方便能找到,归纳来讲有以下几点,本文不详述,可自行查找资料
1,主从模式 2,时钟同步方式传输数据 3,每一次通信都是一次“数据交换” 4,片选独立,因此无需芯片寻址
二,具体逻辑实现
2.1 文件描述

养成良好的代码书写习惯,对代码规范性,可维护性等都有很大好处。
2.2模块接口定义

首先我们需要一个全局的复位信号:sys_rstn,低电平有效
然后需要全局的时钟信号,由于我们设计的单板上一般较常见的晶振是25M,因此这里采用25M作为系统时钟:sys_clk_25m,如果你使用别的频率时钟可以不?当然可以那么SPI的SCK时钟频率会随着你的更改变化,你可以再后面自行再调整一下分频
接下来SPI接口信号,SPI接口我们熟悉的4个信号。
然后,我们需要一个状态位来指示当前SPI口是处于busy还是idle状态:spi_ready
需要一个控制位来发起一次spi接口操作:spi_start,当此信号为1时表示需要发起一次操作;
我们需要确定是针对从设备哪一个寄存器地址进行读写操作,因此需要定义一个操作地址:spi_reg_addr,此示例为14bit寄存器寻址,需要一个控制信号用来指示此次操作是读还是写:spi_rw,如果是写,我们需要一个buffer将要写入从设备的数据先准备好:spi_wr_data,如果是读,还需要一个buffer将从设备读出来的数据先存入以供访问CPLD的设备(假设是CPU)来获取:spi_rd_data。
2.3IO类型定义

这一小节不用做过多的解释,通过上一小节的说明很容易理解。
2.4常量、寄存器定义

需要重点说明的是SPI基于状态机运行,因此首先定义了SPI的6个状态,使用6bit来定义:
IDLE:空闲
CHIP_SEL:从设备片选
REG_ADDR:写地址
WR_DATA:写数据
RD_DATA:读数据
CHIP_DESEL:释放从设备CS
需要一个寄存用来指示当前状态机所处的状态以及下一个状态是什么:curr_spi_state[5:0]、next_spi_state[5:0]。
需要将接口定义部分给过来的信号存储,spi_addr_reg、spi_wdata_reg、spi_rw_reg、spi_start_reg等。
其余寄存器定义通过后面的代码来理解
2.5时钟处理

目的就是为了产生一个6.25M的时钟用于后面SPI接口的操作。
2.6 Start信号宽度

这一段的目的就是,一旦出现有效的start信号(高电平),将其在25M时钟域下产生一个8个周期脉宽的spi_start_wide信号,然后将其打三拍同步到6.25M时钟域下面:spi_start_6m25_reg0、spi_start_6m25_reg1、spi_start_6m25_reg2,在6.25M时钟域下,这个信号在start有效时,持续2个周期。
//*******************************码字太累 明天继续**************************//