最新文章专题视频专题问答1问答10问答100问答1000问答2000关键字专题1关键字专题50关键字专题500关键字专题1500TAG最新视频文章推荐1 推荐3 推荐5 推荐7 推荐9 推荐11 推荐13 推荐15 推荐17 推荐19 推荐21 推荐23 推荐25 推荐27 推荐29 推荐31 推荐33 推荐35 推荐37视频文章20视频文章30视频文章40视频文章50视频文章60 视频文章70视频文章80视频文章90视频文章100视频文章120视频文章140 视频2关键字专题关键字专题tag2tag3文章专题文章专题2文章索引1文章索引2文章索引3文章索引4文章索引5123456789101112131415文章专题3
当前位置: 首页 - 正文

STM32内部FLASH读写操作详解

来源:动视网 责编:小OO 时间:2025-10-01 20:49:20
文档

STM32内部FLASH读写操作详解

STM32芯片内部的FLASH存储器,主要用于存储我们代码。如果内部FLASH存储完我们的代码还有剩余的空间,那么这些剩余的空间我们就可以利用起来,存储一些需要掉电保存的数据。本文以STM32103ZET6为例。STM32103ZET6属于大容量产品,其闪存模块组织如下:其主存储器大小为512KB,分为256页,每页大小都为2KB。我们的程序一般默认烧写到第0页的起始地址(0x08000000)处。当BOOT0引脚和BOOT1引脚都接GND时,就是从这个地址开始运行代码的。这个地址在keil中
推荐度:
导读STM32芯片内部的FLASH存储器,主要用于存储我们代码。如果内部FLASH存储完我们的代码还有剩余的空间,那么这些剩余的空间我们就可以利用起来,存储一些需要掉电保存的数据。本文以STM32103ZET6为例。STM32103ZET6属于大容量产品,其闪存模块组织如下:其主存储器大小为512KB,分为256页,每页大小都为2KB。我们的程序一般默认烧写到第0页的起始地址(0x08000000)处。当BOOT0引脚和BOOT1引脚都接GND时,就是从这个地址开始运行代码的。这个地址在keil中
STM32 芯片内部的 FLASH 存储器,主要用于存储我们代码。如果内部FLASH存储完我们的代码还有剩余的空间,那么这些剩余的空间我们就可以利用起来,存储一些需要掉电保存的数据。本文以STM32103ZET6为例。STM32103ZET6属于大容量产品,其闪存模块组织如下:

其主存储器大小为512KB,分为256页,每页大小都为2KB。我们的程序一般默认烧写到第0页的起始地址(0x08000000)处。

当BOOT0引脚和BOOT1引脚都接GND时,就是从这个地址开始运行代码的。这个地址在keil中可以看到:

假如我们要下载的程序大小为4.05KB,则第0、1、2页用于保存我们的程序,我们需要掉电保存的数据只能保存在第3~第255页这一部分空间内。

我们最终要下载的程序大小可在工程对应的.map文件中看到。.map文件可以双击工程的Target的名字快速打开,如:

下面对STM32内部FLASH进行简单的读写测试:

内部FLASH读写测试

流程图如下:

本流程图省略异常情况,只考虑成功的情况:

示例代码:

本例的关键代码如下(以读写第255页为例):

/*******************************************************************************************************

*------------------------------------------STM32 Demo---------------------------------------------------

*

*       工程说明:STM32内部FLASH实验

*        作    者:ZhengNian

*     博    客:zhengnianli.github.io

*        公 众 号:嵌入式大杂烩

*

********************************************************************************************************/

#define MAIN_CONFIG

#include "config.h"

/* STM32F103ZET6有256页,每一页的大小都为2KB */

#define ADDR_FLASH_PAGE_255     ((uint32_t)0x0807F800) /* Page255 2KB */

/* FLASH读写测试结果 */

#define  TEST_ERROR       -1    /* 错误(擦除、写入错误) */

#define  TEST_SUCCESS  0    /* 成功 */

#define  TEST_FAILED   1    /* 失败 */

/* Flash读写测试buf */

#define BufferSize 6

uint16_t usFlashWriteBuf[BufferSize] = {0x0101,0x0202,0x0303,0x0404,0x0505,0x0606};

uint16_t usFlashReadBuf[BufferSize] = {0};

/* 供本文件调用的函数声明 */

static int FlashReadWriteTest(void);                       

/*******************************************************************************************************

** 函数: main

**------------------------------------------------------------------------------------------------------

** 参数: void

** 返回: 无

** 说明: 主函数

********************************************************************************************************/

int main(void)

{

    /* 上电初始化 */

    SysInit();

    /* 内部Flash读写测试 */

    if (TEST_SUCCESS == FlashReadWriteTest())

    {

      printf("Flash test success!\\n");

    }

    else

    {

      printf("Flash test failed!\\n");

    }

    while (1)

    {}

}

/*******************************************************************************************************

** 函数: FlashReadWriteTest, 内部Flash读写测试函数

**------------------------------------------------------------------------------------------------------

** 参数: void

** 返回: TEST_ERROR:错误(擦除、写入错误)  TEST_SUCCESS:成功   TEST_FAILED:失败

** 说明: 无

********************************************************************************************************/

static int FlashReadWriteTest(void)

{

    uint32_t ucStartAddr;

    /* 解锁 */

    FLASH_Unlock();    

    /* 擦除操作 */

    ucStartAddr = ADDR_FLASH_PAGE_255;

    if (FLASH_COMPLETE != FLASH_ErasePage(ucStartAddr))

    {

        printf("Erase Error!\\n");

        return TEST_ERROR;

    }

    else

    {

        ucStartAddr = ADDR_FLASH_PAGE_255;

        printf("擦除成功,此时FLASH中值为:\\n");

for (int i = 0; i < BufferSize; i++)

        {

            usFlashReadBuf[i] = *(uint32_t*)ucStartAddr;

            printf("ucFlashReadBuf[%d] = 0x%.4x\\n", i, usFlashReadBuf[i]);

            ucStartAddr += 2;

        }

    }

    /* 写入操作 */

    ucStartAddr = ADDR_FLASH_PAGE_255;

    printf("\\n往FLASH中写入的数据为:\\n");

for (int i = 0; i < BufferSize; i++)

    {

        if (FLASH_COMPLETE != FLASH_ProgramHalfWord(ucStartAddr, usFlashWriteBuf[i]))

        {

            printf("Write Error!\\n");

            return TEST_ERROR;

        }

        printf("ucFlashWriteBuf[%d] = 0x%.4x\\n", i, usFlashWriteBuf[i]);

        ucStartAddr += 2;

    }

    /* 上锁 */

    FLASH_Lock();

    /* 读取操作 */

    ucStartAddr = ADDR_FLASH_PAGE_255;

    printf("\\n从FLASH中读出的数据为:\\n");

for (int i = 0; i < BufferSize; i++)

    {

        usFlashReadBuf[i] = *(__IO uint16_t*)ucStartAddr;

        printf("ucFlashReadBuf[%d] = 0x%.4x\\n", i, usFlashReadBuf[i]);

        ucStartAddr += 2;

    }

    /* 读出的数据与写入的数据做比较 */

for (int i = 0; i < BufferSize; i++)

    {

        if (usFlashReadBuf[i] != usFlashWriteBuf[i])

        {

            return TEST_FAILED;

        }

    }

    return TEST_SUCCESS;

}

/*********************************************************************************************************

**                            End Of File

********************************************************************************************************/

(1)进行解锁操作

STM32 的闪存编程是由内嵌的闪存编程/擦除控制器(FPEC)管理 ,这个模块包含的寄存器如下:

STM32 复位后, FPEC 模块是被保护的, 不能写入 FLASH_CR 寄存器;通过写入特定的序列到 FLASH_KEYR 寄存器可以打开 FPEC 模块(即写入 KEY1 和KEY2) , 只有在写保护被解除后, 我们才能操作相关寄存器。固件库中的函数为:

/* 解锁 */

void FLASH_Unlock(void);

(2)擦除将要写的页

STM32 的 FLASH 在编程的时候,也必须要求其写入地址的 FLASH 是被擦除了的(也就是其值必须是 0XFFFF),否则无法写入,在 FLASH_SR 寄存器的 PGERR 位将得到一个警告。

STM32 的闪存擦除分为两种:页擦除和整片擦除。也就是其最小擦除单位为1页,尽管你只需往某页里写10个字节数据或者更少的数据,你也必须先擦除该页(2*1024个字节)。我们这里使用按页擦除,固件库中按页擦除的函数为:

/* 按页擦除 */

FLASH_Status FLASH_ErasePage(uint32_t Page_Address);

其返回值为枚举:

typedef enum

{

  FLASH_BUSY = 1,   /* 忙 */

  FLASH_ERROR_PG,   /* 编程错误 */

  FLASH_ERROR_WRP,  /* 写保护错误 */

  FLASH_COMPLETE,   /* 操作完成 */

  FLASH_TIMEOUT     /* 操作超时 */

}FLASH_Status;

(3)往上一步擦写成功的页写入数据

STM32 闪存的编程每次必须写入16 位。虽然固件库中有如下三个写操作的函数:

FLASH_Status FLASH_ProgramWord(uint32_t Address, uint32_t Data);

FLASH_Status FLASH_ProgramHalfWord(uint32_t Address, uint16_t Data);

FLASH_Status FLASH_ProgramOptionByteData(uint32_t Address, uint8_t Data);

分别为按字(32bit)写入、按半字(16bit)写入、按字节(8bit)写入函数。32 位字节写入实际上是写入的两次 16 位数据,写完第一次后地址+2,这与我们前面讲解的 STM32 闪存的编程每次必须写入 16 位并不矛盾。写入 8 位实际也是占用的两个地址了,跟写入 16 位基本上没啥区别。

(4)写入操作完成后进行上锁操作

对FLASH进行写操作完成后要进行上锁操作,对应的固件库中函数为:

/* 上锁 */

void FLASH_Lock(void);

(5)读出数据

固件库中并没有与读操作的函数。读操作其实就是读取FLASH某个地址的数据。

(6)对比写入的数据与读出的数据是否相等

最后对比我们写入的数据与读出的数据是否完全一致,若一致则表明读写测试成功,否则失败。

程序执行结果:

可见,读出的数据与写入的数据一致,表明读写测试成功。

文档

STM32内部FLASH读写操作详解

STM32芯片内部的FLASH存储器,主要用于存储我们代码。如果内部FLASH存储完我们的代码还有剩余的空间,那么这些剩余的空间我们就可以利用起来,存储一些需要掉电保存的数据。本文以STM32103ZET6为例。STM32103ZET6属于大容量产品,其闪存模块组织如下:其主存储器大小为512KB,分为256页,每页大小都为2KB。我们的程序一般默认烧写到第0页的起始地址(0x08000000)处。当BOOT0引脚和BOOT1引脚都接GND时,就是从这个地址开始运行代码的。这个地址在keil中
推荐度:
  • 热门焦点

最新推荐

猜你喜欢

热门推荐

专题
Top