OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 3323|回复: 5

STM32CubuIDE如何使用flash模拟errom?

[复制链接]

53

主题

567

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
2099
金钱
2099
注册时间
2017-2-11
在线时间
306 小时
发表于 2020-8-25 17:51:06 | 显示全部楼层 |阅读模式
2金钱
  目前我没看到如何通过STM32cubeIDE或者STM32cubeMX来生成flash操作文件,只能通过原子的HAL库例程来编写。

/*
* bsp_stmflash.c
*
*  Created on: Aug 25, 2020
*      Author: jiangyuanyuan
*/

#include "bsp_stmflash.h"

//读取指定地址的字(32位数据)
//faddr:读地址
//返回值:对应数据.
u32 STMFLASH_ReadWord(u32 faddr)
{
        return *(vu32*)faddr;
}

//获取某个地址所在的flash扇区
//addr:flash地址
//返回值:0~11,即addr所在的扇区
u8 STMFLASH_GetFlashSector(u32 addr)
{
        if(addr<ADDR_FLASH_SECTOR_1)return FLASH_SECTOR_0;
        else if(addr<ADDR_FLASH_SECTOR_2)return FLASH_SECTOR_1;
        else if(addr<ADDR_FLASH_SECTOR_3)return FLASH_SECTOR_2;
        else if(addr<ADDR_FLASH_SECTOR_4)return FLASH_SECTOR_3;
        else if(addr<ADDR_FLASH_SECTOR_5)return FLASH_SECTOR_4;
        else if(addr<ADDR_FLASH_SECTOR_6)return FLASH_SECTOR_5;
        else if(addr<ADDR_FLASH_SECTOR_7)return FLASH_SECTOR_6;
        else if(addr<ADDR_FLASH_SECTOR_8)return FLASH_SECTOR_7;
        else if(addr<ADDR_FLASH_SECTOR_9)return FLASH_SECTOR_8;
        else if(addr<ADDR_FLASH_SECTOR_10)return FLASH_SECTOR_9;
        else if(addr<ADDR_FLASH_SECTOR_11)return FLASH_SECTOR_10;
        return FLASH_SECTOR_11;
}

//从指定地址开始写入指定长度的数据
//特别注意:因为STM32F4的扇区实在太大,没办法本地保存扇区数据,所以本函数
//         写地址如果非0XFF,那么会先擦除整个扇区且不保存扇区数据.所以
//         写非0XFF的地址,将导致整个扇区数据丢失.建议写之前确保扇区里
//         没有重要数据,最好是整个扇区先擦除了,然后慢慢往后写.
//该函数对OTP区域也有效!可以用来写OTP区!
//OTP区域地址范围:0X1FFF7800~0X1FFF7A0F(注意:最后16字节,用于OTP数据块锁定,别乱写!!)
//WriteAddr:起始地址(此地址必须为4的倍数!!)
//pBuffer:数据指针
//NumToWrite:字(32位)数(就是要写入的32位数据的个数.)
void STMFLASH_Write(u32 WriteAddr,u32 *pBuffer,u32 NumToWrite)
{
        FLASH_EraseInitTypeDef FlashEraseInit;
        HAL_StatusTypeDef FlashStatus=HAL_OK;
        u32 SectorError=0;
        u32 addrx=0;
        u32 endaddr=0;
        if(WriteAddr<STM32_FLASH_BASE||WriteAddr%4)return;        //非法地址

        HAL_FLASH_Unlock();             //解锁
        addrx=WriteAddr;                                //写入的起始地址
        endaddr=WriteAddr+NumToWrite*4;        //写入的结束地址

        if(addrx<0X1FFF0000)
        {
                while(addrx<endaddr)                //扫清一切障碍.(对非FFFFFFFF的地方,先擦除)
                {
                         if(STMFLASH_ReadWord(addrx)!=0XFFFFFFFF)//有非0XFFFFFFFF的地方,要擦除这个扇区
                        {
                                FlashEraseInit.TypeErase=FLASH_TYPEERASE_SECTORS;       //擦除类型,扇区擦除
                                FlashEraseInit.Sector=STMFLASH_GetFlashSector(addrx);   //要擦除的扇区
                                FlashEraseInit.NbSectors=1;                             //一次只擦除一个扇区
                                FlashEraseInit.VoltageRange=FLASH_VOLTAGE_RANGE_3;      //电压范围,VCC=2.7~3.6V之间!!
                                if(HAL_FLASHEx_Erase(&FlashEraseInit,&SectorError)!=HAL_OK)
                                {
                                        break;//发生错误了
                                }
                                }else addrx+=4;
                                FLASH_WaitForLastOperation(FLASH_WAITETIME);                //等待上次操作完成
                }
        }
        FlashStatus=FLASH_WaitForLastOperation(FLASH_WAITETIME);            //等待上次操作完成
        if(FlashStatus==HAL_OK)
        {
                 while(WriteAddr<endaddr)//写数据
                 {
                        if(HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD,WriteAddr,*pBuffer)!=HAL_OK)//写入数据
                        {
                                break;        //写入异常
                        }
                        WriteAddr+=4;
                        pBuffer++;
                }
        }
        HAL_FLASH_Lock();           //上锁
}

