野火电子论坛

 找回密码
 注册

QQ登录

只需一步,快速开始

查看: 777|回复: 0

使用IAP功能,将第一段数据写入Flash里,进入硬件错误

[复制链接]
发表于 2024-8-27 10:55:08 | 显示全部楼层 |阅读模式
目前调试发现的现象:

上位机点击下载,将第一段数据(192个字节)传入到0x08002000(APP所在的地址)。完成写入后,进入HardFault_Handler。
通过烧录器软件读取User Flash,可以看到192个字节数据正常写入。目前感觉是读写Flash的函数出问题
  1. // 得到FLASH状态
  2. uint8_t Bsp_FLASH_GetStatus(void)
  3. {
  4.         uint32_t res;
  5.         res = FLASH->SR;

  6.         if (res & FLASH_SR_BSY)
  7.                 return 1;

  8.         // flash出错
  9.         if (res & FLASH_FLAG_ALL_ERR)
  10.                 return 2;

  11.         //         /* check flash errors */
  12.         //  error = (FLASH->SR & FLASH_SR_ERRORS);

  13.         //  /* Clear SR register */
  14.         //  FLASH->SR = FLASH_SR_CLEAR;

  15.         return 0; // 操作完成
  16. }
  17. // 等待操作完成
  18. // time:要延时的长短
  19. // 返回值:状态.
  20. uint8_t Bsp_FLASH_WaitDone(uint16_t time)
  21. {
  22.         uint8_t res;
  23.         do
  24.         {
  25.                 res = Bsp_FLASH_GetStatus();
  26.                 if (res != 1)
  27.                         break; // 非忙,无需等待了,直接退出.
  28.                 delay_us(1);
  29.                 time--;
  30.         } while (time);
  31.         if (time == 0)
  32.                 res = 0xff; // TIMEOUT
  33.         return res;
  34. }

  35. // 擦除页
  36. // paddr:页地址
  37. // 返回值:执行情况
  38. uint8_t Bsp_FLASH_ErasePage(uint32_t paddr)
  39. {
  40.         uint8_t res = 0;
  41.         res = Bsp_FLASH_WaitDone(0X5FFF); // 等待上次操作结束,>20ms
  42.         if (res == 0)
  43.         {
  44.                 std_flash_page_erase(paddr);
  45.                 res = Bsp_FLASH_WaitDone(0X5FFF); // 等待操作结束,>20ms
  46.                 if (res != 1)                                          // 非忙
  47.                 {
  48.                         std_flash_set_erase_mode(FLASH_ERASE_DISABLE);
  49.                 }
  50.         }
  51.         return res;
  52. }
  53. // 在FLASH指定地址写入半字
  54. // faddr:指定地址(此地址必须为2的倍数!!)
  55. // dat:要写入的数据
  56. // 返回值:写入的情况
  57. uint8_t Bsp_FLASH_WriteHalfWord(uint32_t faddr, uint16_t dat)
  58. {
  59.         uint8_t res;
  60.         res = Bsp_FLASH_WaitDone(0XFF);
  61.         if (res == 0) // OK
  62.         {
  63.                 FLASH->CR |= 1 << 0;                        // 编程使能
  64.                 *(__IO uint16_t *)faddr = dat;        // 写入数据
  65.                 res = Bsp_FLASH_WaitDone(0XFF); // 等待操作完成
  66.                 if (res != 1)                                        // 操作成功
  67.                 {
  68.                         FLASH->CR &= ~(1 << 0); // 清除PG位.
  69.                 }
  70.         }
  71.         return res;
  72. }

  73. // 在FLASH指定地址写入
  74. // faddr:指定地址(此地址必须为2的倍数!!)
  75. // dat:要写入的数据
  76. // 返回值:写入的情况
  77. uint8_t Bsp_FLASH_WriteDoubleWord(uint32_t faddr, uint64_t dat)
  78. {
  79.         uint8_t res;
  80.         res = Bsp_FLASH_WaitDone(0XFF);
  81.         if (res == 0) // OK
  82.         {
  83.                 FLASH->CR |= 1 << 0; // 编程使能
  84.                 /* Program first word */
  85.                 *(uint32_t *)faddr = (uint32_t)dat;

  86.                 /* Barrier to ensure programming is performed in 2 steps, in right order
  87.                         (independently of compiler optimization behavior) */
  88.                 __ISB();

  89.                 /* Program second word */
  90.                 *(uint32_t *)(faddr + 4U) = (uint32_t)(dat >> 32U);
  91.                 res = Bsp_FLASH_WaitDone(0XFF); // 等待操作完成
  92.                 if (res != 1)                                        // 操作成功
  93.                 {
  94.                         FLASH->CR &= ~(1 << 0); // 清除PG位.
  95.                 }
  96.         }
  97.         return res;
  98. }
  99. // 读取指定地址的半字(16位数据)
  100. // faddr:读地址
  101. // 返回值:对应数据.
  102. uint16_t Bsp_FLASH_ReadHalfWord(uint32_t faddr)
  103. {
  104.         return *(__IO uint16_t *)faddr;
  105. }

  106. uint64_t Bsp_FLASH_ReadDoubleWord(uint32_t faddr)
  107. {
  108.         return *(__IO uint64_t *)faddr;
  109. }
  110. #if STM32_FLASH_WREN // 如果使能了写
  111. // 不检查的写入
  112. // WriteAddr:起始地址
  113. // pBuffer:数据指针
  114. // NumToWrite:半字(16位)数
  115. void Bsp_FLASH_Write_NoCheck(uint32_t WriteAddr, uint64_t *pBuffer, uint16_t NumToWrite)
  116. {
  117.         uint16_t i;
  118.         for (i = 0; i < NumToWrite; i++)
  119.         {
  120.                 Bsp_FLASH_WriteDoubleWord(WriteAddr, pBuffer[i]);
  121.                 WriteAddr += 8; // 地址增加2.
  122.         }
  123. }
  124. // 从指定地址开始写入指定长度的数据
  125. // WriteAddr:起始地址(此地址必须为2的倍数!!)
  126. // pBuffer:数据指针
  127. // NumToWrite:半字(16位)数(就是要写入的16位数据的个数.)
  128. // #define STM_SECTOR_SIZE 1024 //字节

  129. #define STM_SECTOR_SIZE 2048
  130. #define STM_WRSIZE 8

  131. uint64_t Bsp_FLASH_BUF[STM_SECTOR_SIZE / STM_WRSIZE]; // 最多是2K字节

  132. void Bsp_FLASH_Write(uint32_t WriteAddr, uint64_t *pBuffer, uint16_t NumToWrite)
  133. {
  134.         static uint8_t pre_sector = 0;
  135.         uint32_t secpos;        // 扇区地址
  136.         uint16_t secoff;        // 扇区内偏移地址(16位字计算)
  137.         uint16_t secremain; // 扇区内剩余地址(16位字计算)
  138.         uint16_t i;
  139.         uint32_t offaddr; // 去掉0X08000000后的地址

  140.         if (WriteAddr < STM32_FLASH_BASE || (WriteAddr >= (STM32_FLASH_BASE + 1024 * STM32_FLASH_SIZE)))
  141.                 return; // 非法地址

  142.         std_flash_unlock();                                                // 解锁
  143.         offaddr = WriteAddr - STM32_FLASH_BASE; // 实际偏移地址.

  144.         secpos = offaddr / STM_SECTOR_SIZE;                                   // 扇区地址  0~127 for STM32F103RBT6
  145.         secoff = (offaddr % STM_SECTOR_SIZE) / STM_WRSIZE; // 在扇区内的偏移(2个字节为基本单位.)
  146.         secremain = STM_SECTOR_SIZE / STM_WRSIZE - secoff; // 扇区剩余空间大小
  147.         if (NumToWrite <= secremain)
  148.                 secremain = NumToWrite; // 不大于该扇区范围

  149.         while (1)
  150.         {
  151.                 if (secpos != pre_sector)
  152.                 {
  153.                         pre_sector = secpos;
  154.                         Bsp_FLASH_ErasePage(secpos); // 擦除这个扇区
  155.                 }

  156.                 Bsp_FLASH_Write_NoCheck(WriteAddr, pBuffer, secremain); // 写已经擦除了的,直接写入扇区剩余区间.

  157.                 if (NumToWrite == secremain)
  158.                         break; // 写入结束了
  159.                 else           // 写入未结束
  160.                 {
  161.                         secpos++;                                                         // 扇区地址增1
  162.                         secoff = 0;                                                         // 偏移位置为0
  163.                         pBuffer += secremain;                                 // 指针偏移
  164.                         WriteAddr += secremain * STM_WRSIZE; // 写地址偏移(16位数据地址,需要*2)
  165.                         NumToWrite -= secremain;                         // 字节(16位)数递减
  166.                         if (NumToWrite > (STM_SECTOR_SIZE / STM_WRSIZE))
  167.                                 secremain = STM_SECTOR_SIZE / STM_WRSIZE; // 下一个扇区还是写不完
  168.                         else
  169.                                 secremain = NumToWrite; // 下一个扇区可以写完了
  170.                 }
  171.         };
  172.         std_flash_lock(); // 上锁
  173. }
  174. #endif

  175. // 从指定地址开始读出指定长度的数据
  176. // ReadAddr:起始地址
  177. // pBuffer:数据指针
  178. // NumToWrite:半字(16位)数
  179. void Bsp_FLASH_Read(uint32_t ReadAddr, uint64_t *pBuffer, uint16_t NumToRead)
  180. {
  181.         uint16_t i;
  182.         for (i = 0; i < NumToRead; i++)
  183.         {
  184.                 pBuffer[i] = Bsp_FLASH_ReadDoubleWord(ReadAddr); // 读取2个字节.
  185.                 ReadAddr += 8;                                                                         // 偏移8个字节.
  186.         }
  187. }
复制代码


回复

使用道具 举报

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

本版积分规则

联系站长|手机版|野火电子官网|野火淘宝店铺|野火电子论坛 ( 粤ICP备14069197号 ) 大学生ARM嵌入式2群

GMT+8, 2024-10-16 08:17 , Processed in 0.119409 second(s), 24 queries , Gzip On.

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

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