支持Nor Flash读写的SPI主控制器设计、仿真和FPGA验证(含XIP模式)
文章目录
- 前言
- 一、功能
- 二、架构设计
- 三、接口介绍
- 四、寄存器介绍
- 五、APB接口读写W25Q128 Flash
- 六、AHB接口读W25Q128 Flash(即XIP模式)
- 七、CRC32功能使用方法
- 八、SOC系统集成验证
- 九、资源下载
前言
提示:本文仅供个人学习,未经授权严禁转载。
一、功能
(1)支持SPI模式0和模式3(关于SPI模式的介绍网上有很多,这里不再赘述。重点注意一下:对于模式0和模式3,发送端在SPI时钟下降沿发送数据,接收端在SPI时钟上升沿采样数据);
(2)支持Standard SPI,Dual SPI,Quad SPI模式;
(3)支持XIP模式(支持W25Q、N25Q、MX25L等系列SPI Flash);
对于XIP模式的定义,每一款Flash器件的说法似乎有些细微的差异。本文的理解就是,在XIP模式下,Flash器件可以看作一块类似于sram的存储设备,只需要通过地址即可读取Flash的存储内容。不需要像SPI接口读Flash时那样,需要先发送flash专用的读命令,其次发送读地址,以及可能需要发送的dummy cycle,然后Flash才会返回读数据。本文设计的SPI主控制器的AHB path能够将AHB读操作直接转换成SPI读Flash操作,因此从AHB接口端来看,Flash就像一个普通的sram一样,通过地址即可读取Flash中的数据。
(4)SPI控制器时钟频率为50MHz时(SPI接口时钟sclk频率最高为25MHz),AHB接口地址连续读W25QXX Flash带宽最高约为12.5MB/s,随机地址读带宽约4.3MB/s;
(5)支持对AHB接口读取的数据计算CRC32校验码(目的:验证Flash Device中的数据是否被正确传输到SPI主控制器端);
二、架构设计
三、接口介绍
(1)AMBA3 AHB-Lite接口
(2)AMBA4 APB接口
(3)SPI接口
| Name | IO Type | description |
|---|---|---|
| cs_n | output | SPI片选信号 |
| sclk | output | SPI时钟信号 |
| io_0 | inout | SPI数据线0,MOSI |
| io_1 | inout | SPI数据线1,MISO |
| io_2 | inout | SPI数据线2 |
| io_3 | inout | SPI数据线3 |
(4)中断电平信号
在以下情况时会产生中断:
i. 发送buffer为空;
ii. 接收buffer非空;
iii. 在AHB path检测到写操作(AHB path为XIP模式,只支持读操作);
四、寄存器介绍

五、APB接口读写W25Q128 Flash
APB读写Flash需要通过多次访问寄存器来实现。
5.1 APB写Flash
以W25Q128 Flash中写Flash的命令Page Program (02h)为例,只需要通过访问寄存器依次将1byte命令、3byte地址和若干待写入的数据以byte为单位发送出去即可。W25Q128的Page Program命令的sequence如下图所示:
5.1.1 寄存器访问具体流程(以向地址24’h123456写入8’hA0为例)
(1)向寄存器地址8’h20写入32’h02(即把命令8’h02写入tx_buf);
(2)向寄存器地址8’h0写入32’h1(即abort=0, last_byte=0, op_mode=0, rx_trig=0, tx_trig=1);
(3)循环读寄存器地址8’h10,直到读数据的bit0为1(即tx_buf_empty=1);
(4)向寄存器地址8’h20写入32’h12(即把地址的高8bit写入tx_buf);
(5)向寄存器地址8’h0写入32’h1;
(6)循环读寄存器地址8’h10,直到读数据的bit0为1;
(7)向寄存器地址8’h20写入32’h34(即把地址的中间8bit写入tx_buf);
(8)向寄存器地址8’h0写入32’h1;
(9)循环读寄存器地址8’h10,直到读数据的bit0为1;
(10)向寄存器地址8’h20写入32’h56(即把地址的低8bit写入tx_buf);
(11)向寄存器地址8’h0写入32’h1;
(12)循环读寄存器地址8’h10,直到读数据的bit0为1;
(13)向寄存器地址8’h20写入32’hA0(即把要写入Flash的数据写入tx_buf);
(14)向寄存器地址8’h0写入32’h11(即abort=0, last_byte=1, op_mode=0, rx_trig=0, tx_trig=1);
循环读寄存器地址8’h10,直到读数据的bit0为1;
5.1.2 仿真波形
5.2 APB读Flash状态寄存器
在5.1节中介绍了Page Program指令写Flash的流程,但是Page Program指令本身只是负责把要写入Flash的数据发送给Flash端,而数据真正写入Flash存储单元还需要一段时间,这个时间一般是需要若干毫秒。主控端可以通过定时的方式,固定延时多少毫秒后再发起下一次对Flash的读写访问;也可以通过循环读Flash中的状态寄存器,根据状态寄存器的值判断上一次的写操作或者擦除操作是否完成。本文设计的SPI控制器没有定时的功能,因此只能通过软件定时或者读Flash状态寄存器的方式判断当前Flash是否处于busy状态。