//从指定地址开始读出指定长度的数据
//ReadAddr:起始地址
//pBuffer:数据指针
//NumToRead:字(32位)数
void STMFLASH_Read(u32 ReadAddr,u32 *pBuffer,u32 NumToRead)
{
        u32 i;
        for(i=0;i<NumToRead;i++)
        {
                pBuffer[i]=STMFLASH_ReadWord(ReadAddr);//读取4个字节.
                ReadAddr+=4;//偏移4个字节.
        }
}

//////////////////////////////////////////测试用///////////////////////////////////////////
//WriteAddr:起始地址
//WriteData:要写入的数据
void Test_Write(u32 WriteAddr,u32 WriteData)
{
        STMFLASH_Write(WriteAddr,&WriteData,1);//写入一个字
}

#define FLASH_SAVE_ADDR  0X08010000         //设置FLASH 保存地址(必须为4的倍数,且所在扇区,要大于本代码所占用到的扇区.
                                                                                //否则,写操作的时候,可能会导致擦除整个扇区,从而引起部分程序丢失.引起死机.
u8 write_buf[255] = {0};
#define TEXT_LENTH sizeof(write_buf)                                   //数组长度
#define SIZE TEXT_LENTH/4+((TEXT_LENTH%4)?1:0)
void stmflash_test(void)
{
        u8 read_buf[255] = {0};
        u8 i = 0;
        for(i=0;i<255;i++)
                write_buf[i] = i;
        printf("TEXT_LENTH = %d,SIZE = %d\r\n",TEXT_LENTH,SIZE);
        STMFLASH_Write(FLASH_SAVE_ADDR,(u32*)write_buf,SIZE);
        STMFLASH_Read(FLASH_SAVE_ADDR,(u32*)read_buf,SIZE);
        for(i=0;i<255;i++)
                printf("%2d\t",read_buf[i]);
}


/*
* bsp_stmflash.h
*
*  Created on: Aug 25, 2020
*      Author: jiangyuanyuan
*/

#ifndef INC_BSP_STMFLASH_H_
#define INC_BSP_STMFLASH_H_
#include "stm32f4xx_hal.h"
#include "bsp_sys.h"
#include "stdio.h"
//FLASH起始地址
#define STM32_FLASH_BASE 0x08000000         //STM32 FLASH的起始地址
#define FLASH_WAITETIME  50000          //FLASH等待超时时间

//FLASH 扇区的起始地址
#define ADDR_FLASH_SECTOR_0     ((u32)0x08000000)         //扇区0起始地址, 16 Kbytes
#define ADDR_FLASH_SECTOR_1     ((u32)0x08004000)         //扇区1起始地址, 16 Kbytes
#define ADDR_FLASH_SECTOR_2     ((u32)0x08008000)         //扇区2起始地址, 16 Kbytes
#define ADDR_FLASH_SECTOR_3     ((u32)0x0800C000)         //扇区3起始地址, 16 Kbytes
#define ADDR_FLASH_SECTOR_4     ((u32)0x08010000)         //扇区4起始地址, 64 Kbytes
#define ADDR_FLASH_SECTOR_5     ((u32)0x08020000)         //扇区5起始地址, 128 Kbytes
#define ADDR_FLASH_SECTOR_6     ((u32)0x08040000)         //扇区6起始地址, 128 Kbytes
#define ADDR_FLASH_SECTOR_7     ((u32)0x08060000)         //扇区7起始地址, 128 Kbytes
#define ADDR_FLASH_SECTOR_8     ((u32)0x08080000)         //扇区8起始地址, 128 Kbytes
#define ADDR_FLASH_SECTOR_9     ((u32)0x080A0000)         //扇区9起始地址, 128 Kbytes
#define ADDR_FLASH_SECTOR_10    ((u32)0x080C0000)         //扇区10起始地址,128 Kbytes
#define ADDR_FLASH_SECTOR_11    ((u32)0x080E0000)         //扇区11起始地址,128 Kbytes


