STM32小白入门(第14天)-------Flash

发布者:廿由人最新更新时间:2019-07-10 来源: eefocus关键字:STM32  Flash 手机看文章 扫描二维码
随时随地手机看文章

一、Flash概述


    闪存(Flash Memory)是一种长寿命的非易失性(在断电情况下仍能保持所存储的数据信息)的存储器。


用途:SD卡、固态硬盘、芯片内存存储单元存储代码。


二、内部FLASH特征


1、以分区形式进行规划,配置数据最好从最后扇区进行操作,防止覆盖扇区0的代码。


2、写入数据之前得先擦除数据,类似与读书时的黑板原理。



思考题1:擦除完之后,扇区里面所有的数据是什么?


答:所有的数据都是为0xFF,所有bit位都是1.


 


思考题2:假如说现在已经擦除完扇区,先写入了1个字节,然后在下一个偏移地址再次写入新的字节是否在需要擦除扇区?


答案:不需要的。


思考题3:假如说现在已经擦除完扇区,先写了1个字节,然后在同一个地址再次写入新的字节是否在需要擦除扇区?


答案:需要进行擦除!


例子,已经写入数据为0x12345678,然后再写入新的数据为0x1111111,最后得到的数据居然是0x101010.



#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 */


/* Base address of the Flash sectors */ 

#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 */


uint32_t uwStartSector = 0;

uint32_t uwEndSector = 0;

uint32_t uwAddress = 0;

uint32_t uwSectorCounter = 0;


__IO uint32_t uwData32 = 0;


//获取所在扇区

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/*(Address < FLASH_END_ADDR) && (Address >= ADDR_FLASH_SECTOR_11))*/

  {

    sector = FLASH_Sector_11;  

  }


  return sector;

}


//擦除扇区

void FLASH_Eraze(void)

{

//解锁闪存

/* Enable the flash control register access ,使能闪存控制寄存器的访问*/

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); 



/* Get the number of the start and end sectors,将扇区地址转换为扇区号 */

uwStartSector = GetSector(FLASH_USER_START_ADDR); //起始扇区为扇区6

uwEndSector = GetSector(FLASH_USER_END_ADDR); //结束扇区为扇区7

/* start the erase operation */

uwSectorCounter = uwStartSector;

//判断擦除是否已经到达结束扇区

while (uwSectorCounter <= uwEndSector) 

{

/* Device voltage range supposed to be [2.7V to 3.6V], the operation will

be done by word 

像手机升级的一样,必须保证电压稳定,同时看到如果擦除扇区,供电的电压必须为2.7V~3.6V

*/ 

if (FLASH_EraseSector(uwSectorCounter, VoltageRange_3) != FLASH_COMPLETE)

//擦除失败

printf("FLASH_EraseSector errorrn");

while (1);


}

/* jump to the next sector ,切换到下一个扇区*/

if (uwSectorCounter == FLASH_Sector_11)

{

uwSectorCounter += 40;

else 

{

uwSectorCounter += 8;

}

}

}


void FLASH_Wirte_Data(uint32_t data)

{

//对对应的地址写入数据,从扇区6开始写入数据

uwAddress = FLASH_USER_START_ADDR; //扇区6的起始地址

//判断当前的写入地址是否已经到达结束扇区地址

while (uwAddress < FLASH_USER_END_ADDR)

{

//对对应的地址写入4字节数据,全部数据位0x12345678

if (FLASH_ProgramWord(uwAddress, data) == FLASH_COMPLETE)

{

//写入成功后,地址偏移4个字节

uwAddress = uwAddress + 4;

}

else

//写入数据出问题,则将错误的地址进行打印

printf("FLASH_ProgramWord at %x errorrn",uwAddress);

while (1);


}

}


//写入完毕后,则进行锁定闪存,不允许任何的修改

FLASH_Lock(); 

}



void FLASH_Read_Data(void)

{

//从起始扇区开始读取

uwAddress = FLASH_USER_START_ADDR;


//判断读取数据的地址是否已经到达结束扇区

while (uwAddress < FLASH_USER_END_ADDR)

{

//读取数据

uwData32 = *(__IO uint32_t*)uwAddress;

if (uwData32 != 0x12345678)

{

printf("flash read at %X,val=%Xrn",uwAddress,uwData32);

}

//地址偏移4个字节

uwAddress = uwAddress + 4;

}

}


//在6扇区记录

void FLASH_Record(uint32_t data, uint32_t record_count)

