一、功能
(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 主控制器端);
二、架构设计
![图片: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 如下图所示:
![图片:Page Program 序列]
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;