u32 STMFLASH_ReadWord(u32 faddr);                          //读出字
void STMFLASH_Write(u32 WriteAddr,u32 *pBuffer,u32 NumToWrite);                //从指定地址开始写入指定长度的数据
void STMFLASH_Read(u32 ReadAddr,u32 *pBuffer,u32 NumToRead);                   //从指定地址开始读出指定长度的数据
//测试写入
void Test_Write(u32 WriteAddr,u32 WriteData);
void stmflash_test(void);
#endif /* INC_BSP_STMFLASH_H_ */

谁有很好的办法,通过STM32cubeIDE或者STM32cubeMX来生成flash操作文件?我是基于STM32cubeIDE编译器,编译得到的结果也是对的。

最佳答案

查看完整内容[请看2#楼]

/*bsp_stmflash.c*/ /*bsp_stmflash.h*/
正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

53

主题

567

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
2099
金钱
2099
注册时间
2017-2-11
在线时间
306 小时
 楼主| 发表于 2020-8-25 17:51:07 | 显示全部楼层
/*bsp_stmflash.c*/
  1. /*
  2. * bsp_stmflash.c
  3. *
  4. *  Created on: 2020年9月25日
  5. *      Author: jiangyuanyuan
  6. */

  7. #include "bsp_stmflash.h"

  8. //读取指定地址的字(32位数据)
  9. //faddr:读地址
  10. //返回值:对应数据.
  11. u32 STMFLASH_ReadWord(u32 faddr)
  12. {
  13.         return *(vu32*)faddr;
  14. }

  15. //获取某个地址所在的flash扇区
  16. //addr:flash地址
  17. //返回值:0~11,即addr所在的扇区
  18. u8 STMFLASH_GetFlashSector(u32 addr)
  19. {
  20.         if(addr<ADDR_FLASH_SECTOR_1)return FLASH_SECTOR_0;
  21.         else if(addr<ADDR_FLASH_SECTOR_2)return FLASH_SECTOR_1;
  22.         else if(addr<ADDR_FLASH_SECTOR_3)return FLASH_SECTOR_2;
  23.         else if(addr<ADDR_FLASH_SECTOR_4)return FLASH_SECTOR_3;
  24.         else if(addr<ADDR_FLASH_SECTOR_5)return FLASH_SECTOR_4;
  25.         else if(addr<ADDR_FLASH_SECTOR_6)return FLASH_SECTOR_5;
  26.         else if(addr<ADDR_FLASH_SECTOR_7)return FLASH_SECTOR_6;
  27.         else if(addr<ADDR_FLASH_SECTOR_8)return FLASH_SECTOR_7;
  28.         else if(addr<ADDR_FLASH_SECTOR_9)return FLASH_SECTOR_8;
  29.         else if(addr<ADDR_FLASH_SECTOR_10)return FLASH_SECTOR_9;
  30.         else if(addr<ADDR_FLASH_SECTOR_11)return FLASH_SECTOR_10;
  31.         return FLASH_SECTOR_11;
  32. }

  33. //从指定地址开始写入指定长度的数据
  34. //特别注意:因为STM32F4的扇区实在太大,没办法本地保存扇区数据,所以本函数
  35. //         写地址如果非0XFF,那么会先擦除整个扇区且不保存扇区数据.所以
  36. //         写非0XFF的地址,将导致整个扇区数据丢失.建议写之前确保扇区里
  37. //         没有重要数据,最好是整个扇区先擦除了,然后慢慢往后写.
  38. //该函数对OTP区域也有效!可以用来写OTP区!
  39. //OTP区域地址范围:0X1FFF7800~0X1FFF7A0F(注意:最后16字节,用于OTP数据块锁定,别乱写!!)
  40. //WriteAddr:起始地址(此地址必须为4的倍数!!)
  41. //pBuffer:数据指针
  42. //NumToWrite:字(32位)数(就是要写入的32位数据的个数.)
  43. void STMFLASH_Write(u32 WriteAddr,u32 *pBuffer,u32 NumToWrite)
  44. {
  45.         FLASH_EraseInitTypeDef FlashEraseInit;
  46.         HAL_StatusTypeDef FlashStatus=HAL_OK;
  47.         u32 SectorError=0;
  48.         u32 addrx=0;
  49.         u32 endaddr=0;
  50.         if(WriteAddr<STM32_FLASH_BASE||WriteAddr%4)return;        //非法地址

  51.         HAL_FLASH_Unlock();             //解锁
  52.         addrx=WriteAddr;                                //写入的起始地址
  53.         endaddr=WriteAddr+NumToWrite*4;        //写入的结束地址

  54.         if(addrx<0X1FFF0000)
  55.         {
  56.                 while(addrx<endaddr)                //扫清一切障碍.(对非FFFFFFFF的地方,先擦除)
  57.                 {
  58.                          if(STMFLASH_ReadWord(addrx)!=0XFFFFFFFF)//有非0XFFFFFFFF的地方,要擦除这个扇区
  59.                         {
  60.                                 FlashEraseInit.TypeErase=FLASH_TYPEERASE_SECTORS;       //擦除类型,扇区擦除
  61.                                 FlashEraseInit.Sector=STMFLASH_GetFlashSector(addrx);   //要擦除的扇区
  62.                                 FlashEraseInit.NbSectors=1;                             //一次只擦除一个扇区
  63.                                 FlashEraseInit.VoltageRange=FLASH_VOLTAGE_RANGE_3;      //电压范围,VCC=2.7~3.6V之间!!
  64.                                 if(HAL_FLASHEx_Erase(&FlashEraseInit,&SectorError)!=HAL_OK)
  65.                                 {
  66.                                         break;//发生错误了
  67.                                 }
  68.                                 }else addrx+=4;
  69.                                 FLASH_WaitForLastOperation(FLASH_WAITETIME);                //等待上次操作完成
  70.                 }
  71.         }
  72.         FlashStatus=FLASH_WaitForLastOperation(FLASH_WAITETIME);            //等待上次操作完成
  73.         if(FlashStatus==HAL_OK)
  74.         {
  75.                  while(WriteAddr<endaddr)//写数据
  76.                  {
  77.                         if(HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD,WriteAddr,*pBuffer)!=HAL_OK)//写入数据
  78.                         {
  79.                                 break;        //写入异常
  80.                         }
  81.                         WriteAddr+=4;
  82.                         pBuffer++;
  83.                 }
  84.         }
  85.         HAL_FLASH_Lock();           //上锁
  86. }

  87. //从指定地址开始读出指定长度的数据
  88. //ReadAddr:起始地址
  89. //pBuffer:数据指针
  90. //NumToRead:字(32位)数
  91. void STMFLASH_Read(u32 ReadAddr,u32 *pBuffer,u32 NumToRead)
  92. {
  93.         u32 i;
  94.         for(i=0;i<NumToRead;i++)
  95.         {
  96.                 pBuffer[i]=STMFLASH_ReadWord(ReadAddr);//读取4个字节.
  97.                 ReadAddr+=4;//偏移4个字节.
  98.         }
  99. }

  100. //////////////////////////////////////////测试用///////////////////////////////////////////
  101. //WriteAddr:起始地址
  102. //WriteData:要写入的数据
  103. void Test_Write(u32 WriteAddr,u32 WriteData)
  104. {
  105.         STMFLASH_Write(WriteAddr,&WriteData,1);//写入一个字
  106. }

  107. #define FLASH_SAVE_ADDR  0X08010000         //设置FLASH 保存地址(必须为4的倍数,且所在扇区,要大于本代码所占用到的扇区.
  108.                                                                                 //否则,写操作的时候,可能会导致擦除整个扇区,从而引起部分程序丢失.引起死机.
  109. #define TEXT_LENTH sizeof(write_buf)                                   //数组长度
  110. #define SIZE TEXT_LENTH/4+((TEXT_LENTH%4)?1:0)
  111. void stmflash_test(void)
  112. {
  113.         u8 write_buf[255] = {0};
  114.         u8 read_buf[255] = {0};
  115.         u8 i = 0;
  116.         for(i=0;i<255;i++)
  117.                 write_buf[i] = i;
  118.         printf("TEXT_LENTH = %d,SIZE = %d\r\n",TEXT_LENTH,SIZE);
  119.         STMFLASH_Write(FLASH_SAVE_ADDR,(u32*)write_buf,SIZE);
  120.         STMFLASH_Read(FLASH_SAVE_ADDR,(u32*)read_buf,SIZE);
  121.         for(i=0;i<255;i++)
  122.                 printf(" %2d\t",read_buf[i]);
  123. }



