写在前面:
本文章旨在总结备份、方便以后查询,由于是个人总结,如有不对,欢迎指正;另外,内容大部分来自网络、书籍、和各类手册,如若侵权请告知,马上删帖致歉。
目录
一、内存大小
内存的容量一般都是 2的整次方倍,系统对内存的识别是以Byte(字节)为单位,每个字节由 8位二进制数组成,即 8bit(比特,也称“位”)。按照计算机的二进制方式,1Byte=8bit;1KB=1024Byte;1MB=1024KB;1GB=1024MB;1TB=1024GB。
除了字节,还有 “ 位 ” 和 “ 字长 ” 这些单位
- 位(Bit) :最小的存储单位(可以容纳0和1其中之一)
- 字节 (Byte):常用的计算机存储单位。1字节 = 8 位(这是字节的标准定义)
- 字(word) :即机器字长,是自然的存储单位。计算机是多少位的,一个字就有多少位。(如64位的机器,一个机器字长就是64位)
如果是一台 16位机,它的 1个字就由 2个字节构成,字长为 16位; 字长的长度是不固定的,对于不同的 CPU,字长的长度也不一样的;而 STM32是 32位机,所以它的 1个字就相当于 4个字节,那半个字(即字长大小的一半)为 2个字节(16 Bit)
二、STM32F103xx系列内存大小
更多的内存查看可以在选型手册中查找 STM32&STM8选型手册(pdf文档)
三、闪存概述
在 STM32F103xx系列中有高达512K字节的内置闪存存储器,用于存放程序和数据。因此,根据实际代码大小,我们可以利用剩下的内存对 Flash进行编程来存储一些特定的数据(例如:密码,专用的 ID码等),也可以用来模拟 EEPROM的使用
特性:
1、小容量
2、中容量
3、大容量
4、互联网型
更多详细的介绍可以看 STM32F10xxx闪存编程手册
四、写和擦除闪存
在执行闪存写(或擦除)操作时,任何对闪存的读操作都会锁住总线,在写(或擦除)操作完成后读操作才能正确地进行;既在进行写(或擦除)操作时,不能进行代码或数据的读取操作。
进行闪存编程操作时(写或擦除),必须打开内部的 RC振荡器(HSI)。
闪存存储器可以用 ICP或 IAP方式编程。
1、写操作
闪存编程一次可以支持写入16位(半字)。
流程图:
代码实现:
/************************************************
函数名称 : Flash_WritenHalfWord
功 能 : 向 Flash写半个字(16 bit)
参 数 : address ---- 地址位
Buff ---- 存储的数据
Len ---- 长度
返 回 值 : 0 / 1
*************************************************/
uint8_t Flash_WritenHalfWord( uint32_t addr, uint8_t *Buff, uint16_t Len )
{
volatile FLASH_Status FLASHStatus;
uint8_t k = 0;
uint32_t Address;
Address = WRITE_START_ADDR + addr;
FLASHStatus = FLASH_COMPLETE;
FLASH_Unlock(); //解锁
FLASH_ClearFlag(FLASH_FLAG_BSY | FLASH_FLAG_EOP | FLASH_FLAG_PGERR | FLASH_FLAG_WRPRTERR);//清除所有标志
FLASHStatus = FLASH_ErasePage(Address); //扇区擦除
if(FLASHStatus == FLASH_COMPLETE)
{
for(k = 0;(k<Len) && (FLASHStatus == FLASH_COMPLETE);k++)
{
FLASHStatus = FLASH_ProgramHalfWord(Address, *(Buff + k)); //写入半个字(16位)的数据入指定地址
Address = Address + 2; //地址偏移 2个字节
}
FLASH_Lock(); //重新上锁,防止误写入
}
else
{
return 0;
}
if(FLASHStatus == FLASH_COMPLETE)
{
return 1;
}
return 0;
}
2、擦除操作
闪存擦除操作可以按页面擦除或完全擦除(全擦除);全擦除不影响信息块。 为了确保不发生过度编程, 闪存编程和擦除控制器块是由一个固定的时钟控制的。 写操作(编程或擦除)结束时可以触发中断。仅当闪存控制器接口时钟开启时,此中断可以用来从WFI模式退出。
①页擦除流程图:
代码实现(官方封装的):
/**
* @brief Erases a specified FLASH page.
* @note This function can be used for all STM32F10x devices.
* @param Page_Address: The page address to be erased.
* @retval FLASH Status: The returned value can be: FLASH_BUSY, FLASH_ERROR_PG,
* FLASH_ERROR_WRP, FLASH_COMPLETE or FLASH_TIMEOUT.
*/
FLASH_Status FLASH_ErasePage(uint32_t Page_Address) // 页檫除
{
FLASH_Status status = FLASH_COMPLETE;
/* Check the parameters */
assert_param(IS_FLASH_ADDRESS(Page_Address));
#ifdef STM32F10X_XL
if(Page_Address < FLASH_BANK1_END_ADDRESS)
{
/* Wait for last operation to be completed */
status = FLASH_WaitForLastBank1Operation(EraseTimeout);
if(status == FLASH_COMPLETE)
{
/* if the previous operation is completed, proceed to erase the page */
FLASH->CR|= CR_PER_Set;
FLASH->AR = Page_Address;
FLASH->CR|= CR_STRT_Set;
/* Wait for last operation to be completed */
status = FLASH_WaitForLastBank1Operation(EraseTimeout);
/* Disable the PER Bit */
FLASH->CR &= CR_PER_Reset;
}
}
else
{
/* Wait for last operation to be completed */
status = FLASH_WaitForLastBank2Operation(EraseTimeout);
if(status == FLASH_COMPLETE)
{
/* if the previous operation is completed, proceed to erase the page */
FLASH->CR2|= CR_PER_Set;
FLASH->AR2 = Page_Address;
FLASH->CR2|= CR_STRT_Set;
/* Wait for last operation to be completed */
status = FLASH_WaitForLastBank2Operation(EraseTimeout);
/* Disable the PER Bit */
FLASH->CR2 &= CR_PER_Reset;
}
}
#else
/* Wait for last operation to be completed */
status = FLASH_WaitForLastOperation(EraseTimeout);
if(status == FLASH_COMPLETE)
{
/* if the previous operation is completed, proceed to erase the page */
FLASH->CR|= CR_PER_Set;
FLASH->AR = Page_Address;
FLASH->CR|= CR_STRT_Set;
/* Wait for last operation to be completed */
status = FLASH_WaitForLastOperation(EraseTimeout);
/* Disable the PER Bit */
FLASH->CR &= CR_PER_Reset;
}
#endif /* STM32F10X_XL */
/* Return the Erase Status */
return status;
}
②全擦除流程图:
代码实现(也是官方封装的):
/**
* @brief Erases all FLASH pages.
* @note This function can be used for all STM32F10x devices.
* @param None
* @retval FLASH Status: The returned value can be: FLASH_ERROR_PG,
* FLASH_ERROR_WRP, FLASH_COMPLETE or FLASH_TIMEOUT.
*/
FLASH_Status FLASH_EraseAllPages(void) // 全擦除
{
FLASH_Status status = FLASH_COMPLETE;
#ifdef STM32F10X_XL
/* Wait for last operation to be completed */
status = FLASH_WaitForLastBank1Operation(EraseTimeout);
if(status == FLASH_COMPLETE)
{
/* if the previous operation is completed, proceed to erase all pages */
FLASH->CR |= CR_MER_Set;
FLASH->CR |= CR_STRT_Set;
/* Wait for last operation to be completed */
status = FLASH_WaitForLastBank1Operation(EraseTimeout);
/* Disable the MER Bit */
FLASH->CR &= CR_MER_Reset;
}
if(status == FLASH_COMPLETE)
{
/* if the previous operation is completed, proceed to erase all pages */
FLASH->CR2 |= CR_MER_Set;
FLASH->CR2 |= CR_STRT_Set;
/* Wait for last operation to be completed */
status = FLASH_WaitForLastBank2Operation(EraseTimeout);
/* Disable the MER Bit */
FLASH->CR2 &= CR_MER_Reset;
}
#else
/* Wait for last operation to be completed */
status = FLASH_WaitForLastOperation(EraseTimeout);
if(status == FLASH_COMPLETE)
{
/* if the previous operation is completed, proceed to erase all pages */
FLASH->CR |= CR_MER_Set;
FLASH->CR |= CR_STRT_Set;
/* Wait for last operation to be completed */
status = FLASH_WaitForLastOperation(EraseTimeout);
/* Disable the MER Bit */
FLASH->CR &= CR_MER_Reset;
}
#endif /* STM32F10X_XL */
/* Return the Erase Status */
return status;
}
五、读操作
内置闪存模块可以在通用地址空间直接寻址,任何32位数据的读操作都能访问闪存模块的内容并得到相应的数据。
代码实现:
/************************************************
函数名称 : Flash_ReadHalfWord
功 能 : 从 Flash连续读半个字(16 bit)
参 数 : address ---- 地址位
Buff ---- 读取的数据
Len ---- 长度
返 回 值 : 无
*************************************************/
void Flash_ReadHalfWord( uint32_t addr, uint8_t *Buff, uint16_t Len )
{
uint8_t k;
uint32_t Address;
Address = WRITE_START_ADDR + addr;
for(k = 0;k < Len;k++)
{
*(Buff + k) = (*(vu32*) Address); //读指定地址的半个字的数据
Address += 2; //地址偏移 2个字节
}
}
/************************************************
函数名称 : ReadFlash_HalfWord
功 能 : 从 Flash读半个字(16 bit)
参 数 : address ---- 地址位
Buff ---- 读取的数据
Len ---- 长度
返 回 值 : 无
*************************************************/
uint16_t ReadFlash_HalfWord( uint32_t addr )
{
uint32_t Address;
Address = WRITE_START_ADDR + addr;
return (*(vu16*) Address); //读指定地址的半个字的数据
}
六、总代码实现
bsp_flash.c 源文件
#include "bsp_flash.h"
/************************************************
函数名称 : Flash_ReadHalfWord
功 能 : 从 Flash连续读半个字(16 bit)
参 数 : address ---- 地址位
Buff ---- 读取的数据
Len ---- 长度
返 回 值 : 无
*************************************************/
void Flash_ReadHalfWord( uint32_t addr, uint8_t *Buff, uint16_t Len )
{
uint8_t k;
uint32_t Address;
Address = WRITE_START_ADDR + addr;
for(k = 0;k < Len;k++)
{
*(Buff + k) = (*(vu32*) Address); //读指定地址的半个字的数据
Address += 2; //地址偏移 2个字节
}
}
/************************************************
函数名称 : Flash_WritenHalfWord
功 能 : 向 Flash写半个字(16 bit)
参 数 : address ---- 地址位
Buff ---- 存储的数据
Len ---- 长度
返 回 值 : 0 / 1
*************************************************/
uint8_t Flash_WritenHalfWord( uint32_t addr, uint8_t *Buff, uint16_t Len )
{
volatile FLASH_Status FLASHStatus;
uint8_t k = 0;
uint32_t Address;
Address = WRITE_START_ADDR + addr;
FLASHStatus = FLASH_COMPLETE;
FLASH_Unlock(); //解锁
FLASH_ClearFlag(FLASH_FLAG_BSY | FLASH_FLAG_EOP | FLASH_FLAG_PGERR | FLASH_FLAG_WRPRTERR);//清除所有标志
FLASHStatus = FLASH_ErasePage(Address); //扇区擦除
if(FLASHStatus == FLASH_COMPLETE)
{
for(k = 0;(k<Len) && (FLASHStatus == FLASH_COMPLETE);k++)
{
FLASHStatus = FLASH_ProgramHalfWord(Address, *(Buff + k)); //写入半个字(16位)的数据入指定地址
Address = Address + 2; //地址偏移 2个字节
}
FLASH_Lock(); //重新上锁,防止误写入
}
else
{
return 0;
}
if(FLASHStatus == FLASH_COMPLETE)
{
return 1;
}
return 0;
}
/************************************************
函数名称 : ReadFlash_HalfWord
功 能 : 从 Flash读半个字(16 bit)
参 数 : address ---- 地址位
Buff ---- 读取的数据
Len ---- 长度
返 回 值 : 无
*************************************************/
uint16_t ReadFlash_HalfWord( uint32_t addr )
{
uint32_t Address;
Address = WRITE_START_ADDR + addr;
return (*(vu16*) Address); //读指定地址的半个字的数据
}
/*---------------------------- END OF FILE ----------------------------*/
bsp_flash.h 头文件
#ifndef __BSP_FLASH_H
#define __BSP_FLASH_H
#include "stm32f10x.h"
/* STM32大容量产品每页大小2KByte,中、小容量产品每页大小1KByte */
#if defined (STM32F10X_HD) || defined (STM32F10X_HD_VL) || defined (STM32F10X_CL) || defined (STM32F10X_XL)
#define FLASH_PAGE_SIZE ((uint16_t)0x800) //2048
#else
#define FLASH_PAGE_SIZE ((uint16_t)0x400) //1024
#endif
// 写入的起始地址与结束地址
#define WRITE_START_ADDR ((uint32_t)0x08008000)
#define WRITE_END_ADDR ((uint32_t)0x0801FC00)
void Flash_ReadHalfWord( uint32_t addr, uint8_t *Buff, uint16_t Len );
uint8_t Flash_WritenHalfWord( uint32_t addr, uint8_t *Buff, uint16_t Len );
uint16_t ReadFlash_HalfWord( uint32_t addr );
#endif /* __BSP_FLASH_H */
/*---------------------------- END OF FILE ----------------------------*/