SPI_FLASH

本文详细介绍了SPI通信协议的工作原理,特别是Flash存储器的页、扇区和块概念,以及全擦除、扇区擦除和数据读写的时序操作。作者还探讨了如何通过FPGA和FIFO解决跨时钟域问题,并反思了学习过程中的方法和工具使用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1 理论知识

1.1、SPI通信协议

1.1.1SPI 物理层


通讯模式是主从通讯模式
SPI 通讯协议包含 1 条时钟信号线、 2 条数据总线和 1 条片选信号线, 时钟信号线为
SCK, 2 条数据总线分别为 MOSI(主输出从输入)、 MISO(主输入从输出),片选信号线为
CS_N(低电平有效)
 

1.2flash特性

1.2.1页(Page)、扇区(Sector)、块(Block) 的概念

(1)页

Flash存储器中一种区域划分的单元,好比一本书中一页(其中包含N个字)

比如:STM32F1中小容量芯片内部Flash,1K字节为1页,整个Flash分为32页(当然,不同容量的芯片,页数不同)

注: 不同厂家的、不同类型存储器的页大小不同,1KB、2KB、4KB等各种容量的页大小都有。

(2)扇区(Sector)

扇区和页类似,也是一种存储结构单元,只是扇区更常见,大部分Flash主要还是以扇区为最小的单元

比如:W25Q256芯片以4KB为1扇区

 同样: 不同厂家的、不同类型存储器的扇区大小可能不同

(3)块(Block)

块,比扇区更高一个等级,一般1块包含多个扇区。

同样,以上图W25Q256芯片为例:1块包含16个扇区。

说明:W25Q256中256的意思是:存储空间256Mb (32M x 8)  也就是32M字节

还有,你可能会看到一些其他的名词,比如:和扇区一个级别的SubSector和块一个级别的Bank、Bulk

用包含关系来描述Flash物理分区的话: 芯片包含多个块,块又包含多个扇区,扇区又包含多个页,页包含多个字节

根据容量大小来说,它们的关系:
** 页(Page)** < 扇区(Sector) < 块(Block)< 芯片(Chip)**

1.3 几个时间的说明

 保持时间:数据需要保持不变的时间

时序里面特别要注意的三个时间:

1 从片选信号拉低到第一个有效数据写入的时间tSLCH(最小5ns)

2 从最后一个有效数据写入到片选信号拉高的时间tCHSH(最小5ns)

3 片选信号的高电平等待时间tSHSL(最小100ns)

为了方便寄存器的计数  程序中采用的640ns的计数方式实现

2 实战演练

2.1 全擦除和扇区擦除

说明:根据按键消抖后的key的标志信号触发擦除指令。

出现触发信号后,根据flash的操作时序进行指令的一系列操作

2.1.1 全擦除模块的波形图绘制

         根据上述时序的要求,想要实现全擦除,首先要发送写使能指令(注意:在进行每次页面编程、扇区擦除、块擦除、芯片擦除和写状态寄存器操作前,必须设置 WEL 位。要输入“写使能”指令,请拉低 /CS 引脚,在 CLK 上升沿时向数据输入(DI)引脚输入指令代码“06h”,然后将 /CS 引脚拉高。)

        然后按照上面的时序图实现C7指令的写入:先拉低cs_n,然后写入C7指令,等待一阵后拉高cs_n,至此全擦除功能实现完毕。

        注意:

        1、在写使能指令和全擦除指令写入的过程中 牵扯到指令的输入或者输出的时候sck才需要进行信号驱动,其他时刻sck为0即可。

        2、发送指令过程中高位在前,低位在后。

2.1.2 扇区擦除的波形图的绘制

The Block Erase instruction sets all memory within a specified block (64K-bytes) to the erased state of all 1s (FFh). A Write Enable instruction must be executed before the device will accept the Block Erase Instruction (Status Register bit WEL must equal 1). The instruction is initiated by driving the /CS pin low and shifting the instruction code “D8h” followed a 24-bit block address (A23-A0) (see Figure 2). The Block Erase instruction sequence is shown in figure 18.

“块擦除”指令将指定块(64K 字节)中的所有存储器内容都设置为擦除状态即全是1(FFh)。在设备接受“块擦除”指令之前,必须先执行“写使能”指令(状态寄存器位 WEL 必须等于 1)。该指令由拉低 /CS 引脚并输入指令代码“D8h”,接着输入 24 位块地址(A23-A0),如图 2 所示。块擦除指令序列如图 18 所示。