{

//对对应的地址写入数据,从扇区6开始写入数据

//uwAddress = FLASH_USER_START_ADDR; //扇区6的起始地址

//一系列的字节数40

uwAddress = FLASH_USER_START_ADDR + uwRecordCounter + record_count*40;

//判断当前的写入地址是否已经到达结束扇区地址

if(uwAddress < FLASH_USER_END_ADDR)

{

uwRecordCounter = uwRecordCounter + 4;


//对对应的地址写入4字节数据

if (FLASH_ProgramWord(uwAddress, data) != FLASH_COMPLETE)

{

//写入数据出问题,则将错误的地址进行打印

printf("FLASH_ProgramWord at %x errorrn",uwAddress);

while (1);

}

while(uwRecordCounter == 40)

{

uwRecordCounter = 0;

}

}


//写入完毕后,则进行锁定闪存,不允许任何的修改

//FLASH_Lock(); 

}


//读取出记录

void Record_DataRead(uint32_t record_count)

{

uint32_t Read_buf[10] = {0};

uint32_t Read_buf_count = 0;

uint32_t times = 0;

//从起始扇区开始读取

uwAddress = FLASH_USER_START_ADDR;


//判断读取数据的地址是否已经count条记录 每条记录40字节

while (uwAddress < (FLASH_USER_START_ADDR+record_count*40))

{

for(Read_buf_count = 0; Read_buf_count < 10; Read_buf_count++)

{

//读取数据

Read_buf[Read_buf_count] = *(__IO uint32_t*)uwAddress;

//地址偏移4字节

uwAddress = uwAddress + 4;

}

times++;

//格式:[001]2017/10/14  9:40:12 Temp=30.0 Humi=92.0

printf("[%03d]20%x/%x/%x  %x:%x:%x Temp=%d.%d℃ Humi=%d.%drn",times,Read_buf[0],Read_buf[1],

Read_buf[2],Read_buf[3],Read_buf[4],

Read_buf[5],Read_buf[6],Read_buf[7],

Read_buf[8],Read_buf[9]);

}

printf("读取完毕rn");

}



关键字:STM32  Flash 引用地址:STM32小白入门(第14天)-------Flash

上一篇:STM32小白入门(第15天)-------低功耗
下一篇:STM32小白入门(第13天)-------RTC实时时钟和闹钟事件

推荐阅读最新更新时间:2024-11-05 06:44

