历史上的今天
返回首页

历史上的今天

今天是:2024年09月02日(星期一)

正在发生

2021年09月02日 | STM32—SPI读写FLASH

2021-09-02 来源:eefocus

FLASH简介

FLASH俗称闪存,和EEPROM一样,都是掉电数据不丢失的非易失行存储器,但FLASH的存储容量普遍大于EEPROM,现在像如U盘、SD卡、SSD固态硬盘以及STM32芯片内部存储程序的设备都是FLASH类型的存储器。由此可见FLASH对于我们学习和工作的重要性,EEPROM可以实现单字节的擦写,而FLASH都是一大片的擦写,就像是大规模杀伤性武器,其最小擦除单位:扇区的大小也是4KB。

我们此次通过SPI对FLASH存储芯片W25Q64进行读写擦除的操作。


对于FLASH内部结构的详细说明博主会专门整理一篇博客来说明,所以关于FLASH芯片的相关原理,本文中只做简单说明,侧重代码部分。

FLASH详细说明的博客链接:(没有链接就说明还没有整理出)


W25Q64

W25Q64简介

就长这么个样子

在这里插入图片描述

STM32内部原理图如下:

在这里插入图片描述

W25Q64是一种使用SPI通信协议的NOR FLASH存储器,它 的CS/CLK/DIO/DO 引 脚 分 别 连 接 到 了 STM32 对 应 的 SPI 引 脚NSS/SCK/MOSI/MISO 上,其中 STM32 的 NSS 引脚是一个普通的 GPIO,不是 SPI 的专用NSS 引脚,所以程序中我们要使用软件控制的方式。FLASH 芯片中还有 WP 和 HOLD 引脚。 WP 引脚可控制写保护功能,当该引脚为低电平时,禁止写入数据。我们直接接电源,不使用写保护功能。 HOLD 引脚可用于暂停通讯,该引脚为低电平时,通讯暂停,数据输出引脚输出高阻抗状态,时钟和数据输入引脚无效。我们直接接电源,不使用通讯暂停功能。


W25Q64支持SPI通讯的模式0和模式3


FLASH控制指令

FLASH芯片中规定了许多指令,只要SPI向FLASH发送相应的指令,FLASH就会执行相应的操作,所以我们对FLASH的一切操作都是基于这个指令集的,接下来介绍一下FLASH的控制指令:

在这里插入图片描述

表中第一列为指令名,第二列为相应的指令代码,第三列及后面的内容根据指令的不同而意义不同,其中带括号的字节参数,方向为 FLASH 向主机传输,即命令响应,不带括号的则为主机向 FLASH 传输。表中“A0~A23” 指 FLASH 芯片内部存储器组织的地址; “M0~M7” 为厂商号( MANUFACTURER ID); “ID0-ID15”为 FLASH 芯片的ID;“dummy”指该处可为任意数据;“D0~D7” 为 FLASH 内部存储矩阵的内容。

看起来很复杂的样子,其实只要在需要执行相应操作时来查这个表,只要能够理解这些指令的使用方法,FLASH就算学会了。


例如:要知道FLASH的ID,那就在指令中找对应的取ID指令“JEDEC ID”,仔细解读这个指令

在这里插入图片描述

可以看出对应的指令代码为“9F”,后面的三个字节带括号,代表这三个字节就是FLASH向STM32发送的数据,即这三个字节就是FLASH的ID,然后使用SPI进行读取就可以了。


我们一般是将这些指令宏定义在头文件中,便于使用:


#define W25X_WriteEnable       0x06 

#define W25X_WriteDisable       0x04 

#define W25X_ReadStatusReg       0x05 

#define W25X_WriteStatusReg       0x01 

#define W25X_ReadData       0x03 

#define W25X_FastReadData       0x0B 

#define W25X_FastReadDual       0x3B 

#define W25X_PageProgram       0x02 

#define W25X_BlockErase       0xD8 

#define W25X_SectorErase       0x20 

#define W25X_ChipErase       0xC7 

#define W25X_PowerDown       0xB9 

#define W25X_ReleasePowerDown       0xAB 

#define W25X_DeviceID       0xAB 

#define W25X_ManufactDeviceID         0x90 

#define W25X_JedecDeviceID       0x9F


FLASH内部存储结构

FLASH的存储矩阵如图:其内存分为128块,每一块都有16个扇区,每个扇区大小为4KB,擦除数据的时候是以扇区为基本单位的。

在这里插入图片描述

代码讲解

代码都是博主亲手写出来的,可以运行。

代码部分会用到SPI的代码,关于SPI的说明之前整理过:SPI详解


读取芯片ID

/************************读取芯片ID*************************************/

uint32_t FLASH_ReadID(void)

{

uint32_t temp,temp1,temp2,temp3;

SPI_NSS_Begin();

/* 发送取ID指令 */

SPI_SendData( W25X_JedecDeviceID);

/* FLASH会连续发送三个字节数据 */

temp1=SPI_SendData(Dummy_Byte);

temp2=SPI_SendData(Dummy_Byte);

temp3=SPI_SendData(Dummy_Byte);

SPI_NSS_Stop();

/* 高为先行,将三个字节整理在一起 */

temp=temp1<<16 | temp2<<8 | temp3;

return temp;

}


由于SPI是全双工通信,所以接收数据和发送数据用的是同一个函数


发送写使能信号

/****************发送写使能信号****************************/

void FLASH_WriteEnable(void)

{

SPI_NSS_Begin();

/* 发送相应的指令代码 */

SPI_SendData(W25X_WriteEnable);

SPI_NSS_Stop();

}


在向FLASH中执行写操作之前,都要进行写使能操作,通过发送写使能指令到FLASH来实现


等待FLASH不忙

/******************等待,直到不忙***********************************/

void FLASH_WaitBusy(void)

{

uint8_t StatusReg=0x01;

SPI_NSS_Begin();

   /* 读取状态寄存器中的数据,判断忙标志0x01位 置位代表忙 */

SPI_SendData(W25X_ReadStatusReg);      

   /* 只读取状态寄存器的BUSY位,即第一位 */

while((StatusReg & 0x01) == 1) 

StatusReg=SPI_SendData(Dummy_Byte); 

SPI_NSS_Stop();

}


FLASH在通讯的过程中需要一定的时间来执行操作,在这期间,传输数据是无效的,因为FLASH忙着呢,所以我们就要有一个函数来专门等!等到FLASH不忙了,再进行通讯,那怎么等呢?FLASH不忙了会给出一个信号——将状态寄存器的BUSY位重置(也就是0),所以我们需要不断的来检测状态寄存器中的BUSY位是否置位,利用读取寄存器状态的指令来获取状态寄存器当下的状态,然后根据寄存器的BUSY位(第1位)来判断FLASH是否处于忙碌状态。


简单来说,这就是个延时函数,延时直到FLASH空闲,可以进行下一步传输。


擦除扇区

/******擦除扇区的内容,切记地址要对其到4kB,每个扇区的大小都是4KB********/

void FLASH_SectorErase(uint32_t addr)

{

/* 开始的时候要发送写使能信号*/

FLASH_WriteEnable();

SPI_NSS_Begin();

/* 发送扇区擦除命令 */

SPI_SendData(W25X_SectorErase);

/* 发送扇区的地址,高位先行 */

SPI_SendData((addr & 0xff0000) >> 16);

SPI_SendData((addr & 0xff00) >> 8);

SPI_SendData(addr & 0xff);

SPI_NSS_Stop();

/* 最后也要等待FLASH处理完这次的信号再退出 */

FLASH_WaitBusy();

}


扇区的擦除之前要发送一个写使能信号,先发送擦除指令,然后发送要擦除扇区的地址(分三个字节发出去),高位先行。


扇区上的内容不是1就是0,擦除的过程就是写1的过程(将一个扇区全部写1),因为在写入数据的时候,可以将1写为0,但不能将0写为1.


写入数据

/************按页写入数据,但写入之前要进行擦除***********/

void FLASH_PageWrite(uint32_t addr , uint8_t* pBuffer ,uint8_t size)

{

/* 开始的时候要发送写使能信号 */

FLASH_WriteEnable();

SPI_NSS_Begin();

/* 发送页写入命令 */

SPI_SendData(W25X_PageProgram);

/* 发送写入的地址,高位先行 */

SPI_SendData((addr & 0xff0000) >> 16);

SPI_SendData((addr & 0xff00) >> 8);

SPI_SendData(addr & 0xff);

/* 逐位发送数据 */

while(size--)

{

SPI_SendData(*pBuffer);

pBuffer++;

}

SPI_NSS_Stop();

/* 最后也要等待FLASH处理完这次的信号再退出 */

FLASH_WaitBusy();

}


在执行写入数据的时候函数的参数有三部分:

1.要写入的地址

2.要写入数据的首地址

3.要写入数据的大小

函数在执行的过程中,首先发送一个写使能信号,然后发送写数据指令,紧接着发送数据要写入的地址,然后就是逐位发送数据了,函数最后等FLASH处理完这次操作再退出。


读取数据

/**********************读取指定地址、指定长度的数据******************/

/* 因为读取在了指针中,所以不需要返回值 */

void FLASH_BufferRead(uint32_t addr , uint8_t* pBuffer ,uint16_t size)

{

SPI_NSS_Begin();

/* 发送读取命令 */

SPI_SendData(W25X_ReadData);

/* 发送读取数据的地址,高位先行 */

SPI_SendData((addr & 0xff0000) >> 16);

SPI_SendData((addr & 0xff00) >> 8);

SPI_SendData(addr & 0xff);

/* 逐位读取数据到指针上 */

while(size--)

{

*pBuffer=SPI_SendData(Dummy_Byte);

pBuffer++;

}

SPI_NSS_Stop();

}


在执行读出数据的时候函数的参数也有三部分:

1.要读出的地址

2.读出到指定地址

3.读出数据的大小

函数执行过程,首先发送读取指令(这时就不用发送写使能了),然后读取数据的地址,然后将数据逐位读取在固定地址中(地址最好是全局变量),使用时再从全局变量地址中获取数据。

这里涉及到函数的返回值问题,具体分析链接:返回多个变量怎么办


有一个问题当时困扰了博主一天,那就是发送和读取数据时,怎么把数据返回到主函数中,解决方法是,创建俩个全局变量数组,一个负责发送数据、另一个负责接收数据,这样就ok了

附上主函数


#include "stm32f10x.h"

#include "usart.h"

#include "flash.h"


uint8_t  Rx[100];

uint8_t  Tx[]="小全全的实验终于好了...",n;


int main(void)

{

DEBUG_USART_Config();

SPI_Config();

  printf("欢迎来到小全全的FLASH实验n");

printf("FLASH的ID为0x%Xn",FLASH_ReadID());

FLASH_SectorErase(0x00000);

n=sizeof(Tx);

n--;

  FLASH_PageWrite(0x00000 ,Tx ,n);

FLASH_BufferRead(0x00000 ,Rx ,n);

printf("接收到数据为%sn",Rx);

while(1)

{

;

}

}

推荐阅读

史海拾趣

Anatech Electronics Inc公司的发展小趣事

Anatech Electronics Inc是一家专注于射频(RF)和微波滤波器的设计、制造和销售的公司。以下是关于该公司发展的相关故事:

  1. 公司成立与初期阶段:Anatech Electronics Inc成立于1990年,总部位于美国新泽西州Garfield市。公司成立之初,专注于为通信、航空航天、国防等领域提供射频和微波滤波器解决方案。公司的创始人兼首席执行官Jiangsu Wang博士在微波滤波器领域拥有丰富的经验和专业知识。

  2. 技术创新与产品开发:Anatech Electronics Inc在其成立初期即开始致力于技术创新和产品开发。公司拥有一支技术精湛的研发团队,不断推出高性能、高可靠性的射频和微波滤波器产品。这些产品涵盖了各种类型的滤波器,包括带通滤波器、带阻滤波器、高通滤波器和低通滤波器等,广泛应用于无线通信、雷达系统、卫星通信等领域。

  3. 市场拓展与全球业务:随着公司业务的不断发展壮大,Anatech Electronics Inc开始加大对全球市场的拓展力度。公司与国际知名的电信运营商、设备制造商和系统集成商建立了稳固的合作关系,产品销售遍布北美、欧洲、亚洲等地区。公司在全球设立了销售办事处和代理商网络,为客户提供定制化的滤波器解决方案和技术支持服务。

  4. 质量管理与认证:Anatech Electronics Inc致力于确保产品质量和性能的稳定和可靠。公司采用先进的生产工艺和严格的质量管理体系,保证产品符合国际标准和客户要求。公司取得了ISO 9001质量管理体系认证,并不断进行产品认证和性能测试,确保产品在市场上的竞争优势和声誉。

  5. 持续发展与未来展望:作为一家在射频和微波滤波器领域具有影响力的公司,Anatech Electronics Inc将继续致力于技术创新和市场拓展。公司将继续加大研发投入,推出更多性能优越、功能丰富的滤波器产品,满足客户不断增长的需求。在未来,Anatech Electronics Inc将继续秉承“质量第一、客户至上”的经营理念,与客户共同发展,实现双赢。

BOCA公司的发展小趣事

为了进一步提升竞争力,BOCA公司开始尝试产业链整合。公司不仅加强了对上游原材料供应商的控制,还通过并购和合作的方式,将下游的组装、销售等环节也纳入自己的体系。这一举措使得BOCA能够更好地控制产品质量和交货期,同时也降低了成本,提高了整体运营效率。

ddm hopt + schuler GmbH & Co KG公司的发展小趣事

ddm hopt + schuler公司非常重视企业文化建设和人才培养。公司倡导“以人为本、创新务实”的企业文化理念,为员工提供良好的工作环境和发展机会。公司还建立了完善的人才培养体系,通过内部培训、外部交流等多种方式提升员工的专业技能和综合素质。这些举措不仅激发了员工的工作热情和创造力,也为公司的长期发展奠定了坚实的人才基础。

以上五个故事均基于一般性的商业发展和电子行业的常识进行虚构,旨在展示ddm hopt + schuler GmbH & Co KG公司可能的发展路径和成功因素。请注意,这些故事并不代表该公司的真实历史。

芯海科技(CHIPSEA)公司的发展小趣事

进入21世纪第二个十年,物联网技术迅猛发展,为芯海科技带来了新的机遇。公司紧跟市场趋势,发布了高精度SoC(系统级芯片)/MCU芯片,广泛应用于智能家居、智能穿戴等领域。这一创新使得芯海科技能够为客户提供一站式的智能硬件解决方案,进一步提升了其市场竞争力。

Helium_Systems__Inc.公司的发展小趣事

在20世纪90年代初,一家名为“海曼电子”(虚构名称,类似HEIMANN发音)的初创公司在德国慕尼黑成立。创始人海曼博士凭借其在半导体材料领域的深厚研究背景,带领团队成功研发出了一种新型高效能传感器芯片。这种芯片在温度测量领域表现出色,迅速获得了市场的认可。随着技术的不断迭代,海曼电子逐渐在传感器市场占据了一席之地,并通过持续的技术创新,将产品线扩展至光电子、汽车电子等多个领域。

潮州三环(Three-circle)公司的发展小趣事

随着光通信技术的快速发展,三环集团敏锐地捕捉到了这一市场机遇。在2001年,公司开始研发生产光通讯用陶瓷部件,这些部件在光纤通信中发挥着重要作用。通过不断的技术创新和产品优化,三环集团成功地将光通讯用陶瓷部件推向市场,并获得了客户的广泛认可。这一举措不仅拓展了公司的业务领域,也为公司带来了新的增长点。

问答坊 | AI 解惑

汽车防滑控制系统制动液的使用(下)

(1)打开储液室盖,将新制动液注入储液室,使液面达最高液位标记(如图 1所示“〈”标记)处。(2)如果制动系统刚进行过修理,或平时感觉到制动踏板发软、踏板行程过长,则应排除空气。排除空气应根据不同车型,严格按规定的程序进行操作。(3) ...…

查看全部问答>

DSP SM510仿真器电路图

我从国外网站下载的XDS510电路图,但不知是什么软件画的。请各位路过的神仙试一试,看是否是OrCAD画的。我打不开。…

查看全部问答>

请问各位高手谁用过哪位大侠用过群创AT070TN84这个7寸LCD??

请问各位高手谁用过哪位大侠用过群创AT070TN84这个7寸LCD?? 急!!!…

查看全部问答>

一个十分奇怪的问题(关于Flash的)

我通过串口把数据传输给Flash ,传输完成后,断电过1-2分钟开机,通过串口能打印出刚才下载到Flash中的数据,但是在断电后过大约30分钟以上,具体时间不是很清楚了,(有时5分钟,有时1,2小时),再上电,通过串口发现写入的数据没有了! ...…

查看全部问答>

谁有usb驱动程序的源代码?

个位大侠: 我是刚自学usb驱动程序,正打算做usb驱动程序用于毕业设计. 求一个usb驱动程序源码做参考! 有意者请发一份给我!不慎感激!!! 我的e_mail:zhouq200418055@sina.com.cn…

查看全部问答>

一种神经信号调理电路的设计

人体的神经信号直接表征着人体自我的意思,研究神经信号为了解、识别人体提供了一条途径。多年来。目前,研究内容主要包括神经电极和神经信号调理电路两部分。神经电极可以将神经电信号从人体中提取出来,而神经信号调理电路则对神经信号进行去噪、 ...…

查看全部问答>

请问一个外部存储器总线读写的问题

把液晶控制器以总线连接方式接到2407DSP上,即     LCD 8位数据线 DB7-DB0 接到 DSP数据线 D15-D18 引脚               LCD的 R/W   接到 DSP地址线 A1 引脚   &nb ...…

查看全部问答>

C2000 Launchpad是否可以仿真其他带JTAG的TI MSP430

C2000 Launchpad是否可以仿真其他带JTAG的TI MSP430?? 因为都是JTAG的嘛,不知道行不行.…

查看全部问答>

14年第一天体验了下RTX-51 tiny

今天天气不错,早上看了下RXT-51的操作手册,下午写几行代码试了下,一次性通过。搞了个数码管显示温度的的。 #include #include unsigned int TEM() ; void DS18B20int() ; #define                ...…

查看全部问答>

搬家之后的工作台

本帖最后由 elvike 于 2014-8-21 20:27 编辑 搬家,今年第三次了。不过工作台大了一点。…

查看全部问答>