GD32F103读写内部FLASH

古城微笑少年丶 2022-09-08 13:51 773阅读 0赞

GD32F103读写内部FLASH


测试环境:

  • STM32F103C8
  • 20KBytes RAM
  • 64KBytes FLASH

30d0eb54199a4070970b0f09104896b2.png
watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_Q1NETiBAeS16aGVuZw_size_34_color_FFFFFF_t_70_g_se_x_16

watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_Q1NETiBAeS16aGVuZw_size_34_color_FFFFFF_t_70_g_se_x_16 1

头文件

  1. /** * @brief Create by AnKun on 2019/10/10 */
  2. #ifndef GDFLASH_H__
  3. #define GDFLASH_H__
  4. #include "gd32f10x.h"
  5. /// 移植修改区 ///
  6. /* FLASH大小:64K */
  7. #define GD32FLASH_SIZE 0X00010000UL
  8. /* FLASH起始地址 */
  9. #define GD32FLASH_BASE FLASH_BASE
  10. /* FLASH结束地址 */
  11. #define GD32FLASH_END (GD32FLASH_BASE | GD32FLASH_SIZE)
  12. /* FLASH页大小:1K */
  13. #define GD32FLASH_PAGE_SIZE (1024U)
  14. /* FLASH总页数 */
  15. #define GD32FLASH_PAGE_NUM (GD32FLASH_SIZE / GD32FLASH_PAGE_SIZE)
  16. /// 导出函数声明
  17. void FLASH_Init(void);
  18. uint32_t FLASH_Read(uint32_t Address, void *Buffer, uint32_t Size);
  19. uint32_t FLASH_Write(uint32_t Address, const uint16_t *Buffer, uint32_t NumToWrite);
  20. int FLASH_ErasePage(uint32_t PageAddress, uint32_t NbPages);
  21. uint32_t FLASH_WriteNotErase(uint32_t Address, const uint16_t *Buffer, uint32_t NumToWrite);
  22. #endif // !GDFLASH_H__

源文件

  1. /** * @file flash.c * * @brief Create by AnKun on 2019/10/10 * */
  2. #include "gdflash.h"
  3. #include <string.h>
  4. __align(4) static uint16_t FlashBuffer[GD32FLASH_PAGE_SIZE >> 1];
  5. /// 初始化FLASH
  6. void FLASH_Init(void)
  7. {
  8. fmc_unlock();
  9. fmc_flag_clear(FMC_FLAG_BANK0_END);
  10. fmc_flag_clear(FMC_FLAG_BANK0_WPERR);
  11. fmc_flag_clear(FMC_FLAG_BANK0_PGERR);
  12. fmc_lock();
  13. }
  14. /** * 读FLASH * @param Address 地址 * @param Buffer 存放读取的数据 * @param Size 要读取的数据大小,单位字节 * @return 读出成功的字节数 */
  15. uint32_t FLASH_Read(uint32_t Address, void *Buffer, uint32_t Size)
  16. {
  17. uint32_t nread = Size;
  18. uint8_t* d = (uint8_t *)Buffer;
  19. const uint8_t* s = (const uint8_t *)Address;
  20. if (!Buffer || Address < GD32FLASH_BASE || Address >= GD32FLASH_END)
  21. return 0;
  22. while (nread >= sizeof(uint32_t) && (((uint32_t)s) <= (GD32FLASH_END - 4)))
  23. {
  24. *(volatile uint32_t *)d = *(volatile uint32_t *)s;
  25. d += sizeof(uint32_t);
  26. s += sizeof(uint32_t);
  27. nread -= sizeof(uint32_t);
  28. }
  29. while (nread && (((uint32_t)s) < GD32FLASH_END))
  30. {
  31. *d++ = *s++;
  32. nread--;
  33. }
  34. return Size - nread;
  35. }
  36. /** * 写FLASH * @param Address 写入起始地址,!!!要求2字节对齐!!! * @param Buffer 待写入的数据,!!!要求2字节对齐!!! * @param NumToWrite 要写入的数据量,单位:半字,!!!要求2字节对齐!!! * @return 实际写入的数据量,单位:字节 */
  37. uint32_t FLASH_Write(uint32_t Address, const uint16_t *Buffer, uint32_t NumToWrite)
  38. {
  39. uint32_t i = 0;
  40. uint32_t pagepos = 0; // 页位置
  41. uint32_t pageoff = 0; // 页内偏移地址
  42. uint32_t pagefre = 0; // 页内空余空间
  43. uint32_t offset = 0; // Address在FLASH中的偏移
  44. uint32_t nwrite = NumToWrite; // 记录剩余要写入的数据量
  45. const uint16_t *pBuffer = (const uint16_t *)Buffer;
  46. /* 非法地址 */
  47. if (Address < GD32FLASH_BASE || Address > (GD32FLASH_END - 2) || NumToWrite == 0 || pBuffer == NULL)
  48. return 0;
  49. /* 解锁FLASH */
  50. fmc_unlock();
  51. /* 计算偏移地址 */
  52. offset = Address - GD32FLASH_BASE;
  53. /* 计算当前页位置 */
  54. pagepos = offset / GD32FLASH_PAGE_SIZE;
  55. /* 计算要写数据的起始地址在当前页内的偏移地址 */
  56. pageoff = ((offset % GD32FLASH_PAGE_SIZE) >> 1);
  57. /* 计算当前页内空余空间 */
  58. pagefre = ((GD32FLASH_PAGE_SIZE >> 1) - pageoff);
  59. /* 要写入的数据量低于当前页空余量 */
  60. if (nwrite <= pagefre)
  61. pagefre = nwrite;
  62. while (nwrite != 0)
  63. {
  64. /* 检查是否超页 */
  65. if (pagepos >= GD32FLASH_PAGE_NUM)
  66. break;
  67. /* 读取一页 */
  68. FLASH_Read(GD32FLASH_BASE + pagepos * GD32FLASH_PAGE_SIZE, FlashBuffer, GD32FLASH_PAGE_SIZE);
  69. /* 检查是否需要擦除 */
  70. for (i = 0; i < pagefre; i++)
  71. {
  72. if (*(FlashBuffer + pageoff + i) != 0xFFFF) /* FLASH擦出后默认内容全为0xFF */
  73. break;
  74. }
  75. if (i < pagefre)
  76. {
  77. uint32_t count = 0;
  78. uint32_t index = 0;
  79. if(FLASH_ErasePage(pagepos * GD32FLASH_PAGE_SIZE, 1) < 0)
  80. break;
  81. /* 复制到缓存 */
  82. for (index = 0; index < pagefre; index++)
  83. {
  84. *(FlashBuffer + pageoff + index) = *(pBuffer + index);
  85. }
  86. /* 写回FLASH */
  87. count = FLASH_WriteNotErase(GD32FLASH_BASE + pagepos * GD32FLASH_PAGE_SIZE, FlashBuffer, GD32FLASH_PAGE_SIZE >> 1);
  88. if (count != (GD32FLASH_PAGE_SIZE >> 1))
  89. {
  90. nwrite -= count;
  91. break;
  92. }
  93. }
  94. else
  95. {
  96. /* 无需擦除,直接写 */
  97. uint32_t count = FLASH_WriteNotErase(Address, pBuffer, pagefre);
  98. if (count != pagefre)
  99. {
  100. nwrite -= count;
  101. break;
  102. }
  103. }
  104. pBuffer += pagefre; /* 读取地址递增 */
  105. Address += (pagefre << 1); /* 写入地址递增 */
  106. nwrite -= pagefre; /* 更新剩余未写入数据量 */
  107. pagepos++; /* 下一页 */
  108. pageoff = 0; /* 页内偏移地址置零 */
  109. /* 根据剩余量计算下次写入数据量 */
  110. pagefre = nwrite >= (GD32FLASH_PAGE_SIZE >> 1) ? (GD32FLASH_PAGE_SIZE >> 1) : nwrite;
  111. }
  112. /* 加锁FLASH */
  113. fmc_unlock();
  114. return ((NumToWrite - nwrite) << 1);
  115. }
  116. uint32_t FLASH_WriteNotErase(uint32_t Address, const uint16_t *Buffer, uint32_t NumToWrite)
  117. {
  118. uint32_t nwrite = NumToWrite;
  119. uint32_t addrmax = GD32FLASH_END - 2;
  120. while (nwrite)
  121. {
  122. if (Address > addrmax)
  123. break;
  124. fmc_halfword_program(Address, *Buffer);
  125. if ((*(__IO uint16_t*) Address) != *Buffer)
  126. break;
  127. nwrite--;
  128. Buffer++;
  129. Address += 2;
  130. }
  131. return (NumToWrite - nwrite);
  132. }
  133. int FLASH_ErasePage(uint32_t PageAddress, uint32_t NbPages)
  134. {
  135. while(NbPages--)
  136. {
  137. if(fmc_page_erase(PageAddress) != FMC_READY)
  138. {
  139. return -1;
  140. }
  141. PageAddress += GD32FLASH_PAGE_SIZE;
  142. }
  143. return 0;
  144. }

ends…

发表评论

表情:
评论列表 (有 0 条评论,773人围观)

还没有评论,来说两句吧...

相关阅读

    相关 stm32 内部flash

    ![1][] 嵌入式闪存 闪存存储器有主存储块和信息块组成 大容量产品主存储块最大为64K×64位,每个存储块划分为256个2K字节的页 编程和擦除闪存 闪存编