概念:计算机中最小的信息单位是bit,也就是一个二进制位,8个bit组成一个Byte,也就是1个字节,
1个存储单元存放1个字节,每个存储单元对应一个32位(bit)地址,所以重要的话说三遍:对于32bit的ARM CPU
一个32位地址指向1个字节!!! 一个32位地址指向1个字节!!! 一个32位地址指向1个字节!!!
我们常说的flash空间,多少多少K,指的是多少多少K byte
我使用的是STM32F030C8T6 的芯片 ,查询数据手册可知其flash的大小为64Kbytes,SRAM为8Kbytes
flash地址起始于0x0800 0000,结束地址是0x0800 0000加上芯片实际的flash大小,不同的芯片flash大小不同。
RAM起始地址是0x2000 0000,结束地址是0x2000 0000加上芯片的RAM大小。不同的芯片RAM也不同。
Flash中的内容一般用来存储代码和一些定义为const的数据,断电不丢失,
RAM可以理解为内存,用来存储代码运行时的数据,变量等等。掉电数据丢失。
STM32将外设等都映射为地址的形式,对地址的操作就是对外设的操作。
stm32的外设地址从0x4000 0000开始,可以看到在库文件中,是通过基于0x4000 0000地址的偏移量来操作寄存器以及外设的。
一般情况下,程序文件是从 0x0800 0000 地址写入,这个是STM32开始执行的地方,0x0800 0004是STM32的中断向量表的起始地址。
在使用keil进行编写程序时,其编程地址的设置一般是这样的:
程序的写入地址从0x08000000(数好零的个数)开始的,其大小为0x80000也就是512K的空间,换句话说就是告诉编译器flash的空间是从0x08000000-0x08080000,RAM的地址从0x20000000开始,大小为0x10000也就是64K的RAM。这与STM32的内存地址映射关系是对应的。
M3复位后,从0x08000004取出复位中断的地址,并且跳转到复位中断程序,中断执行完之后会跳到我们的main函数,main函数里边一般是一个死循环,进去后就不会再退出,当有中断发生的时候,M3将PC指针强制跳转回中断向量表,然后根据中断源进入对应的中断函数,执行完中断函数之后,再次返回main函数中。大致的流程就是这样。
对内部flash的写过程
1. 解锁(1) 往 Flash 密钥寄存器 FLASH_KEYR 中写入 KEY1 = 0x45670123
(2) 再往 Flash 密钥寄存器 FLASH_KEYR 中写入 KEY2 = 0xCDEF89AB
2. 数据操作位数
最大操作位数会影响擦除和写入的速度,其中 64 位宽度的操作除了配置寄存器位外,还需要在 Vpp 引脚外加一个 8-9V 的电压源,且其供电间不得超过一小时,否则 FLASH可能损坏,所以 64 位宽度的操作一般是在量产时对 FLASH 写入应用程序时才使用,大部分应用场合都是用 32 位的宽度。
3. 擦除扇区
在写入新的数据前,需要先擦除存储区域, STM32 提供了扇区擦除指令和整个FLASH 擦除(批量擦除)的指令,批量擦除指令仅针对主存储区。
扇区擦除的过程如下:
(1) 检查 FLASH_SR 寄存器中的“忙碌寄存器位 BSY”,以确认当前未执行任何
Flash 操作;
(2) 在 FLASH_CR 寄存器中,将“激活扇区擦除寄存器位 SER ”置 1,并设置“扇
区编号寄存器位 SNB”,选择要擦除的扇区;
(3) 将 FLASH_CR 寄存器中的“开始擦除寄存器位 STRT ”置 1,开始擦除;
(4) 等待 BSY 位被清零时,表示擦除完成。
4. 写入数据
擦除完毕后即可写入数据,写入数据的过程并不是仅仅使用指针向地址赋值,赋值前还还需要配置一系列的寄存器,步骤如下:
(1) 检查 FLASH_SR 中的 BSY 位,以确认当前未执行任何其它的内部 Flash 操作;
(2) 将 FLASH_CR 寄存器中的 “激活编程寄存器位 PG” 置 1;
(3) 针对所需存储器地址(主存储器块或 OTP 区域内)执行数据写入操作;
(4) 等待 BSY 位被清零时,表示写入完成。
5. 上锁
对内部flash的读过程
flash读取的过程比较简单,直接将flash地址中的值赋给自己定义的变量即可,注意地址一定要写正确
主题代码部分
主要实现的功能是:在flash中划分出1kb的空间来保存数据,起始地址为0x0800f800,结束地址为0x0800fc00 也就是说可以存放256个32bit的数据。在本程序中只存放了两个32bit数据 (其实定义了三个元素的数组,第0个数据的读取不正确,就从第1个数据开始保存)
flash.c文件
#include "flash.h"
/* Private define ------------------------------------------------------------*/
#define FLASH_PAGE_SIZE ((uint32_t)0x00000400) /* FLASH Page Size(1KB) */
#define FLASH_USER_START_ADDR ((uint32_t)0x0800F800) /* Start @ of user Flash area */
#define FLASH_USER_END_ADDR ((uint32_t)0x0800FC00) /* End @ of user Flash area */
#define COUNTER_MAX (sizeof(flashRom.data32)/sizeof(flashRom.data32[0])) //2
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
uint32_t Counter = 0x00, Address = 0x00;
//uint32_t Data = 0x3210ABCD;
uint32_t NbrOfPage = 0x00;
__IO FLASH_Status FLASHStatus = FLASH_COMPLETE;
//__IO TestStatus MemoryProgramStatus = PASSED;
/**************************************************
函数名称
功能
参数
返回值
作者
**************************************************/
uint8_t WriteFlash(void)
{
/* Unlock the Flash to enable the flash control register access *************/
FLASH_Unlock(); //解锁
/* Erase the user Flash area
(area defined by FLASH_USER_START_ADDR and FLASH_USER_END_ADDR) ***********/
/* Clear pending flags (if any) */ //清除flash待处理标志位
FLASH_ClearFlag(FLASH_FLAG_EOP | FLASH_FLAG_PGERR | FLASH_FLAG_WRPERR);
/* Define the number of page to be erased */ //要擦出的大小
NbrOfPage = (FLASH_USER_END_ADDR - FLASH_USER_START_ADDR) / FLASH_PAGE_SIZE;
/* Erase the FLASH pages */ //开始擦除
for(Counter = 0; (Counter < NbrOfPage) && (FLASHStatus == FLASH_COMPLETE); Counter++)
{
if (FLASH_ErasePage(FLASH_USER_START_ADDR + (FLASH_PAGE_SIZE * Counter))!= FLASH_COMPLETE)
{
/* Error occurred while sector erase.
User can add here some code to deal with this error */
FLASH_Lock();
return 1;
}
IWDG_ReloadCounter();
}
/* 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;
Counter = 0;
flashRom.cali.flashWritten = 0xA5; //表示已经在flash中写入数据
while (Address < FLASH_USER_END_ADDR && Counter < COUNTER_MAX)
{
if (FLASH_ProgramWord(Address, flashRom.data32[Counter]) == FLASH_COMPLETE) //¼ì²â flash²»Ã¦
{
Address = Address + 4;
Counter++;
}
else
{
/* Error occurred while writing data in Flash memory.
User can add here some code to deal with this error */
FLASH_Lock(); //数据写入完成 上锁
return 1;
}
IWDG_ReloadCounter();
}
/* Lock the Flash to disable the flash control register access (recommended
to protect the FLASH memory against possible unwanted operation) *********/
FLASH_Lock();
return 0;
}
/**************************************************
函数名称 FlashRead
功能
参数
返回值
作者
**************************************************/
void FlashRead(void)
{
Address = FLASH_USER_START_ADDR;
// MemoryProgramStatus = PASSED;
Counter = 0;
while (Address < FLASH_USER_END_ADDR && Counter < COUNTER_MAX)
{
flashRom.data32[Counter] = *(__IO uint32_t *)Address;
if(flashRom.cali.flashWritten != 0xA5)
{
flashRom.cali.check = 0x00; //无校准记录
break;
}
Address = Address + 4;
Counter++;
}
}
flash.h文件
#ifndef __FLASH_H
#define __FLASH_H
#include "stm32f0xx.h"
typedef enum //注意:该枚举变量已经在 库函数中定义过的,就将本文件中的删除。加上只是为了观赏性
{
FLASH_BUSY = 1,
FLASH_ERROR_WRP,
FLASH_ERROR_PROGRAM,
FLASH_COMPLETE,
FLASH_TIMEOUT
}FLASH_Status;
/* flash存储结构体 */
struct CalibrateStruct
{
// 32位为一个读写单位
uint8_t flashWritten; // 记录flash曾写入过,读取数据可用 记录值:0xA5
uint8_t check;
uint16_t __RESERVE0; // 保留 维持前32位的独立性
//以上部分保留不允许修改
};
/* flash存储联合体 */
union FlashRom
{
struct CalibrateStruct cali;
uint32_t data32[3]; //
};
#endif
本程序的问题:写入的第一个数据,读取不正确(不知道其中原因,望大神指点迷津)。所以从开始地址的第二个32位数开始保存有效数据
说明:本文章中的文字部分参考 https://blog.csdn.net/qq_33559992/article/details/77676716
其中添加自己的一部分东西。 代码部分为鄙人书写,实测可用