使用Keil MDK运行第一个STM32程序
1.1.1 使用Keil MDK运行第一个STM32F10X程序 在上一小节中已经详细介绍了使用Keil MDK和标准外设库创建一个工程的过程,下面将介绍基于这个工程来编写一个小程序,通过这个程序我们可以初步了解: STM32标准外设库的简单使用过程 STM32外设的使用方法和大致流程 程序的编译、链接、下载步骤 利用Keil MDK的在线仿真功能进行软件仿真的简要步骤 1. 程序的编写 (1)程序实现的功能 为了方便各位读者的入门和理解,这个小程序的功能非常简单,作为本书功能实践的第一个程序,其功能当然也是最为经典的“Hello World!”了,只不过不是简单的屏幕输出,而是利用硬件的串口进行输出,同时作为单
[单片机]
使用Keil MDK运行第一个<font color='red'>STM32</font>程序
STM32串口通信:串口通信库
从箱底捞出来的f103,支持的c语言太基础,虽然性能很高,然而开发时间长难以快速的使用,一开始把 c++那些该有的都搬进来,结果当然是觉得有的函数都没有了。小小的写了一个库用来通过串口来DEBUG 一共有这几个函数,串口为PA9和PA10,在C8T6最小系统上面通过测试 Serial_Begin() 初始化USART,设定波特率 Serial_WriteLine() 传输数据并换行 Serial_Write() 传输数据,没有换行符 例: char str = { THIS IS STM32C8T6 }; void main() { Serial_Begin(115200); while(1) { Serial_Write
[单片机]
<font color='red'>STM32</font>串口通信:串口通信库
stm32变更外部晶振时时钟配置
学习野火的固件库UART1串口案例时,用的是SIM9008模块应用板上STM32103F103RB芯片,使用的外部晶振是12M。 串口读取的是乱码 默认的外部晶振是8M 由于stm32的库默认是外部晶振8M的情况下实现的,所以配置串口波特率的时候也是按8M,包括主频。 如果采用外部晶振8M或12M,配置时钟为72MHZ 。 1)在system32_stm32f10x.c文件中的void SetSysClockTo72(void)里这样改: 8M: RCC- CFGR |= (uint32_t)(RCC_CFGR_PLLSRC_HSE | RCC_CFGR_PLLMULL9);//8*9=72 12M: RCC- CFGR |=
[单片机]
关于STM32 GPIO配置模式
其实关于GPIO模式,手册有非常详细的说明,可见好好查看Datasheet有多么重要!! 首先关于stm32的GPIO口有输入输出之分,这点与51单片机使用的双向IO口有区别,这就需要根据我们具体是输入还是输出配置为相应的输入输出模式。输入就是输入模式,输出就是输出模式,两者不能混用。 下面这段话是手册这么描述GPIO口的: 通用I/O(GPIO) 复位期间和刚复位后,复用功能未开启, I/O端口被配置成浮空输入模式(CNFx =01b, MODEx =00b)。 复位后, JTAG引脚被置于输入上拉或下拉模式: ─ PA15: JTDI置于上拉模式 ─ PA14: JTCK置于下拉模式 ─ PA13: JTMS置于上拉模式 ─
[单片机]
关于<font color='red'>STM32</font> GPIO配置模式
解决STM32 I2C接口死锁在BUSY状态的方法讨论
关于STM32的I2C接口死锁在BUSY状态无法恢复的现象,网上已有很多讨论,看早几年比较老的贴子,有人提到复位MCU也无法恢复、只有断电才行的状况,那可是相当严重的问题。类似复位也无法恢复的情况是存在的,技术支持矢口否认问题存在,并不是正确面对问题的态度。比如我用这款F439芯片的SDRAM控制器,在错误操作后进入HardFault状态,复位无法恢复,JTAG也无法联机,只能断电重来,官方的Erratasheet里也提到了。 如果I2C接口无法可靠工作,那么所做的设计将存在严重隐患,不可能要求用户用断电的方法恢复系统。如果像某些网友提到弃用硬件I2C,转为GPIO模拟I2C时序,那么首先I2C时钟频率不易确定,因为STM32的时
[单片机]
stm32 数据类型的定义(常用的U8,U16,U32到底代表什么)
在Keil MDK 开发环境里,比如一个 无符号32位整形数据会有很多种表示方法: 1,unsigned int 32 (C语言标准表达方法) 2,uint32_t ; 3 ,u32; 这三种方式都是在表达同一个意思,可为什么ST的开发人员要搞的这么乱呢? 还有其他好多你可能看起来很陌生 ,很不好理解的表达方式, 如:_IO int32_t 他等同于vs32(这个你同样很陌生),不过他还等同于 volatile int32_t, 还等同于 volatile signed int 32; 最后这种表达方式才是C语言的标准表达方式,够乱吧,能把初学者弄的晕头转向。 u8,u16,u32都是unsigned char类型,不过u8是
[单片机]
STM32 上使用 printf 输出函数
如果要实现在串口 或者 LCD 上显示,必须重定义标准库函数里调用的与输出设备相关的函数。 如果使用 printf 输出到串口,需要将 fputc 里面的输出指向串口,这一过程就叫重定向。 那么如何让 STM32 使用 printf 函数呢?只需要将 fputc 里面的输 出指向 STM32 串口即可。 int fputc(int ch,FILE *p) //函数默认的,在使用 printf 函数时自动调用 { USART_SendData(USART1,(u8)ch); while(USART_GetFlagStatus(USART1,USART_FLAG_TXE)==RESET); return ch;
[单片机]
<font color='red'>STM32</font> 上使用 printf 输出函数
stm32的总线AMBA、AHB、APB
AMBA AMBA(Advanced Microprocessor Bus Architecture)是ARM公司提出的一种开放性的SoC总线标准,现在已经广泛的应用于RISC的内核上了。 AMBA定义了一种多总线系统(multilevel busing system),包括系统总线和等级稍低的外设总线。 AMBA支持32位、64位、128位的数据总线,和32位的地址总线,同时支持byte和half-word设计。 它定义了两种总线: AHB(Advanced High-performance Bus)先进的高性能总线,也叫做ASB(Advanced System Bus)。APB(Advanced peripheral Bus)
[单片机]
<font color='red'>stm32</font>的总线AMBA、AHB、APB
小广播
设计资源 培训 开发板 精华推荐

最新单片机文章
  • 学习ARM开发(16)
    ARM有很多东西要学习,那么中断,就肯定是需要学习的东西。自从CPU引入中断以来,才真正地进入多任务系统工作,并且大大提高了工作效率。采 ...
  • 学习ARM开发(17)
    因为嵌入式系统里全部要使用中断的,那么我的S3C44B0怎么样中断流程呢?那我就需要了解整个流程了。要深入了解,最好的方法,就是去写程序 ...
  • 学习ARM开发(18)
    上一次已经了解ARM的中断处理过程,并且可以设置中断函数,那么它这样就可以工作了吗?答案是否定的。因为S3C44B0还有好几个寄存器是控制中 ...
  • 嵌入式系统调试仿真工具
    嵌入式硬件系统设计出来后就要进行调试,不管是硬件调试还是软件调试或者程序固化,都需要用到调试仿真工具。 随着处理器新品种、新 ...
  • 最近困扰在心中的一个小疑问终于解惑了~~
    最近在驱动方面一直在概念上不能很好的理解 有时候结合别人写的一点usb的例子能有点感觉,但是因为arm体系里面没有像单片机那样直接讲解引脚 ...
  • 学习ARM开发(1)
  • 学习ARM开发(2)
  • 学习ARM开发(4)
  • 学习ARM开发(6)
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件
更多往期活动

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved