datasheet

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

编辑:什么鱼 引用地址:http://www.eeworld.com.cn/mcu/ic467308.html
本网站转载的所有的文章、图片、音频视频文件等资料的版权归版权所有人所有,本站采用的非本站原创文章及图片等内容无法一一联系确认版权者。如果本网所选内容的文章作者及编辑认为其作品不宜公开自由传播,或不应无偿使用,请及时通过电子邮件或电话通知我们,以迅速采取适当措施,避免给双方造成不必要的经济损失。

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

关注eeworld公众号 快捷获取更多信息
关注eeworld公众号
快捷获取更多信息
关注eeworld服务号 享受更多官方福利
关注eeworld服务号
享受更多官方福利

推荐阅读

STM32 Systick定时器在实现1us延时时的问题与解决

问题:使用systick_config()函数来实现计数,这个函数在下面代码中的 SysTick_CTRL_TICKINT_Msk 开启了中断。不论系统时钟为72Mhz或36Mhz若设置STM32每10us进入一次中断,计时是可以的;而每1us进入中断,由于中断指令较多,那么程序就会困在中断里出不来。static __INLINE uint32_t SysTick_Config(uint32_t ticks){   if (ticks > SysTick_LOAD_RELOAD_Msk)  return (1);           
发表于 2019-07-17

stm32 ADC知识总结(二)

关于STM32的ADC的一些重要特点需要记住: 1)STM32F103系列至少有2个ADC,这些ADC可以独立使用,也可以使用双重模式(提高采样率); 2)STM32的ADC是12位逐次逼近型的模数转换器,一共有18个通道,可以测量16个外部信号和2个内部信号源; 3)每个通道的ADC可以在单次、连续、扫描或者间断模式下进行; 4)前面讲过STM32的ADC是12位的,结果存储在16位的数据寄存器中,有4位用不到,所以ADC存在左对齐或右对齐的方式; 5)模拟看门狗允许应用程序检测输入电压是否超出用户定义的高低阈值; 6)STM32的ADC最大的转换速率为1MHz
发表于 2019-07-17
stm32 ADC知识总结(二)

stm32f070 stop 模式 rtc定时启动调试总结

stm32f070 stop 模式 rtc定时启动调试总结。1.在进stoop模式之前一定对gpio进行配置。/* GPIO Ports Clock Enable */__HAL_RCC_GPIOA_CLK_ENABLE();__HAL_RCC_GPIOB_CLK_ENABLE();__HAL_RCC_GPIOF_CLK_ENABLE();/Configure GPIO pins : GPIO_PIN_All/GPIO_InitStruct.Pin = GPIO_PIN_All;GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;GPIO_InitStruct.Pull = GPIO_NOPULL
发表于 2019-07-17

RTC_WakeUp中断唤醒STM32F4停止模式

RTC_WakeUp唤醒STM32F4停止模式(借鉴的是原子哥写的代码): 首先我们先初始化RTC配置://RTC初始化u8 MyRTC_Init(void){    RTC_InitTypeDef RTC_InitStructrue;    u16 retry=0x1FFF;    RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR,ENABLE);//使能PWR时钟    PWR_BackupAccessCmd(ENABLE);//使能后备寄存器    if
发表于 2019-07-17

关于stm32stop模式下,串口唤醒中的问题及解决办法

首先讲一下应用场景:STM32F1 + HAL库+ Freertos ,STOP模式下利用串口引脚唤醒。stop mode 处理内容如下:1,配置所有引脚为模拟输入(参考官方代码)2,配置串口接收引脚为外部中断3,进入stop mode4,初始化串口等外设现象:第一次从stop模式唤醒时串口能正常通信,判断一段时间后无数据则再一次进入stop mode,然后再一次唤醒,此时串口无法输出。最后发现原因是串口重新初始化时HAL_UART_Init()函数中会判断if(huart->State == HAL_UART_STATE_RESET),此时才会执行HAL_UART_MspInit(huart),配置串口IO口。解决办法
发表于 2019-07-17

STM32开发笔记1: STM32F407时钟配置

单片机型号:STM32F407    本文讲解STMF407时钟的使用及其配置方法。        1、STM32F407的分类        a、LSI是低速内部时钟,RC震荡器,频率为32KHz左右。供独立看门狗和自动唤醒单元使用。        b、LSE是低速外部时钟,接频率为32.768KHz的石英晶体。这个主要是RTC的时钟源。        c、HSE是高速外部时钟,可接石英/陶瓷谐振器,或者接外部时钟源,频率范围
发表于 2019-07-17
STM32开发笔记1: STM32F407时钟配置

小广播

何立民专栏

单片机及嵌入式宝典

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

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