(39)STM32——FLASH闪存

这篇具有很好参考价值的文章主要介绍了(39)STM32——FLASH闪存。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

目录

学习目标

成果展示 

介绍

组成

主存储器

系统存储器

OTP 区域

选项字节

读取

 编程

寄存器

步骤

擦除

扇区擦除

批量擦除

寄存器

代码 

总结 


学习目标

        本节我们要来介绍一下关于FLASH闪存的知识,也是有关存储部分的知识,和之前学的EEPROM类似。FLASH结合了ROM和RAM的长处,不仅具备电子可擦除可编程(EEPROM)的性能,还可以快速读取数据(NVRAM的优势),使数据不会因为断电而丢失。

成果展示 

介绍

        不同型号的 STM32F40xx/41xx,其 FLASH 容量也有所不同,最小的只有 128K 字节,最大的则达到了 1024K 字节。探索者 STM32F4 开发板选择的 STM32F407ZGT6 的 FLASH 容量为 1024K 字节,STM32F40xx/41xx 的闪存模块组织如图所示:

(39)STM32——FLASH闪存

组成

         STM32F4 的闪存模块由:主存储器、系统存储器、OPT 区域和选项字节等 4 部分组成,接下来我们就来详细介绍一下各个部分。

主存储器

        该部分用来存放代码和数据常数(如 const 类型的数据)。分为 12 个扇区,前 4 个扇区为 16KB 大小,然后扇区 4 是 64KB 大小,扇区 5~11 是128K 大小,不同容量的 STM32F4, 拥有的扇区数不一样,比如STM32F407ZGT6,则拥有全部 12 个扇区。从上图可以看出主存储器的起始地址就是 0X08000000, B0、B1 都接 GND 的时候,就是从 0X08000000 开始 运行代码的。

系统存储器

        主要用来存放 STM32F4 的 bootloader 代码,此代码是出厂的时候就固化在 STM32F4 里面了,专门来给主存储器下载代码的。当 B0 接 V3.3,B1 接 GND 的时候,从该存储器启动(即进入串口下载模式)。

OTP 区域

        即一次性可编程区域,共 528 字节,被分成两个部分,前面 512 字节(32 字节为 1 块,分成 16 块),可以用来存储一些用户数据(永远不可以擦除), 后面 16 字节,用于锁定对应块。

选项字节

        用于配置读保护、BOR 级别、软件/硬件看门狗以及器件处于待机或停止模式下的复位。

        闪存存储器接口寄存器,该部分用于控制闪存读写等,是整个闪存模块的控制机构。

        在执行闪存写操作时,任何对闪存的读操作都会锁住总线,在写操作完成后读操作才能正确地进行;既在进行写或擦除操作时,不能进行代码或数据的读取操作。

读取

        STM23F4 的 FLASH 读取是很简单的。例如,我们要从地址 addr,读取一个字(字节为 8位,半字为 16 位,字为 32 位),可以通过如下的语句读取:

data=*(vu32*)addr;

        将 addr 强制转换为 vu32 指针,然后取该指针所指向的地址的值,即得到了 addr 地址的值。 类似的,将上面的 vu32 改为 vu16,即可读取指定地址的一个半字。相对 FLASH 读取来说, STM32F4 FLASH 的写就复杂一点了,下面我们介绍 STM32F4 闪存的编程和擦除。

        为了准确读取 Flash 数据, 必须根据 CPU 时钟 (HCLK) 频率和器件电源电压在 Flash 存取控制寄存器 (FLASH_ACR) 中正确地设置等待周期数 (LATENCY)。当电源电压低于 2.1V 时,必须关闭预取缓冲器。Flash 等待周期与 CPU 时钟频率之间的对应关系,如表所示:

        供电电压,我们一般是 3.3V,所以,在我们设置 168Mhz 频率作为 CPU 时钟之前,必须先设置 LATENCY 为 5,否则 FLASH 读写可能出错,导致死机。 