复制代码


/*bsp_stmflash.h*/

  1. /*
  2. * bsp_stmflash.h
  3. *
  4. *  Created on: Aug 25, 2020
  5. *      Author: jiangyuanyuan
  6. */

  7. #ifndef INC_BSP_STMFLASH_H_
  8. #define INC_BSP_STMFLASH_H_
  9. #include "stm32f4xx_hal.h"
  10. #include "bsp_sys.h"
  11. #include "stdio.h"
  12. //FLASH起始地址
  13. #define STM32_FLASH_BASE 0x08000000         //STM32 FLASH的起始地址
  14. #define FLASH_WAITETIME  50000          //FLASH等待超时时间

  15. //FLASH 扇区的起始地址
  16. #define ADDR_FLASH_SECTOR_0     ((u32)0x08000000)         //扇区0起始地址, 16 Kbytes
  17. #define ADDR_FLASH_SECTOR_1     ((u32)0x08004000)         //扇区1起始地址, 16 Kbytes
  18. #define ADDR_FLASH_SECTOR_2     ((u32)0x08008000)         //扇区2起始地址, 16 Kbytes
  19. #define ADDR_FLASH_SECTOR_3     ((u32)0x0800C000)         //扇区3起始地址, 16 Kbytes
  20. #define ADDR_FLASH_SECTOR_4     ((u32)0x08010000)         //扇区4起始地址, 64 Kbytes
  21. #define ADDR_FLASH_SECTOR_5     ((u32)0x08020000)         //扇区5起始地址, 128 Kbytes
  22. #define ADDR_FLASH_SECTOR_6     ((u32)0x08040000)         //扇区6起始地址, 128 Kbytes
  23. #define ADDR_FLASH_SECTOR_7     ((u32)0x08060000)         //扇区7起始地址, 128 Kbytes
  24. #define ADDR_FLASH_SECTOR_8     ((u32)0x08080000)         //扇区8起始地址, 128 Kbytes
  25. #define ADDR_FLASH_SECTOR_9     ((u32)0x080A0000)         //扇区9起始地址, 128 Kbytes
  26. #define ADDR_FLASH_SECTOR_10    ((u32)0x080C0000)         //扇区10起始地址,128 Kbytes
  27. #define ADDR_FLASH_SECTOR_11    ((u32)0x080E0000)         //扇区11起始地址,128 Kbytes


  28. u32 STMFLASH_ReadWord(u32 faddr);                          //读出字
  29. void STMFLASH_Write(u32 WriteAddr,u32 *pBuffer,u32 NumToWrite);                //从指定地址开始写入指定长度的数据
  30. void STMFLASH_Read(u32 ReadAddr,u32 *pBuffer,u32 NumToRead);                   //从指定地址开始读出指定长度的数据
  31. //测试写入
  32. void Test_Write(u32 WriteAddr,u32 WriteData);
  33. void stmflash_test(void);
  34. #endif /* INC_BSP_STMFLASH_H_ */
复制代码
回复

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165475
金钱
165475
注册时间
2010-12-1
在线时间
2115 小时
发表于 2020-8-26 01:05:39 | 显示全部楼层
帮顶
回复

使用道具 举报

70

主题

6761

帖子

0

精华

论坛大神

Rank: 7Rank: 7Rank: 7

积分
13079
金钱
13079
注册时间
2012-11-26
在线时间
3809 小时
发表于 2020-8-26 08:56:35 | 显示全部楼层
没涉及到外设,CUBEMX也没法自动生成吧,自己移植一个读写函数,网上不少的
学无止境
回复

使用道具 举报

53

主题

567

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
2099
金钱
2099
注册时间
2017-2-11
在线时间
306 小时
 楼主| 发表于 2020-8-26 09:04:08 | 显示全部楼层
jermy_z 发表于 2020-8-26 08:56
没涉及到外设,CUBEMX也没法自动生成吧,自己移植一个读写函数,网上不少的

搜了很久,貌似没发现会自动生成,自己写的是可以的。只是看看有没有自动生成的方法。
回复

使用道具 举报

3

主题

312

帖子

0

精华

高级会员

Rank: 4

积分
907
金钱
907
注册时间
2011-10-19
在线时间
196 小时
发表于 2020-10-16 14:15:24 | 显示全部楼层
ST官方有个完善的用片内Flash模拟EEProm的库,使用该库就可以像EEProm一样不断的更新存储的数据而不用管如何擦除。
详见应用笔记AN4894:https://www.st.com/content/ccc/r ... s/en.DM00311483.pdf
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2025-4-29 23:25

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

快速回复 返回顶部 返回列表