嵌入式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擦除与写入相关推荐

  1. 基于STM32的Flash擦除方式

    基于STM32的Flash擦除方式 前言 介绍 STM32 FLASH 闪存的编程和擦除 Flash擦除的标准库函数 软件设计 直接使用固件库函数擦除当前地址所在的内容 擦除对应地址和大小的Flash ...

  2. 嵌入式C语言STM32在FLASH中读取写入数据

    STM32F4XX向指定FLASH地址读写 向FLASH中写入数据的主体思想就是先解锁,然后清标志位,然后找到要写入的地址,然后改变标志准备写入,然后在按已有的函数按地址一字节一字节的写入,最后要将F ...

  3. 基于飞思卡尔MC9S12XS的Flash擦除和写入操作

    关于Flash的擦除和写入,真的是让我最费力的一部分,网上的相关资料很少,好不容易找到了一点相关代码,却发现程序不能正常的运行,而且更令人无解的是程序本身怎么检查都检查不出错误.好啦,一点一点的说说我 ...

  4. STM32:Flash擦除与读写操作(HAL库)

    应用平台:STM32F030F4P6 ST官方库:STM32Cube_FW_F0_V1.9.0 背景知识 绝大多数的单片机和微控制器(ARM,x86),地址空间都是以字节为单位的,也就是说一个地址是一 ...

  5. STM32——FLASH擦除/写入失败的踩坑笔记。(WRPERR)

    踩坑flash 操作失败. 查询标志位发现,是因为 WRPERR (写保护置位) 最后debug慢慢遍历程序找到了原因. 是因为对一个 未初始化的野指针 进行了赋值操作.野指针地址为flash地址.故 ...

  6. STM32内部Flash读写问题

    STM32Flash读写之Flash调试技巧 文章目录 1.先熟悉所用MCU的Flash存储大小以及扇区地址 2.Flsah写之前为什么要先擦除 3.Flash擦除长时间占用CPU 4.实测Flash ...

  7. 基于STM32的Flash读写详解

    基于STM32的Flash读取 前言 介绍 STM32 FLASH 闪存的编程和擦除 Flash读写的标准库函数 软件设计 FLASH的读取 直接读取某一地址的内容 读取选定位置的选定大小的内容 FL ...

  8. 用keil怎么擦除_分享STM32 FLASH 擦除(以及防止误擦除程序代码)、写入

    编译环境:我用的是(Keil)MDK4.7.2 stm32库版本:我用的是3.5.0 一.本文不对FLASH的基础知识做详细的介绍,不懂得地方请查阅有关资料. 对STM32 内部FLASH进行编程操作 ...

  9. STM32操作访问flash,包括写入数据到flash和从flash读取数据

    文章目录 序言:flash相关知识背景 一.FLASH操作流程与操作选址 1.1 FLASH操作流程 1.2 如何查找并选定要写入Flash十六进制地址 二.Flash基本知识点 2.1 Flash容 ...

最新文章

  1. Redis Cluster 介绍与搭建
  2. OpenGL 着色器的N体仿真
  3. system函数和popen函数使用方法
  4. java web开发技术大_2021年六大javaweb开发主流技术
  5. Linux Socket C语言网络编程:Pthread Socket [code from GitHub, for study]
  6. 生产环境 direct path read 与log file sync等待事件问题处理
  7. 《结对-结对编程项目作业名称-结对项目总结》
  8. 教你6步定制你的Ubuntu桌面
  9. 问题二十二:C++中怎么添加log开关
  10. php截取字符串utf8,php自定义截取中文字符串-utf8版
  11. BZOJ1934: [Shoi2007]Vote 善意的投票
  12. C语言基础2-C语言条件结构
  13. WINDOWS也需要装WINDOWS虚拟机
  14. 提取excel表数据成json格式的以及对图片重命名
  15. linux如何复制代码不乱码,网上复制代码要小心,很可能会带入乱码字符
  16. stokes方程matlab,Navier-Stokes matlab 238万源代码下载- www.pudn.com
  17. gbox推荐源_GBox
  18. 滑膜间充质干细胞复合壳聚糖水凝胶/角蛋白壳聚糖水凝胶复合材料/壳聚糖/海藻酸纳复合水凝胶的制备
  19. js获取0-1之间的随机数,获取1-10之间的随机数
  20. 人类dna信息量_如果有一个人的DNA序列等遗传信息数据,理论上能否克隆出这个人?需多少MB(兆字节)的信息量?...

热门文章

  1. Vue中修改element-ui中的el-table中默认的暂无数据样式
  2. 关于Flash Player 10 socket connection timeout
  3. serverlet 原理_容器原理架构详解(全)
  4. DOS游戏手柄键盘映射说明书
  5. seo点击软件,seo点击软件网站
  6. 4万高考冒名顶替事件_山东高考冒名顶替事件后续, 人民日报第一时间亮明态度!...
  7. mysql的print用法_e.printStackTrace();和log.error()的区别和用法
  8. 浅谈好未来的盈利模式
  9. win98 支持html5,穿越1999:如何装一台Win98时代的PC
  10. 使用STC-ISP软件生成定时器初始化函数遇到的问题