The /CS pin must be driven high after the eighth bit of the last byte has been latched. If this is not done the Block Erase instruction will not be executed. After /CS is driven high, the self-timed Block Erase instruction will commence for a time duration of tBE (See AC Characteristics). While the Block Erase cycle is in progress, the Read Status Register instruction may still be accessed for checking the status of the BUSY bit. The BUSY bit is a 1 during the Block Erase cycle and becomes a 0 when the cycle is finished and the device is ready to accept other instructions again. After the Block Erase cycle has finished the Write Enable Latch (WEL) bit in the Status Register is cleared to 0. The Block Erase instruction will not be executed if the addressed page is protected by the Block Protect (TB, BP2, BP1, and BP0) bits (see Status Register Memory Protection table).

在最后一个字节的第 8 位被捕获后,必须将 /CS 引脚拉高。如果不这样做,则不会执行块擦除指令。将 /CS 引脚拉高后,将开始进行自定时块擦除指令,持续时间为 tBE(参见 AC 特性)。在块擦除循环进行时,仍可访问“读取状态寄存器”指令,以检查 BUSY 位的状态。在块擦除循环进行时,BUSY 位为 1,当循环结束并且设备准备好再次接受其他指令时,BUSY 位变为 0。块擦除周期结束后,“写使能锁存器(WEL)”位在状态寄存器中将被清除为 0。如果地址所在页面受“块保护”(TB、BP2、BP1 和 BP0)位(参见状态寄存器存储保护表)的保护,则块擦除指令将不会被执行。

         与全擦除类似,扇区擦除要求先进行写使能指令,然后先发送扇区擦除指令,紧接着发送地址

2.2 页写与连续写

        连续写这里就是多次的页写操作,同样根据芯片手册的要求进行相应时序程序的编写。

2.3 数据读取

        这里涉及到跨时钟域处理的问题,为什么这么说?

        首先,fpga对于flash数据的读取的速度要比串口发送到PC机的速度要快,这里为了实现串口数据的正确传输,这里就运用到了fifo IP核的相关知识:先把从flash读取到的数据暂存到8bit位宽的fifo当中,然后等待100个字节的串口数据接收完毕。在100个字节的串口数据接收完毕以后,设计一个cnt计时器,开始从fifo向串口的发送模块进行数据传输。

   

        这里特别强调一下fifo数据的写入,这是笔者出现严重错误的部分,原因在于错误理解了芯片手册的介绍:

        接收到地址后,被地址定位的存储器位置的数据字节会在 CLK 下降沿时从 DO 引脚开始以最高有效位(MSB)优先的方式依次输出。在每个数据字节输出后,地址会自动增加为下一个较高地址,以实现连续的数据流

        注意数据的输出是从miso引脚出来的,但是要注意mimo数据的更新开始是在sck的下降沿,这也就意味着读取flash芯片的存储信息不能在sck的下降沿,因为此时的数据不稳定,数据的读入依然我们选择在sck的上升沿进行读取。这里有跨时钟域部分的含义,就是说通过同步fifo的模式,实现了从快速时钟域向慢速时钟域的转换。

3 总结

        本章节的学习花费了笔者将近两个星期的时间,当然期间的学习是断断续续的。总结花费时间长的原因:1、学习的目的不明确,没有明确的学习方法论。对于芯片的学习,笔者觉得可以主要从两个方面学习,第一是芯片指令的学习,指令部分有比较详细的时序数据操作介绍;第二个是输入时序部分的讲解,通过输入时序的要求我们可以设置最小的byte计数时间。结合输入时序的要求核指令部分的介绍,就可以写出目的指令的时序程序,然后通过仿真进行验证。

        此外,本次的代码的编写主要不是依靠viso文件波形图的绘制,更多的是依靠modelsim仿真后逐步对波形的调整实现的。这种情况是在波形图的中间变量太多,viso时序图不容易绘制的背景下出现的,当然,目前来说我不认为这是一种高效的编程方式。

        同时我也注意到:所有中间变量都是为了服务于输入输出波形的对应关系的,所以说可能会存在输入输出波形一致,但是中间变量不一致的情况,而我们可能每个人编写程序的不同可能更多的也会体现在中间变量的设置上。