(39)STM32——FLASH闪存

 编程

  • 执行任何 Flash 编程操作(擦除或编程)时,CPU 时钟频率 (HCLK)不能低于 1 MHz。如果在 Flash 操作期间发生器件复位,无法保证 Flash 中的内容。
  • 在对 STM32F4 的 Flash 执行写入或擦除操作期间,任何读取 Flash 的尝试都会导致总线阻塞。只有在完成编程操作后,才能正确处理读操作。这意味着,写/擦除操作进行期间不能从 Flash 中执行代码或数据获取操作。

寄存器

  • FLASH 访问控制寄存器(FLASH_ACR)
  • FLASH 秘钥寄存器(FLASH_KEYR)
  • FLASH 选项秘钥寄存器(FLASH_OPTKEYR)
  • FLASH 状态寄存器(FLASH_SR)
  • FLASH 控制寄存器(FLASH_CR)
  • FLASH 选项控制寄存器(FLASH_OPTCR)

        STM32F4 复位后,FLASH 编程操作是被保护的,不能写入 FLASH_CR 寄存器;通过写入特定的序列(0X45670123 和 0XCDEF89AB)到 FLASH_KEYR 寄存器才可解除写保护,只有在写保护被解除后,我们才能操作相关寄存器。

  1. 写 0X45670123 到 FLASH_KEYR
  2. 写 0XCDEF89AB 到 FLASH_KEYR

        通过这两个步骤,即可解锁 FLASH_CR,如果写入错误,那么 FLASH_CR 将被锁定,直到下次复位后才可以再次解锁。

        STM32F4 闪存的编程位数可以通过 FLASH_CR 的 PSIZE 字段配置,PSIZE 的设置必须和电源电压匹配,由于我们开发板用的电压是 3.3V,所以 PSIZE 必须设置为 10,即 32 位并行位数。擦除或 者编程,都必须以 32 位为基础进行,见表:

(39)STM32——FLASH闪存

        STM32F4 的 FLASH 在编程的时候,也必须要求其写入地址的 FLASH 是被擦除了的(也就是其值必须是 0XFFFFFFFF),否则无法写入,而且擦除是按片区来擦除的。

步骤

  • 检查 FLASH_SR 中的 BSY 位,确保当前未执行任何 FLASH 操作。
  • 将 FLASH_CR 寄存器中的 PG 位置 1,激活 FLASH 编程。
  • 针对所需存储器地址(主存储器块或 OTP 区域内)执行数据写入操作:
    • 并行位数为 x8 时按字节写入(PSIZE=00) 
    • 并行位数为 x16 时按半字写入(PSIZE=01)
    • 并行位数为 x32 时按字写入(PSIZE=02)(我们是这个)
    • 并行位数为 x64 时按双字写入(PSIZE=03)
  • 等待 BSY 位清零,完成一次编程。

        按以上四步操作,就可以完成一次 FLASH 编程。不过有几点要注意:

  1. 编程前,要确保 要写如地址的 FLASH 已经擦除。
  2. 要先解锁(否则不能操作 FLASH_CR)。
  3. 编程操作对 OPT 区域也有效,方法一模一样。

擦除

        我们在 STM32F4 的 FLASH 编程的时候,首先需要判断缩写地址是否被擦除了,所以,我们来介绍一下擦除操作,擦除主要分为扇区擦除和整片擦除,我们简单的来介绍一下扇区擦除。

扇区擦除

  1. 检查 FLASH_CR 的 LOCK 是否解锁,如果没有则先解锁
  2. 检查 FLASH_SR 寄存器中的 BSY 位,确保当前未执行任何 FLASH 操作
  3. 在 FLASH_CR 寄存器中,将 SER 位置 1,并从主存储块的 12 个扇区中选择要擦除的 扇区 (SNB)
  4. 将 FLASH_CR 寄存器中的 STRT 位置 1,触发擦除操作
  5. 等待 BSY 位清零

批量擦除

  1. 检查 FLASH_SR 寄存器中的 BSY 位,确保当前未执行任何 FLASH 操作
  2. 在 FLASH_CR 寄存器中,将 MER 位置 1
  3. 在 FLASH_CR 寄存器中,将 STRT 位置 1,触发擦除操作
  4. 等待 BSY 位清零

寄存器

        寄存器还是不详细介绍了,感兴趣的同学可以去看开发手册。

代码 

// stmflash.c
#include "stmflash.h"
#include "delay.h"
#include "usart.h" 

 
 
//读取指定地址的半字(16位数据) 
//faddr:读地址 
//返回值:对应数据.
u32 STMFLASH_ReadWord(u32 faddr)
{
	return *(vu32*)faddr; 
}  
//获取某个地址所在的flash扇区
//addr:flash地址
//返回值:0~11,即addr所在的扇区
uint16_t STMFLASH_GetFlashSector(u32 addr)
{
	if(addr<ADDR_FLASH_SECTOR_1)return FLASH_Sector_0;
	else if(addr<ADDR_FLASH_SECTOR_2)return FLASH_Sector_1;
	else if(addr<ADDR_FLASH_SECTOR_3)return FLASH_Sector_2;
	else if(addr<ADDR_FLASH_SECTOR_4)return FLASH_Sector_3;
	else if(addr<ADDR_FLASH_SECTOR_5)return FLASH_Sector_4;
	else if(addr<ADDR_FLASH_SECTOR_6)return FLASH_Sector_5;
	else if(addr<ADDR_FLASH_SECTOR_7)return FLASH_Sector_6;
	else if(addr<ADDR_FLASH_SECTOR_8)return FLASH_Sector_7;
	else if(addr<ADDR_FLASH_SECTOR_9)return FLASH_Sector_8;
	else if(addr<ADDR_FLASH_SECTOR_10)return FLASH_Sector_9;
	else if(addr<ADDR_FLASH_SECTOR_11)return FLASH_Sector_10; 
	return FLASH_Sector_11;	
}
//从指定地址开始写入指定长度的数据
//特别注意:因为STM32F4的扇区实在太大,没办法本地保存扇区数据,所以本函数
//         写地址如果非0XFF,那么会先擦除整个扇区且不保存扇区数据.所以
//         写非0XFF的地址,将导致整个扇区数据丢失.建议写之前确保扇区里
//         没有重要数据,最好是整个扇区先擦除了,然后慢慢往后写. 
//该函数对OTP区域也有效!可以用来写OTP区!
//OTP区域地址范围:0X1FFF7800~0X1FFF7A0F
//WriteAddr:起始地址(此地址必须为4的倍数!!)
//pBuffer:数据指针
//NumToWrite:字(32位)数(就是要写入的32位数据的个数.) 
void STMFLASH_Write(u32 WriteAddr,u32 *pBuffer,u32 NumToWrite)	
{ 
  FLASH_Status status = FLASH_COMPLETE;
	u32 addrx=0;
	u32 endaddr=0;	
  if(WriteAddr<STM32_FLASH_BASE||WriteAddr%4)return;	//非法地址,对于有效性进行判断
	FLASH_Unlock();									//解锁 
  FLASH_DataCacheCmd(DISABLE);//FLASH擦除期间,必须禁止数据缓存
 		
	addrx=WriteAddr;				//写入的起始地址
	endaddr=WriteAddr+NumToWrite*4;	//写入的结束地址
	if(addrx<0X1FFF0000)			//只有主存储区,才需要执行擦除操作!!
	{
		while(addrx<endaddr)		//扫清一切障碍.(对非FFFFFFFF的地方,先擦除)
		{
			if(STMFLASH_ReadWord(addrx)!=0XFFFFFFFF)//有非0XFFFFFFFF的地方,要擦除这个扇区
			{   
				status=FLASH_EraseSector(STMFLASH_GetFlashSector(addrx),VoltageRange_3);//VCC=2.7~3.6V之间!!
				if(status!=FLASH_COMPLETE)break;	//发生错误了
			}else addrx+=4;
		} 
	}
	if(status==FLASH_COMPLETE)
	{
		while(WriteAddr<endaddr)//写数据
		{
			if(FLASH_ProgramWord(WriteAddr,*pBuffer)!=FLASH_COMPLETE)//写入数据
			{ 
				break;	//写入异常
			}
			WriteAddr+=4;
			pBuffer++;
		} 
	}
  FLASH_DataCacheCmd(ENABLE);	//FLASH擦除结束,开启数据缓存
	FLASH_Lock();//上锁
} 

//从指定地址开始读出指定长度的数据
//ReadAddr:起始地址
//pBuffer:数据指针
//NumToRead:字(4位)数
void STMFLASH_Read(u32 ReadAddr,u32 *pBuffer,u32 NumToRead)   	
{
	u32 i;
	for(i=0;i<NumToRead;i++)
	{
		pBuffer[i]=STMFLASH_ReadWord(ReadAddr);//读取4个字节.
		ReadAddr+=4;//偏移4个字节.	
	}
}

//main.c
#include "sys.h"
#include "delay.h"
#include "usart.h"
#include "led.h"
#include "stmflash.h" 
#include "key.h"  

//要写入到STM32 FLASH的字符串数组
const u8 TEXT_Buffer[]={"STM32 FLASH TEST"};
#define TEXT_LENTH sizeof(TEXT_Buffer)	 		  	//数组长度	
#define SIZE TEXT_LENTH/4+((TEXT_LENTH%4)?1:0)

#define FLASH_SAVE_ADDR  0X0800C004 	//设置FLASH 保存地址(必须为偶数,且所在扇区,要大于本代码所占用到的扇区.
										//否则,写操作的时候,可能会导致擦除整个扇区,从而引起部分程序丢失.引起死机.
int main(void)
{ 
	u8 key=0;
	u16 i=0;
	u8 datatemp[SIZE];	
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置系统中断优先级分组2
	delay_init(168);  //初始化延时函数
	uart_init(115200);		//初始化串口波特率为115200
	
	LED_Init();					//初始化LED  
 	KEY_Init();					//按键初始化 ; 
	printf ("KEY1:Write  KEY0:Read");
	printf ("\r\n\r\n");
	while(1)
	{
		key=KEY_Scan(0);
		if(key==KEY1_PRES)	//KEY1按下,写入STM32 FLASH
		{ 
 			printf ("Start Write FLASH....");
			printf ("\r\n\r\n");
			STMFLASH_Write(FLASH_SAVE_ADDR,(u32*)TEXT_Buffer,SIZE);
			printf ("FLASH Write Finished!");//提示传送完成
			printf ("\r\n\r\n");
		}
		if(key==KEY0_PRES)	//KEY0按下,读取字符串并显示
		{
 			printf ("Start Read FLASH.... ");
			printf ("\r\n\r\n");
			STMFLASH_Read(FLASH_SAVE_ADDR,(u32*)datatemp,SIZE);
			printf ("The Data Readed Is: %s ",datatemp);//提示传送完成
			printf ("\r\n\r\n");
		}
		i++;
		delay_ms(10);  
		if(i==20)
		{
			LED0=!LED0;//提示系统正在运行	
			i=0;
		}		   
	}    
}

总结 

        这节FLASH的内容,难度不是特别大,但是感觉还是慢有用的,加深了之前学到的有关存储的知识 。文章来源地址https://www.toymoban.com/news/detail-474660.html

到了这里,关于(39)STM32——FLASH闪存的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • STM32 Flash学习(一)

    不同型号的STM32,其Flash容量也不同。 MiniSTM32开发板选择的STM32F103RCT6的FLASH容量为256K字节,属于大容量产品。 STM32的闪存模块由:主存储器、信息块和闪存存储器接口寄存器等3部分组成。 主存储器,该部分用来存放代码和数据常量(如const类型的数据)。 对于大容量产品,

    2024年02月15日
    浏览(39)
  • STM32 Flash学习(三)

    开机的时候先显示一些提示信息,然后在主循环里面检测两个按键。 其中1个按键WK_UP用来执行写入FLASH的操作,另一个按照KEY0用来执行读出操作。 添加了两个文件stmflash.c和stmflash.h。 STMFLASH_Write(u32 WriteAddr,u16 *pBuffer,u16 NumToWrite) 参数: WriteAddr:起始地址(必须为2的倍数)

    2024年02月15日
    浏览(38)
  • STM32CubeMX学习笔记16--- STM32内部FLASH

    1. 内部FLASH简介         之前的文章中介绍过STM32F1利用SPI与外部FLASH(W25QXX芯片)通讯的例程,本例程将介绍STM32F1的内部FLASH,通过内部FLASH实现数据读写操作。 不同型号的STM32,其FLASH容量也有所不同,最小的只有16K字节,最大的则达到了1024K字节。此处我们使用的是ST

    2024年04月09日
    浏览(41)
  • STM32 NOR_FLASH 学习

    FLASH是常用的,用于存储数据的半导体器件,它具有容量大,可重复擦写、按“扇区/块”擦除、掉电后数据可继续保存的特性。 NOR FLASH的单位是MB,EEPROM的单位是KB。 NM25Q128,是NOR FLASH的一种,是诺存公司生产的一种SPI FLASH,具有SPI接口。相似的还有W25Q128、BY25Q128,这三者都

    2024年02月07日
    浏览(27)
  • STM32案例学习 GY-39环境监测传感器模块

    野火STM32F1系列开发板 正点STM32F1系列开发板 STM32F103ZET6核心板 GY-39环境监测传感器模块 GY-39 是一款低成本,气压,温湿度,光强度传感器模块。工作电压 3-5v,功耗小,安装方便。 其工作原理是,MCU 收集各种传感器数据,统一处理,直接输出计算后的结果。此模块,有两种方

    2024年02月12日
    浏览(48)
  • STM32CubeMX学习笔记(48)——USB接口使用(MSC基于外部Flash模拟U盘)

    USB(Universal Serial BUS)通用串行总线 ,是一个外部总线标准,用于规范电脑与外部设备的连接和通讯。是应用在 PC 领域的接口技术。USB 接口支持设备的即插即用和热插拔功能。USB 是在 1994 年底由英特尔、康柏、IBM、Microsoft 等多家公司联合提出的。 USB 发展到现在已经有 US

    2024年01月16日
    浏览(48)
  • STM32CubeMX学习笔记(47)——USB接口使用(MSC基于内部Flash模拟U盘)

    USB(Universal Serial BUS)通用串行总线 ,是一个外部总线标准,用于规范电脑与外部设备的连接和通讯。是应用在 PC 领域的接口技术。USB 接口支持设备的即插即用和热插拔功能。USB 是在 1994 年底由英特尔、康柏、IBM、Microsoft 等多家公司联合提出的。 USB 发展到现在已经有 US

    2024年02月15日
    浏览(44)
  • [深入理解NAND Flash (原理篇)] Flash(闪存)存储器底层原理 | 闪存存储器重要参数

    传送门 总目录  所在专栏   《 深入理解SSD》 个人辛苦整理,付费内容,禁止转载。 内容摘要 从底层物理原理上了解 Nand Flash。 现代计算机构想是基于冯 · 诺依曼架构的图灵计算机设备,图灵从理论上去论证了现代计算机可以实现,也就是给现代计算机注入了灵魂,而冯

    2024年02月06日
    浏览(44)
  • 【FPGA】SPI读写FLASH闪存

    通信原理 SPI也是以主从方式工作,通常需要四根线来完成数据的传输,分别是MISO MOSI CS SCLK。以下是这四根线代表的含义: MISO:主设备输入,从设备输出 MOSI:主设备输出,从设备输入 CS :片选信号,选择进行通信的从设备 SCLK:时钟线,由主设备产生给到从设备 SPI通信的

    2024年02月16日
    浏览(37)
  • STM32笔记 Flash

    笔记来源于江科协议的视频 芯片采用与stm32F103C8T6 •STM32F1系列的FLASH包含程序存储器、系统存储器和选项字节三个部分,通过闪存存储器接口(外设)可以对程序存储器和选项字节进行擦除和编程,系统存储器里面存储的是BootLoader,是不允许修改的。 •读写FLASH的用途: 利

    2024年01月18日
    浏览(38)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包