W25Q128的BUSY位在状态寄存器1的bit0,读状态寄存器1的sequence如下图所示:

5.2.1 寄存器访问具体流程(以循环读W25Q128状态寄存器1,且直到BUSY等于0为例)
(1)向寄存器地址8’h20写入32’h05(即把命令8’h05写入tx_buf);
(2)向寄存器地址8’h0写入32’h2(即abort=0, last_byte=0, op_mode=0, rx_trig=1, tx_trig=0);
(3)循环读寄存器地址8’h10,直到读数据的bit 1为1(即rx_buf_full=1);
(4)APB读寄存器地址8’h24,APB read data即为状态寄存器1的值;
(5)判断状态寄存器1的bit 0(BUSY)是否为0,若为0则表示flash处于idle状态,向寄存器地址8’h0写入32’h21/32’h22(即abort置1,rx_trig或tx_trig置1,op_mode和last_byte可以为任意值),将cs_n直接拉高,结束当前的SPI传输;否则返回步骤(2);
5.2.2 仿真波形
六、AHB接口读W25Q128 Flash(即XIP模式)
AHB读数据位宽为32bit,一次AHB读命令固定从Flash中读4byte数据,因此建议通过AHB path读Flash时,一次读32bit数据,从而提高读取速率。(AHB的narrow transfer也是支持的,支持AHB一次读1byte、2byte、4byte数据,只是AHB读操作转换成SPI读Flash操作时,都是4字节对齐的读Flahs操作)
另外,该SPI主控支持AHB读取一个地址后,在没有收到下一个AHB读命令的情况下,自动从Flash中读取下一个地址的32bit数据,节省SPI读Flash时的命令、地址和dummy的开销,从而提高AHB连续读Flash的带宽。
(1)AHB地址非连续读Flash波形如下,第一个读地址为24’h123450,第二个读地址为24’h123458。
(2)AHB地址连续读Flash波形如下,第一个读地址为24’h123450,第二个读地址为24’h123454。
七、CRC32功能使用方法
(1)向寄存器地址8’h28写入32’h3,使能CRC32计算的功能,并初始化CRC32。
(2)通过AHB接口从Flash中读数据,所有AHB接口读取的数据都会参与CRC32的计算;
(3)读取寄存器地址8’h2C,获取CRC32的计算结果。
八、SOC系统集成验证
将该SPI主控和ARM Cortex-M3核集成在一起,并编写C代码对Flash进行读写测试。从Flash中读数据的测试结果如下。(已提前将Flash中的数据初始化为0~256,即Flash地址0~255的值依次为0~255,地址256~511的值同样依次为0~255,其他地址的值以此类推)
测试的C代码:

串口打印结果:

九、资源下载
免费版verilog代码和仿真文件下载:点击下载