文章目录
- 一.概要
- 二.内部FLASH地址空间排布
- 三.内部FLASH主要特色
- 四.内部FLASH读写操作
- 1.FLASH数据读取
- 2.FLASH数据擦除
- 3.FLASH数据写入
- 五.内部FLASH的各种保护
- 1.写保护
- 2.读保护
- 六.FLASH读写例程
- 七.CubeMX工程源代码下载
- 八.小结
一.概要
STM32F103C8T6是一款强大而灵活的微控制器,它的片内Flash存储器可以用来存储有关代码和数据,在实际应用中,我们也需要对这个存储器进行读写操作。
STM32的FLASH主存储块按页组织,有的产品每页1KB,有的产品每页2KB。页面典型的用途就是用于按页擦除FLASH。从这点来看,页面有点像通用FLASH的扇区。
本文介绍了STM32F103C8T6的FLASH存储空间,FLASH数据的读写,以及读写保护等。
二.内部FLASH地址空间排布
根据用途,STM32片内的FLASH分成两部分:主存储块、信息块。
主存储块用于存储程序,我们写的程序一般存储在这里,用户还可以存储数据。
信息块又分成两部分:系统存储器、选项字节。 系统存储器存储用于存放在系统存储器自举模式下的启动程序(BootLoader),当使用ISP方式加载程序时,就是由这个程序执行。这个区域由芯片厂写入BootLoader,然后锁死,用户是无法改变这个区域的。 选项字节存储芯片的配置信息及对主存储块的保护信息,主要有写保护字节,读保护字节等。
STM32F103C8T6是中容量产品主存储块64-128KB, 每页1KB,系统存储器2KB(启动代码),存储空间如下图:
三.内部FLASH主要特色
四.内部FLASH读写操作
1.FLASH数据读取
内置闪存模块可以在通用地址空间直接寻址,任何32位数据的读操作都能访问闪存模块的内容并得到相应的数据。
以下是一个示例代码,展示了如何在C语言中读取STM32F103的内部Flash数据
// 假设我们要读取的数据在Flash地址0x8000000的位置
#define FLASH_ADDRESS 0x8000000
uint32_t data = (uint32_t)FLASH_ADDRESS;
2.FLASH数据擦除
STM32F103的FLASH在写入数据前确实需要先进行擦除操作。这是因为FLASH存储器的特性决定的,与其它FLASH存储器一样,STM32F103的FLASH也是按页(扇区)进行管理的,FLASH可以按页擦除,也可以整片擦除。
按页擦除操作流程:
3.FLASH数据写入
对主存储器数据写入每次可以写入16位。当FLASH_CR寄存器的PG位为’1’时,在一个闪存地址写入一个半字将启动一次编程;写入任何非半字的数据,都会产生总线错误。
FLASH数据写入操作流程:
五.内部FLASH的各种保护
1.写保护
STM32F103的FLASH写保护可以通过编程特定的选项字节来启用或禁用,以便保护特定的内存区域免受未经授权的写入,用于避免误写/误擦除操作。
对于STM32F103C8T6写保护是以WRPx选项字节每1比特位代表4页为单位实现的。
2.读保护
将Flash设置为读保护的目的,是为了防止其他人通过STLINK等仿真器,将Flash中的程序读取出来(设想一下,你辛辛苦苦研发的产品,别人通过仿真器将程序读取出来,再copy一下产品的硬件,就可以生产),所以可以通过将Flash设置为读保护来保护自己的程序。
读保护是通过设置RDP选择字节进行对FLASH的读保护。
六.FLASH读写例程
硬件准备:
STLINK接STM32F103C8T6小系统板,STLINK接电脑USB口。
打开STM32CubeMX软件,新建工程
Part Number处输入STM32F103C8,再双击就创建新的工程
配置下载口引脚
配置外部晶振引脚
配置系统主频
配置工程文件名,保存路径,KEIL5工程输出方式
生成工程
用Keil5打开工程
添加代码,FLASH解锁,FLASH写入,FLASH数据读取
#define FLASH_USER_START_ADDR (FLASH_BASE + (16 * FLASH_PAGE_SIZE)) //FLASH写入的起始地址,0x08004000
#define FLASH_USER_END_ADDR (FLASH_USER_START_ADDR + FLASH_PAGE_SIZE)//FLASH写入的结束地址
#define DATA_32 ((uint32_t)0x12345678)
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
uint32_t Address = 0, PAGEError = 0;//页管理变量
__IO uint32_t data32 = 0 , MemoryProgramStatus = 0;
/*Variable used for Erase procedure*/
static FLASH_EraseInitTypeDef EraseInitStruct;
/* USER CODE END PTD */
/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
/* USER CODE END PD */
/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */
/* USER CODE END PM */
/* Private variables ---------------------------------------------------------*/
/* USER CODE BEGIN PV */
/* USER CODE END PV */
/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
/* USER CODE BEGIN PFP */
/* USER CODE END PFP */
/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
/* USER CODE END 0 */
/**
* @brief The application entry point.
* @retval int
*/
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();//初始化1毫秒 Tick
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();//外部8M晶振,系统72M主频
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
/* USER CODE BEGIN 2 */
HAL_FLASH_Unlock();//FLASH解锁
/* Erase the user Flash area
(area defined by FLASH_USER_START_ADDR and FLASH_USER_END_ADDR) ***********/
/* Fill EraseInit structure*/
EraseInitStruct.TypeErase = FLASH_TYPEERASE_PAGES;
EraseInitStruct.PageAddress = FLASH_USER_START_ADDR;
EraseInitStruct.NbPages = (FLASH_USER_END_ADDR - FLASH_USER_START_ADDR) / FLASH_PAGE_SIZE;
if (HAL_FLASHEx_Erase(&EraseInitStruct, &PAGEError) != HAL_OK)//擦除FLASH
{
}
/* Program the user Flash area word by word
(area defined by FLASH_USER_START_ADDR and FLASH_USER_END_ADDR) ***********/
Address = FLASH_USER_START_ADDR;
while (Address < FLASH_USER_END_ADDR)
{
if (HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, Address, DATA_32) == HAL_OK)//把0x12345678写入0x08008000开始的地址
{
Address = Address + 4;
}
else
{
/* Error occurred while writing data in Flash memory.
User can add here some code to deal with this error */
}
}
/* Lock the Flash to disable the flash control register access (recommended
to protect the FLASH memory against possible unwanted operation) *********/
HAL_FLASH_Lock();//FLASH锁
/* Check if the programmed data is OK
MemoryProgramStatus = 0: data programmed correctly
MemoryProgramStatus != 0: number of words not programmed correctly ******/
Address = FLASH_USER_START_ADDR;
MemoryProgramStatus = 0x0;
while (Address < FLASH_USER_END_ADDR)//取出来比对
{
data32 = *(__IO uint32_t *)Address;
if (data32 != DATA_32)
{
MemoryProgramStatus++;
}
Address = Address + 4;
}
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
七.CubeMX工程源代码下载
通过百度网盘分享的文件:24.片上FLASH读写实验.rar
链接:https://pan.baidu.com/s/1-pvP7qU-0mCBnu-_EbZucw
提取码:gixg
如果链接失效,可以联系博主给最新链接
程序下载下来之后解压就行
八.小结
在STM32的开发过程中,保存用户数据、实现程序的自我更新等应用场景都离不开对FLASH读写操作。