STM32嵌入式FLASH擦除与写入
嵌入式Flash
Flash具有以下主要特性:
1.对于STM32F40x和 STM32F41x,容量高达1 MB;对于STM32F42x和STM32F43x,容量高达2MB。128位宽数据读取---------意思就是128/8=16(字节)
2.字节、半字、字和双字数据写入----对应一个字节,两个字节,四个字节,八个字节。(推荐以字读取和写入,即四个字节,刚好32位)
3.扇区擦除与全部擦除
扇区擦除就像你删除电脑的C盘内容,不删除D-F盘内容一样。
扇区擦除完的数据都为0XFF
4.存储器组织结构Flash 结构如下:
-主存储器块,分为4个16 KB扇区、1个64 KB扇区和7个128 KB扇区-系统存储器,器件在系统存储器自举模式下从该存储器启动
编程的时候,要注意写入数据是在哪个扇区,而且要知道扇区地址,不能够超过芯片的FLASH大小,例如你是512KB的,最多就到扇区7。
512字节OTP (一次性可编程,once time program),用于存储用户数据。OTP区域还有16个额外字节,用于锁定对应的OTP数据块。选项字节,用于配置读写保护、BOR级别、软件/硬件看门狗以及器件处于待机或停止模式下的复位。低功耗模式(有关详细信息,请参见参考手册的“电源控制(PWR)”部分)
STM32片内自带SRAM和FLASH,FLASH是用来存储程序的,SRAM是用来存储程序运行中的中间变量,通常不同型号的STM32的SRAM和FLASH大小是不相同的。例如STM32L431RCT6,SRAM容量大小为64KB,闪存FLASH的容量大小为256KB。
库函数的识别方法:硬件开头+大小写结合,ucos系统的代码量可能有100kb。
编程(根据固件库手册的例子进行模仿编写)
(1)解锁保护机制
(2)清空标志位
(3)获取扇区的起始地址和末地址(用于擦除扇区)
(4)使用循环,擦除扇区
(5)写入数据(一定要先擦除,才能写入数据)
(6)读取数据,验证是否正确写入
(7)锁定FLASH,进行保护
#include "stm32f4xx.h"
#include "stm32f4xx_gpio.h"
#include "stm32f4xx_rcc.h"
#include "stm32f4xx_usart.h"
#include "stdio.h"static GPIO_InitTypeDef GPIO_InitStructure;
static USART_InitTypeDef USART_InitStructure;
static NVIC_InitTypeDef NVIC_InitStructure; //重定义fputc函数
int fputc(int ch, FILE *f)
{ USART_SendData(USART1,ch);while(USART_GetFlagStatus(USART1,USART_FLAG_TXE)==RESET); return ch;
} void delay_us(uint32_t nus)
{ uint32_t temp; SysTick->LOAD =SystemCoreClock/8/1000000*nus; //时间加载 SysTick->VAL =0x00; //清空计数器SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk ; //使能滴答定时器开始倒数 do{temp=SysTick->CTRL;}while((temp&0x01)&&!(temp&(1<<16))); //等待时间到达 SysTick->CTRL&=~SysTick_CTRL_ENABLE_Msk; //关闭计数器SysTick->VAL =0X00; //清空计数器
}void delay_ms(uint16_t nms)
{ uint32_t temp; SysTick->LOAD=SystemCoreClock/8/1000*nms; //时间加载(SysTick->LOAD为24bit)SysTick->VAL =0x00; //清空计数器SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk ; //能滴答定时器开始倒数 do{temp=SysTick->CTRL;}while((temp&0x01)&&!(temp&(1<<16))); //等待时间到达 SysTick->CTRL&=~SysTick_CTRL_ENABLE_Msk; //关闭计数器SysTick->VAL =0X00; //清空计数器
} void USART1_Init(uint32_t baud)
{RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA,ENABLE); //使能GPIOA时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE); //使能USART1时钟//串口1对应引脚复用映射GPIO_PinAFConfig(GPIOA,GPIO_PinSource9,GPIO_AF_USART1); //GPIOA9复用为USART1GPIO_PinAFConfig(GPIOA,GPIO_PinSource10,GPIO_AF_USART1); //GPIOA10复用为USART1//USART1端口配置GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9 | GPIO_Pin_10; //GPIOA9与GPIOA10GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; //复用功能GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //速度50MHzGPIO_InitStructure.GPIO_OType = GPIO_OType_PP; //推挽复用输出GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; //上拉GPIO_Init(GPIOA,&GPIO_InitStructure); //初始化PA9,PA10//USART1 初始化设置USART_InitStructure.USART_BaudRate = baud; //波特率设置USART_InitStructure.USART_WordLength = USART_WordLength_8b; //字长为8位数据格式USART_InitStructure.USART_StopBits = USART_StopBits_1; //一个停止位USART_InitStructure.USART_Parity = USART_Parity_No; //无奇偶校验位USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; //无硬件数据流控制USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; //收发模式USART_Init(USART1, &USART_InitStructure); //初始化串口1USART_Cmd(USART1, ENABLE); //使能串口1 USART_ITConfig(USART1, USART_IT_RXNE, ENABLE); //开启相关中断//Usart1 NVIC 配置NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn; //串口1中断通道NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3; //抢占优先级3NVIC_InitStructure.NVIC_IRQChannelSubPriority =3; //子优先级3NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道使能NVIC_Init(&NVIC_InitStructure); //根据指定的参数初始化VIC寄存器
}uint32_t uwStartSector = 0;
uint32_t uwEndSector = 0;
uint32_t uwAddress = 0;
uint32_t uwSectorCounter = 0;__IO uint32_t uwData32 = 0;
__IO uint32_t uwMemoryProgramStatus = 0;//这些地址从F4中文手册的第三章FLASH可以查到
#define ADDR_FLASH_SECTOR_0 ((uint32_t)0x08000000) /* Base address of Sector 0, 16 Kbytes */
#define ADDR_FLASH_SECTOR_1 ((uint32_t)0x08004000) /* Base address of Sector 1, 16 Kbytes */
#define ADDR_FLASH_SECTOR_2 ((uint32_t)0x08008000) /* Base address of Sector 2, 16 Kbytes */
#define ADDR_FLASH_SECTOR_3 ((uint32_t)0x0800C000) /* Base address of Sector 3, 16 Kbytes */
#define ADDR_FLASH_SECTOR_4 ((uint32_t)0x08010000) /* Base address of Sector 4, 64 Kbytes */
#define ADDR_FLASH_SECTOR_5 ((uint32_t)0x08020000) /* Base address of Sector 5, 128 Kbytes */
#define ADDR_FLASH_SECTOR_6 ((uint32_t)0x08040000) /* Base address of Sector 6, 128 Kbytes */
#define ADDR_FLASH_SECTOR_7 ((uint32_t)0x08060000) /* Base address of Sector 7, 128 Kbytes */
#define ADDR_FLASH_SECTOR_8 ((uint32_t)0x08080000) /* Base address of Sector 8, 128 Kbytes */
#define ADDR_FLASH_SECTOR_9 ((uint32_t)0x080A0000) /* Base address of Sector 9, 128 Kbytes */
#define ADDR_FLASH_SECTOR_10 ((uint32_t)0x080C0000) /* Base address of Sector 10, 128 Kbytes */
#define ADDR_FLASH_SECTOR_11 ((uint32_t)0x080E0000) /* Base address of Sector 11, 128 Kbytes */#define ADDR_FLASH_SECTOR_12 ((uint32_t)0x08100000) /* Base address of Sector 12, 16 Kbytes */
#define ADDR_FLASH_SECTOR_13 ((uint32_t)0x08104000) /* Base address of Sector 13, 16 Kbytes */
#define ADDR_FLASH_SECTOR_14 ((uint32_t)0x08108000) /* Base address of Sector 14, 16 Kbytes */
#define ADDR_FLASH_SECTOR_15 ((uint32_t)0x0810C000) /* Base address of Sector 15, 16 Kbytes */
#define ADDR_FLASH_SECTOR_16 ((uint32_t)0x08110000) /* Base address of Sector 16, 64 Kbytes */
#define ADDR_FLASH_SECTOR_17 ((uint32_t)0x08120000) /* Base address of Sector 17, 128 Kbytes */
#define ADDR_FLASH_SECTOR_18 ((uint32_t)0x08140000) /* Base address of Sector 18, 128 Kbytes */
#define ADDR_FLASH_SECTOR_19 ((uint32_t)0x08160000) /* Base address of Sector 19, 128 Kbytes */
#define ADDR_FLASH_SECTOR_20 ((uint32_t)0x08180000) /* Base address of Sector 20, 128 Kbytes */
#define ADDR_FLASH_SECTOR_21 ((uint32_t)0x081A0000) /* Base address of Sector 21, 128 Kbytes */
#define ADDR_FLASH_SECTOR_22 ((uint32_t)0x081C0000) /* Base address of Sector 22, 128 Kbytes */
#define ADDR_FLASH_SECTOR_23 ((uint32_t)0x081E0000) /* Base address of Sector 23, 128 Kbytes *///这里就以6起始,7结束
#define FLASH_USER_START_ADDR ADDR_FLASH_SECTOR_6 /* Start address of user Flash area */#define FLASH_USER_END_ADDR ADDR_FLASH_SECTOR_7 /* End address of user Flash area *///获取扇区地址
static uint32_t GetSector(uint32_t Address)
{uint32_t sector = 0;if((Address < ADDR_FLASH_SECTOR_1) && (Address >= ADDR_FLASH_SECTOR_0)){sector = FLASH_Sector_0; }else if((Address < ADDR_FLASH_SECTOR_2) && (Address >= ADDR_FLASH_SECTOR_1)){sector = FLASH_Sector_1; }else if((Address < ADDR_FLASH_SECTOR_3) && (Address >= ADDR_FLASH_SECTOR_2)){sector = FLASH_Sector_2; }else if((Address < ADDR_FLASH_SECTOR_4) && (Address >= ADDR_FLASH_SECTOR_3)){sector = FLASH_Sector_3; }else if((Address < ADDR_FLASH_SECTOR_5) && (Address >= ADDR_FLASH_SECTOR_4)){sector = FLASH_Sector_4; }else if((Address < ADDR_FLASH_SECTOR_6) && (Address >= ADDR_FLASH_SECTOR_5)){sector = FLASH_Sector_5; }else if((Address < ADDR_FLASH_SECTOR_7) && (Address >= ADDR_FLASH_SECTOR_6)){sector = FLASH_Sector_6; }else if((Address < ADDR_FLASH_SECTOR_8) && (Address >= ADDR_FLASH_SECTOR_7)){sector = FLASH_Sector_7; }else if((Address < ADDR_FLASH_SECTOR_9) && (Address >= ADDR_FLASH_SECTOR_8)){sector = FLASH_Sector_8; }else if((Address < ADDR_FLASH_SECTOR_10) && (Address >= ADDR_FLASH_SECTOR_9)){sector = FLASH_Sector_9; }else if((Address < ADDR_FLASH_SECTOR_11) && (Address >= ADDR_FLASH_SECTOR_10)){sector = FLASH_Sector_10; }else if((Address < ADDR_FLASH_SECTOR_12) && (Address >= ADDR_FLASH_SECTOR_11)){sector = FLASH_Sector_11; }else if((Address < ADDR_FLASH_SECTOR_13) && (Address >= ADDR_FLASH_SECTOR_12)){sector = FLASH_Sector_12; }else if((Address < ADDR_FLASH_SECTOR_14) && (Address >= ADDR_FLASH_SECTOR_13)){sector = FLASH_Sector_13; }else if((Address < ADDR_FLASH_SECTOR_15) && (Address >= ADDR_FLASH_SECTOR_14)){sector = FLASH_Sector_14; }else if((Address < ADDR_FLASH_SECTOR_16) && (Address >= ADDR_FLASH_SECTOR_15)){sector = FLASH_Sector_15; }else if((Address < ADDR_FLASH_SECTOR_17) && (Address >= ADDR_FLASH_SECTOR_16)){sector = FLASH_Sector_16; }else if((Address < ADDR_FLASH_SECTOR_18) && (Address >= ADDR_FLASH_SECTOR_17)){sector = FLASH_Sector_17; }else if((Address < ADDR_FLASH_SECTOR_19) && (Address >= ADDR_FLASH_SECTOR_18)){sector = FLASH_Sector_18; }else if((Address < ADDR_FLASH_SECTOR_20) && (Address >= ADDR_FLASH_SECTOR_19)){sector = FLASH_Sector_19; }else if((Address < ADDR_FLASH_SECTOR_21) && (Address >= ADDR_FLASH_SECTOR_20)){sector = FLASH_Sector_20; } else if((Address < ADDR_FLASH_SECTOR_22) && (Address >= ADDR_FLASH_SECTOR_21)){sector = FLASH_Sector_21; }else if((Address < ADDR_FLASH_SECTOR_23) && (Address >= ADDR_FLASH_SECTOR_22)){sector = FLASH_Sector_22; }else/*(Address < FLASH_END_ADDR) && (Address >= ADDR_FLASH_SECTOR_23))*/{sector = FLASH_Sector_23; }return sector;
}int main(void)
{ char buf[128]={0};//使能GPIOG的硬件时钟RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOG, ENABLE);//系统定时器初始化,时钟源来自HCLK,且进行8分频,//系统定时器时钟频率=168MHz/8=21MHzSysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8); //设置中断优先级分组2NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//串口1,波特率115200bps,开启接收中断USART1_Init(115200);/* Enable the flash control register access ,使能FLASH寄存器的访问,解除保护机制*/FLASH_Unlock();/* Clear pending flags (if any) ,清空标志位*/ FLASH_ClearFlag(FLASH_FLAG_EOP | FLASH_FLAG_OPERR | FLASH_FLAG_WRPERR | FLASH_FLAG_PGAERR | FLASH_FLAG_PGPERR|FLASH_FLAG_PGSERR);
#if 1/* 通过扇区地址转换为扇区号,因为进行扇区擦除的时候,需要填写扇区的编号*/uwStartSector = GetSector(FLASH_USER_START_ADDR);uwEndSector = GetSector(FLASH_USER_END_ADDR);/* Strat the erase operation ,开始扇区擦除*/uwSectorCounter = uwStartSector;while (uwSectorCounter <= uwEndSector) {/* Device voltage range supposed to be [2.7V to 3.6V], the operation willbe done by word */ if (FLASH_EraseSector(uwSectorCounter, VoltageRange_3) != FLASH_COMPLETE){ /* Error occurred while sector erase. ,擦除错误User can add here some code to deal with this error */while (1){printf("Erase error\r\n");delay_ms(500);}}/* jump to the next sector */if (uwSectorCounter == FLASH_Sector_11){uwSectorCounter += 40;} else {uwSectorCounter += 8;}}//添加读取数据的代码,测试擦除完之后读到的值是?uwAddress = FLASH_USER_START_ADDR; //扇区6的起始地址while (uwAddress < FLASH_USER_END_ADDR){//指向扇区地址并取指就等同于读取数据uwData32 = *(__IO uint32_t*)uwAddress;//因为每次读取是4个字节,所以每次地址偏移4个字节uwAddress = uwAddress + 4;//[可选]打印一些调试信息,每偏移1000地址就打印一次数据if(uwAddress % 1000 ==0)printf("%8X \r\n",uwData32);} #endif/* Program the user Flash area word by word ,开始写入数据*//* area defined by FLASH_USER_START_ADDR and FLASH_USER_END_ADDR */uwAddress = FLASH_USER_START_ADDR; //扇区6的起始地址while (uwAddress < FLASH_USER_END_ADDR) //以扇区7的起始地址作为结束地址{//每次写入数据为0x12345678的时候以4字节也就是以字为单位if (FLASH_ProgramWord(uwAddress, 0x12345678) == FLASH_COMPLETE){//每写完一次,地址偏移4个字节uwAddress = uwAddress + 4;}else{ /* Error occurred while writing data in Flash memory,写入失败 User can add here some code to deal with this error */while (1){printf("Program error at addr %8X \r\n",uwAddress);delay_ms(500);}}}/* Lock the Flash to disable the flash control register access ,写入后,锁定FLASH*/FLASH_Lock(); /* Check if the programmed data is OK ,读取FLASH数据并进行校验*//* MemoryProgramStatus = 0: data programmed correctlyMemoryProgramStatus != 0: number of words not programmed correctly */uwAddress = FLASH_USER_START_ADDR;uwMemoryProgramStatus = 0;while (uwAddress < FLASH_USER_END_ADDR){//指向扇区地址并取指就等同于读取数据!!!!!!!!!!!!!!!!!!!!!!!!uwData32 = *(__IO uint32_t*)uwAddress;//读取到的数据不等于0x12345678的时候,就进行错误的计数if (uwData32 != 0x12345678){uwMemoryProgramStatus++; }//因为每次读取是4个字节,所以每次地址偏移4个字节uwAddress = uwAddress + 4;//[可选]打印一些调试信息,每偏移1000地址就打印一次数据if(uwAddress % 1000 ==0)printf("%8X \r\n",uwData32);} /* Check Data correctness ,最后进行数据错误计数输出*/if(uwMemoryProgramStatus){printf("Read check is not correct\r\n");}else{printf("Read check is correct\r\n"); }while(1){}
}
如何知道当前保存数据的数目﹖
方法1:将数据的数目保存到其他扇区或者其他地址。
方法2:当读取到数据为0xFF的时候,就是该区域没有被改写过。
STM32嵌入式FLASH擦除与写入相关推荐
- 基于STM32的Flash擦除方式
基于STM32的Flash擦除方式 前言 介绍 STM32 FLASH 闪存的编程和擦除 Flash擦除的标准库函数 软件设计 直接使用固件库函数擦除当前地址所在的内容 擦除对应地址和大小的Flash ...
- 嵌入式C语言STM32在FLASH中读取写入数据
STM32F4XX向指定FLASH地址读写 向FLASH中写入数据的主体思想就是先解锁,然后清标志位,然后找到要写入的地址,然后改变标志准备写入,然后在按已有的函数按地址一字节一字节的写入,最后要将F ...
- 基于飞思卡尔MC9S12XS的Flash擦除和写入操作
关于Flash的擦除和写入,真的是让我最费力的一部分,网上的相关资料很少,好不容易找到了一点相关代码,却发现程序不能正常的运行,而且更令人无解的是程序本身怎么检查都检查不出错误.好啦,一点一点的说说我 ...
- STM32:Flash擦除与读写操作(HAL库)
应用平台:STM32F030F4P6 ST官方库:STM32Cube_FW_F0_V1.9.0 背景知识 绝大多数的单片机和微控制器(ARM,x86),地址空间都是以字节为单位的,也就是说一个地址是一 ...
- STM32——FLASH擦除/写入失败的踩坑笔记。(WRPERR)
踩坑flash 操作失败. 查询标志位发现,是因为 WRPERR (写保护置位) 最后debug慢慢遍历程序找到了原因. 是因为对一个 未初始化的野指针 进行了赋值操作.野指针地址为flash地址.故 ...
- STM32内部Flash读写问题
STM32Flash读写之Flash调试技巧 文章目录 1.先熟悉所用MCU的Flash存储大小以及扇区地址 2.Flsah写之前为什么要先擦除 3.Flash擦除长时间占用CPU 4.实测Flash ...
- 基于STM32的Flash读写详解
基于STM32的Flash读取 前言 介绍 STM32 FLASH 闪存的编程和擦除 Flash读写的标准库函数 软件设计 FLASH的读取 直接读取某一地址的内容 读取选定位置的选定大小的内容 FL ...
- 用keil怎么擦除_分享STM32 FLASH 擦除(以及防止误擦除程序代码)、写入
编译环境:我用的是(Keil)MDK4.7.2 stm32库版本:我用的是3.5.0 一.本文不对FLASH的基础知识做详细的介绍,不懂得地方请查阅有关资料. 对STM32 内部FLASH进行编程操作 ...
- STM32操作访问flash,包括写入数据到flash和从flash读取数据
文章目录 序言:flash相关知识背景 一.FLASH操作流程与操作选址 1.1 FLASH操作流程 1.2 如何查找并选定要写入Flash十六进制地址 二.Flash基本知识点 2.1 Flash容 ...
最新文章
- Redis Cluster 介绍与搭建
- OpenGL 着色器的N体仿真
- system函数和popen函数使用方法
- java web开发技术大_2021年六大javaweb开发主流技术
- Linux Socket C语言网络编程:Pthread Socket [code from GitHub, for study]
- 生产环境 direct path read 与log file sync等待事件问题处理
- 《结对-结对编程项目作业名称-结对项目总结》
- 教你6步定制你的Ubuntu桌面
- 问题二十二:C++中怎么添加log开关
- php截取字符串utf8,php自定义截取中文字符串-utf8版
- BZOJ1934: [Shoi2007]Vote 善意的投票
- C语言基础2-C语言条件结构
- WINDOWS也需要装WINDOWS虚拟机
- 提取excel表数据成json格式的以及对图片重命名
- linux如何复制代码不乱码,网上复制代码要小心,很可能会带入乱码字符
- stokes方程matlab,Navier-Stokes matlab 238万源代码下载- www.pudn.com
- gbox推荐源_GBox
- 滑膜间充质干细胞复合壳聚糖水凝胶/角蛋白壳聚糖水凝胶复合材料/壳聚糖/海藻酸纳复合水凝胶的制备
- js获取0-1之间的随机数,获取1-10之间的随机数
- 人类dna信息量_如果有一个人的DNA序列等遗传信息数据,理论上能否克隆出这个人?需多少MB(兆字节)的信息量?...
热门文章
- Vue中修改element-ui中的el-table中默认的暂无数据样式
- 关于Flash Player 10 socket connection timeout
- serverlet 原理_容器原理架构详解(全)
- DOS游戏手柄键盘映射说明书
- seo点击软件,seo点击软件网站
- 4万高考冒名顶替事件_山东高考冒名顶替事件后续, 人民日报第一时间亮明态度!...
- mysql的print用法_e.printStackTrace();和log.error()的区别和用法
- 浅谈好未来的盈利模式
- win98 支持html5,穿越1999:如何装一台Win98时代的PC
- 使用STC-ISP软件生成定时器初始化函数遇到的问题