0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

如何快速读写MCU内部flash?

GReq_mcu168 来源:21ic网站 作者:binoo7 2022-03-28 10:06 次阅读

今天和大家分享一下STM32F103C8T6读写内部flash,关于103系列的单片机大家可以参考选项手册查看flash的容量。 一、芯片FLASH容量分类: c6126546-ae20-11ec-aa7f-dac502259ad0.png 可以看到我们今天介绍的这款芯片的flash大小是64K的,网上也有人说它可以支持到128K,但是官方给出的解释是前64K是有保证的,后面的无法保证,所以想要使用的小伙伴需要慎重。 现在芯片的flash大小我们知道了,下面就可以看看这个flash是怎么划分的了,通过芯片数据手册,我们能看到今天说的STM32F103C8T6是属于中等容量的设备。 c6343504-ae20-11ec-aa7f-dac502259ad0.png 既然是中等容量的设备了,那我们就来看看flash划分吧,在STM32的闪存编程手册中有这样一段话:按照不同容量,存储器组织成: 32个1K字节/页(小容量)128个1K字节/页(中容量)256个2K字节/页(大容量) 这段话怎么理解呢,就是告诉我们小容量的设备(内存是6K和32K)的设备是由1K字节每页组成的。 中容量的设备(内存是64K和128K)的设备是由1K字节每页组成的。大容量的设备(内存是256K、384K和512K)的设备是由2K字节每页组成的。 举个例子吧: 一个芯片的存储容量是64K,这64K是什么呢,就是64*1024个BYTE,一个BYTE是由8位0或1组成的,(比如0000 1111 这8个二进制数组成了一个字节,用十进制来说就是15) 小结一下:64K的flash可以存储64*1024个字节的数据。 咱们继续说,这64K的数据怎么划分,存储是按照页为单位进行存储的,一页1K的容量,也就说一页可以存储1024个字节。 一共是多少页? 答案是:64页,我们看一下官方是不是这么说的 c65f5c20-ae20-11ec-aa7f-dac502259ad0.png 在闪存编程手册里确实是这么说的,所以我们刚才说是64页是正确的 二、 读写步骤: 上面我们知道了芯片是怎么分类的,下面我们就重点来讲解一下芯片是怎么读写的。 内部flash我们参照HAL库或者标准库,直接调用ST公司给我们封装好的库进行编程就可以了,这里我用的是标准库,有兴趣的小伙伴可以去看看HAL库。 是不是有小伙伴会疑问什么是标准库,什么是HAL库? 在这里给大家解释一下,这两个库都是ST公司,直接把寄存器封装成函数,供大家直接调用某一个函数,就可以完成各种寄存器的配置,不容大家直面芯片的寄存器,方便阅读和使用,因为每个函数的名称功能都是不一样的,在调用前可以参考函数的注释,在F0和F4的标准库里甚至有每个函数的用法,不知道为什么在F1的库里把使用步骤去掉了。 咱们继续,读写的话库函数分为:
/*------------ Functions used for all STM32F10x devices -----*/void FLASH_SetLatency(uint32_t FLASH_Latency);void FLASH_HalfCycleAccessCmd(uint32_t FLASH_HalfCycleAccess);void FLASH_PrefetchBufferCmd(uint32_t FLASH_PrefetchBuffer);void FLASH_Unlock(void);void FLASH_Lock(void);FLASH_Status FLASH_ErasePage(uint32_t Page_Address);FLASH_Status FLASH_EraseAllPages(void);FLASH_Status FLASH_EraseOptionBytes(void);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);FLASH_Status FLASH_EnableWriteProtection(uint32_t FLASH_Pages);FLASH_Status FLASH_ReadOutProtection(FunctionalState NewState);FLASH_Status FLASH_UserOptionByteConfig(uint16_t OB_IWDG, uint16_t OB_STOP, uint16_t OB_STDBY);uint32_t FLASH_GetUserOptionByte(void);uint32_t FLASH_GetWriteProtectionOptionByte(void);
FlagStatus FLASH_GetReadOutProtectionStatus(void);FlagStatus FLASH_GetPrefetchBufferStatus(void);void FLASH_ITConfig(uint32_t FLASH_IT, FunctionalState NewState);FlagStatus FLASH_GetFlagStatus(uint32_t FLASH_FLAG);void FLASH_ClearFlag(uint32_t FLASH_FLAG);FLASH_Status FLASH_GetStatus(void);FLASH_Status FLASH_WaitForLastOperation(uint32_t Timeout);/*------------ New function used for all STM32F10x devices -----*/void FLASH_UnlockBank1(void);void FLASH_LockBank1(void);FLASH_Status FLASH_EraseAllBank1Pages(void);FLASH_Status FLASH_GetBank1Status(void);FLASH_StatusFLASH_WaitForLastBank1Operation(uint32_tTimeout);
在这里就不一个一个的详细说了,我们说一下常用的就行 1. 解锁void FLASH_Unlock(void); 2. 上锁void FLASH_Lock(void); 3. 页擦除FLASH_Status FLASH_ErasePage(uint32_t Page_Address); 4. 半字写入FLASH_Status FLASH_ProgramHalfWord(uint32_t Address, uint16_t Data); 上面这4个函数就是我们最常用的。 下面说一下数据写入的步骤: 第一步:解锁。 第二步:判断写入的数据是否被擦除过,也就是判断写入的地址内存放的是不是0xFFFF 这里要重点说一下,为什么要判断是不是0xFFFF而不是判断是不是0xFF呢?因为我们每次写入数据都要写入半字,也就是两个字节的数据才行,而且写入的地址只能是2的整数倍,不能是奇数。这里大家注意一下。 第三步:写入数据 STM32F103C8T6只能按照半字的方式进行数据写入,写入前的数据必须是0XFFFF,因为FLASH数据写入,只能写0,不能写1,这也就是为什么我们要先确保写入前的数据是被擦除了的原因。 第四步:上锁。 第五步:验证写入是否正确。 其实第五步可以省略。 我们看看官方给的写入过程: c671fd76-ae20-11ec-aa7f-dac502259ad0.png 好了,其实是一样的。下面我就和大家来分享一下(百分之九十九参考的正点原子的例程)。
//不检查的写入//WriteAddr:起始地址//pBuffer:数据指针//NumToWrite:半字(16位)数   void STMFLASH_Write_NoCheck(u32 WriteAddr,u16 *pBuffer,u16 NumToWrite)   {                                                   u16 i;        for(i=0;i        {                FLASH_ProgramHalfWord(WriteAddr,pBuffer);            WriteAddr+=2;//地址增加2.        }  }
//从指定地址开始写入指定长度的数据//WriteAddr:起始地址(此地址必须为2的倍数!!)//pBuffer:数据指针//NumToWrite:半字(16位)数(就是要写入的16位数据的个数.)u16 STMFLASH_BUF[STM_SECTOR_SIZE/2];//最多是2K字节void STMFLASH_Write(u32 WriteAddr,u16 *pBuffer,u16 NumToWrite)        {        u32 secpos;           //扇区地址        u16 secoff;           //扇区内偏移地址(16位字计算)        u16 secremain; //扇区内剩余地址(16位字计算)                    u16 i;            u32 offaddr;   //去掉0X08000000后的地址        if(WriteAddr=(STM32_FLASH_BASE+1024*STM32_FLASH_SIZE)))return;//非法地址        FLASH_Unlock();                                                //解锁        offaddr=WriteAddr-STM32_FLASH_BASE;                //实际偏移地址.        secpos=offaddr/STM_SECTOR_SIZE;                        //扇区地址  0~127 for STM32F103RBT6        secoff=(offaddr%STM_SECTOR_SIZE)/2;                //在扇区内的偏移(2个字节为基本单位.)        secremain=STM_SECTOR_SIZE/2-secoff;                //扇区剩余空间大小           if(NumToWrite<=secremain)        {          secremain=NumToWrite;//不大于该扇区范围        }        while(1)         {                        STMFLASH_Read(((secpos*STM_SECTOR_SIZE)+STM32_FLASH_BASE),STMFLASH_BUF,STM_SECTOR_SIZE/2);//读出整个扇区的内容                for(i=0;i//校验数据//                for(i=0;i<(STM_SECTOR_SIZE/2);i++)//校验数据                {                        if(STMFLASH_BUF[secoff+i]!=0XFFFF)break;//需要擦除  //        if(STMFLASH_BUF!=0XFFFF)break;//需要擦除                                         }                FLASH_ClearFlag(FLASH_FLAG_EOP | FLASH_FLAG_PGERR | FLASH_FLAG_WRPRTERR);                if(i//需要擦除//                if(i<(STM_SECTOR_SIZE/2))//需要擦除                {                        FLASH_ClearFlag(FLASH_FLAG_EOP | FLASH_FLAG_PGERR | FLASH_FLAG_WRPRTERR);                        FLASH_ErasePage(secpos*STM_SECTOR_SIZE+STM32_FLASH_BASE);//擦除这个扇区                        for(i=0;i//复制                        {                                STMFLASH_BUF[i+secoff]=pBuffer;                                  }                        STMFLASH_Write_NoCheck(secpos*STM_SECTOR_SIZE+STM32_FLASH_BASE,STMFLASH_BUF,STM_SECTOR_SIZE/2);//写入整个扇区                  }else STMFLASH_Write_NoCheck(WriteAddr,pBuffer,secremain);//写已经擦除了的,直接写入扇区剩余区间.                                                    if(NumToWrite==secremain)break;//写入结束了                else//写入未结束                {                                secpos++;                                //扇区地址增1                                secoff=0;                                //偏移位置为0                                            pBuffer+=secremain;          //指针偏移                                WriteAddr+=(secremain*2);        //写地址偏移                                            NumToWrite-=secremain;        //字节(16位)数递减                                if(NumToWrite>(STM_SECTOR_SIZE/2))                                {                                  secremain=STM_SECTOR_SIZE/2;//下一个扇区还是写不完                                }                                else                                 {                                   secremain=NumToWrite;//下一个扇区可以写完了                                }                }                 }                FLASH_Lock();//上锁}
最终我们调用STMFLASH_Write()函数进行数据的写入,是不是有没看懂的小伙伴,我给大家解释一下写入的过程吧。 这个STMFLASH_Write()函数,是说给定一个写入的地址、数据和写入的个数,然后按照给定的地址开始写数据,注意红色字体。 写数据是怎么做的呢? 首先是整理一下写入的页地址和需要写入多少页,每一页写入的话起始地址是什么然后开始一页一页的写,当遇到跨页写入的时候,把第二页的地址写进去,写的个数继续写入就行。 还有一个地方很重要,就是我修改了库函数:
/**  * [url=home.php?mod=space&uid=247401]@brief[/url]  Programs a half word at a specified address.  * [url=home.php?mod=space&uid=536309]@NOTE[/url]   This function can be used for all STM32F10x devices.  * @param  Address: specifies the address to be programmed.  * @param  Data: specifies the data to be programmed.  * @retval FLASH Status: The returned value can be: FLASH_ERROR_PG,  *         FLASH_ERROR_WRP, FLASH_COMPLETE or FLASH_TIMEOUT.   */FLASH_Status FLASH_ProgramHalfWord(uint32_t Address, uint16_t Data){        FLASH_ClearFlag(FLASH_FLAG_EOP | FLASH_FLAG_PGERR | FLASH_FLAG_WRPRTERR);  FLASH_Status status = FLASH_COMPLETE;  /* Check the parameters */  assert_param(IS_FLASH_ADDRESS(Address));#ifdef STM32F10X_XL  /* Wait for last operation to be completed */  status = FLASH_WaitForLastOperation(ProgramTimeout);  if(Address < FLASH_BANK1_END_ADDRESS)  {    if(status == FLASH_COMPLETE)    {      /* if the previous operation is completed, proceed to program the new data */      FLASH->CR |= CR_PG_Set;      *(__IO uint16_t*)Address = Data;      /* Wait for last operation to be completed */      status = FLASH_WaitForLastBank1Operation(ProgramTimeout);      /* Disable the PG Bit */      FLASH->CR &= CR_PG_Reset;    }  }  else  {    if(status == FLASH_COMPLETE)    {      /* if the previous operation is completed, proceed to program the new data */      FLASH->CR2 |= CR_PG_Set;      *(__IO uint16_t*)Address = Data;      /* Wait for last operation to be completed */      status = FLASH_WaitForLastBank2Operation(ProgramTimeout);      /* Disable the PG Bit */      FLASH->CR2 &= CR_PG_Reset;    }  }#else  /* Wait for last operation to be completed */  status = FLASH_WaitForLastOperation(ProgramTimeout);  if(status == FLASH_COMPLETE)  {    /* if the previous operation is completed, proceed to program the new data */    FLASH->CR |= CR_PG_Set;    *(__IO uint16_t*)Address = Data;    /* Wait for last operation to be completed */    status = FLASH_WaitForLastOperation(ProgramTimeout);    /* Disable the PG Bit */    FLASH->CR &= CR_PG_Reset;  } #endif  /* STM32F10X_XL */  /* Return the Program Status */  return status;}
大家能看出来吗?就是红色字体部分,增加了一个每次写入前清除所有异常状态。为什么添加这个呢? 因为,如果你写入的数据的地址没有擦除,你就写入的话会导致异常状态的发生,而这个异常状态时要手动清除的,如果你没有清除这个异常状态,而继续写入数据的话,那么你后面写入任何数据都会报错,均写不进去,所以我在这里增加了一个异常状态清除,如果前面写入的数据报错了,不会影响我接下来的数据写入。 这里大家就清除为什么了吧。 写数据会了,那么再说一下读数据,其实这里读数据要比外部flash读取容易的多,我们直接读取地址,返回的就是地址存放的数据,是不是很简单。 看下面的函数:
//读取指定地址的半字(16位数据)//faddr:读地址(此地址必须为2的倍数!!)//返回值:对应数据.u16 STMFLASH_ReadHalfWord(u32 faddr){        return *(vu16*)faddr; }//从指定地址开始读出指定长度的数据//ReadAddr:起始地址//pBuffer:数据指针//NumToWrite:半字(16位)数void STMFLASH_Read(u32 ReadAddr,u16 *pBuffer,u16 NumToRead)           {        u16 i;        for(i=0;i        {                pBuffer=STMFLASH_ReadHalfWord(ReadAddr);//读取2个字节.                ReadAddr+=2;//偏移2个字节.                }}
有没有很开心,读写数据就是这么简单就完成了。 以后如果我们想开发BootLoader、把剩余的flash利用起来,就都很简单了。我会把用到的数据手册当成附件挂到下面,大家可以自行下载。(点击“阅读原文”下载) 以后我们再一起学习其他的功能,最后打个广告,ST的芯片很给力,大家应该多支持,如果你觉得学到了知识的话,那么请留意评论谢谢。 审核编辑 :李倩

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 芯片
    +关注

    关注

    437

    文章

    44017

    浏览量

    403609
  • mcu
    mcu
    +关注

    关注

    142

    文章

    14490

    浏览量

    340791
  • FlaSh
    +关注

    关注

    9

    文章

    1407

    浏览量

    146209
收藏 人收藏

    评论

    相关推荐

    请问28335如何读写内部FLASH

    读写内部FLASH?谢谢!
    发表于 06-13 02:47

    stm32内部flash读写

    内部flash读写,stm32内部flash主要用于存储代码,应用程序就是通过下载器sh烧录到内部flash的,flash掉电不会丢失,芯片ch重新商店内核从flash中加载代码运行
    发表于 08-05 07:23

    如何对STM32内部Flash进行读写

    内部Flash进行读写呢?其程序是怎样去实现的?
    发表于 11-02 07:14

    读写STM32内部FLASH问题解析

    读写外挂FLASH芯片的,而是读写STM32内部FLASH的。我参考网上的资料写了 读写FLASH的程序,可是编译的时候很多错误。其中第一条的 没有声明FLASH_COMPLETE用这个
    发表于 01-09 16:46

    求助,请问如何读写M4内部Flash

    读写新唐M4内部Flash?我需要直接读写Flash,请问有相关的代码可以参考吗?谢谢。
    发表于 06-28 07:47

    51 系列单片机慢速读写的时序扩展

    速读写的时序扩展
    发表于 05-15 14:28 18次下载

    如何进行CPU内部Flash读写的实例资料说明

    内部Flash读写的实例资料说明。
    发表于 05-29 17:36 8次下载
    如何进行CPU<b>内部</b><b>Flash</b><b>读写</b>的实例资料说明

    STM32内部Flash读写问题

    Flash读写Flash调试技巧文章目录先熟悉所用MCUFlash存储大小以及扇区地址Flsah写之前为什么要先擦除Flash擦除长时间占用CPU实测Flash擦写占用的时间
    发表于 12-01 20:21 19次下载
    STM32<b>内部</b><b>Flash</b><b>读写</b>问题

    HAL库之读写STM32F103内部FLASH空间

    FLASH读写操作本文开发环境MCU型号:STM32F103C8T6IDE环境: MDK 5.25代码生成工具
    发表于 12-01 20:51 18次下载
    HAL库之<b>读写</b>STM32F103<b>内部</b>的<b>FLASH</b>空间

    如何使用Simplicity Studio查看MCU内部Flash的数据

    MCU开发工程师在产品开发和调试阶段,需要将MCU内部Flash存放的Code数据读取出来,来分析数据是否被异常更改。如果做过32位的Coretex-M内核MCU开发的工程师也肯定
    发表于 12-02 09:36 15次下载
    如何使用Simplicity Studio查看<b>MCU</b><b>内部</b><b>Flash</b>的数据

    STM32读写内部flash注意点

    读写内部flash注意点先说注意点怎么写怎么读的总结先说注意点1、写之前的第一步是要先解锁flash,解锁后最好清除下所有的flag,然后是擦除操作,然后是写,最后写完加锁保护
    发表于 12-02 11:21 7次下载
    STM32<b>读写</b><b>内部</b><b>flash</b>注意点

    STM32F4内部Flash读写

    内部Flash读写《STM32CubeMX之内部Flash读写》,F1系列的也是一样的。而F4系列的单片机与F0和F1略有不同,HAL库对应的函数也不...
    发表于 12-02 11:36 21次下载
    STM32F4<b>内部</b><b>Flash</b><b>读写</b>

    单片机内部Flash是Nor 还是Nand Flash

    Flash Memory,即平时所说的“闪存”。 Flash结合了ROM和RAM的长处,不仅具备电子可擦除可编程(EEPROM)的功能,还可以快速读取数据,具
    的头像 发表于 10-09 15:01 4477次阅读

    外置FLASH读写实验

    Flash,全名叫做Flash EEPROM Memory,即平时所说的“闪存”,它结合了ROM和RAM的长处,不仅可以反复擦除,还可以快速读取数据,STM32运行的程序其实就是存放在Flash当中
    的头像 发表于 03-01 14:56 3537次阅读

    STM32CUBEIDE(16)----内部Flash读写

    Flash进行读写,用芯片内部Flash可以对一些需要断电保存的数据进行保存,无需加外部得存储芯片,本例程采用的是STM32F103RBT6,128K大小的Flash
    的头像 发表于 07-27 09:24 527次阅读
    STM32CUBEIDE(16)----<b>内部</b><b>Flash</b><b>读写</b>