<think>嗯,用户想了解SPI Flash的相关信息或者使用方法,需要教程或工作原理。首先,我需要回忆SPI Flash的基础知识,确保自己理解正确。SPI是串行外设接口,而SPI Flash是一种基于SPI接口的闪存设备,常用于存储固件、配置数据等。 首先,工作原理部分,SPI Flash的结构应该包括存储单元、控制逻辑和SPI接口。存储单元通常使用NOR或NAND Flash技术,但SPI Flash多为NOR型,因为支持随机读取,适合代码存储。控制逻辑负责处理命令,比如读取、写入、擦除等操作。SPI接口包括四个信号线:SCK(时钟)、MOSI(主出从入)、MISO(主入从出)、CS(片选),可能还有WP和HOLD引脚用于写保护和保持状态。 然后,用户可能需要了解基本操作步骤,比如读数据、写使能、页编程、扇区擦除等。每个操作都有对应的指令码,比如读数据是0x03,写使能是0x06。要注意的是,写操作前必须先发送写使能命令,并且写入前需要确保目标扇区已擦除,因为闪存只能将1变为0,擦除会将整个扇区恢复为1。 硬件连接方面,需要正确连接SPI的引脚,注意主从设备的对应关系。软件驱动部分,需要实现SPI的初始化、命令发送、数据读写等函数。例如,初始化时要配置时钟极性、相位,片选引脚的控制,以及GPIO的设置。 实际应用中,用户可能会遇到问题,比如通信失败,可能原因包括时序配置错误、指令顺序不对、未等待就绪状态等。需要检查SPI模式是否匹配,是否有正确的CS控制,以及是否在写入前等待了足够的延迟。 现在要生成相关问题,可能需要覆盖SPI Flash与其他存储器的区别、SPI通信模式的配置、如何提高读写速度、使用中的常见错误及解决方法,以及在嵌入式系统中的具体应用案例。这些问题能帮助用户深入理解并解决实际操作中的问题。 最后,要确保回答结构清晰,分点讲解,代码示例正确,引用相关的知识点,比如SPI模式、指令集等,但用户提供的引用标识没有具体来源,可能需要用通用标注。同时,避免使用Markdown格式,保持自然的中文表达。</think>### SPI Flash工作原理与使用方法 #### 一、SPI Flash基本结构 SPI Flash是基于SPI接口的NOR型闪存,包含存储单元阵列、控制逻辑和SPI接口模块[^1]。其核心特性包括: - 存储密度:1Mb~256Mb - 页编程单位:通常256字节 - 擦除单位:4KB扇区/32KB块/64KB块 - 接口协议:支持标准SPI/Dual SPI/Quad SPI #### 二、操作流程详解 1. **读数据操作**: ```c // 发送读指令(0x03) + 24位地址 spi_send(0x03); spi_send((address >> 16) & 0xFF); spi_send((address >> 8) & 0xFF); spi_send(address & 0xFF); // 持续读取数据 for(int i=0; i<length; i++){ data[i] = spi_receive(); } ``` 需注意时序参数:$t_{ACC}$(存取时间)和$t_{SHQV}$(输出保持时间)[^2] 2. **编程操作**: ```python def page_program(address, data): send_write_enable() cs_low() spi_transfer(0x02) # 页编程指令 send_24bit_address(address) for byte in data: spi_transfer(byte) cs_high() wait_busy() # 等待编程完成 ``` 满足时序约束:$t_{PP}$(页编程时间)通常3-5ms #### 三、硬件连接规范 典型接线示意图: ``` MCU SPI Flash SCK ------> SCK MOSI ------> SI MISO <------ SO CS ------> CS# GND ------> WP# (写保护) 3.3V ------> HOLD# (保持) ``` 注意电平匹配:需确认VDD范围(2.7-3.6V) #### 四、软件驱动开发 关键函数实现示例: ```c uint8_t spi_flash_read_status(void){ uint8_t status; FLASH_CS_LOW(); spi_transfer(0x05); // 读状态寄存器指令 status = spi_transfer(0xFF); FLASH_CS_HIGH(); return status; } void spi_flash_sector_erase(uint32_t addr){ send_write_enable(); FLASH_CS_LOW(); spi_transfer(0x20); // 4KB扇区擦除指令 spi_transfer((addr >> 16) & 0xFF); spi_transfer((addr >> 8) & 0xFF); spi_transfer(addr & 0xFF); FLASH_CS_HIGH(); while(busy_status()); // 等待擦除完成 } ``` #### 五、典型问题排查 1. **读写数据异常**: - 检查SPI模式(CPOL/CPHA) - 验证时序参数是否满足$t_{CS}$(片选保持时间) - 确认供电电压稳定(纹波<5%) 2. **擦除失败**: - 检查写保护引脚(WP#)状态 - 确保执行擦除前已发送WRITE ENABLE(0x06) - 验证地址对齐(必须4KB边界对齐)
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值