老版本GCU
您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符
 
 
 
 
 
 

485 行
15 KiB

  1. /************************************************************************
  2. * 模块名称:iap.c
  3. * 程序功能:
  4. * 编 写 者:
  5. * 编写日期:2017-06-22
  6. * 修 改 者:
  7. * 修改日期:
  8. * 编译环境:KEIL4 MDK ARM V4.74
  9. * 硬件平台:STM32F103ZCT6
  10. ************************************************************************/
  11. /************************************************************************/
  12. /* */
  13. /* INCLUDES */
  14. /* */
  15. /************************************************************************/
  16. #include "share.h"
  17. #include "com.h"
  18. #include "stm32f10x_flash.h"
  19. /************************************************************************/
  20. /* */
  21. /* DEFINITION */
  22. /* */
  23. /************************************************************************/
  24. typedef void (*pFunction)(void);
  25. /************************************************************************/
  26. /* */
  27. /* DECLARATION */
  28. /* */
  29. /************************************************************************/
  30. /************************************************************************/
  31. /* */
  32. /* VARIABLE */
  33. /* */
  34. /************************************************************************/
  35. pFunction Jump_To_Application;
  36. uint32_t m_JumpAddress;
  37. uint32_t BlockNbr = 0, UserMemoryMask = 0;
  38. __IO uint32_t FlashProtection = 0;
  39. //大容量芯片扇区大小为2K,而小容量的每个扇区是1K
  40. u16 STMFLASH_BUF[STM_SECTOR_SIZE/2]; //定义数组最大为2K字节
  41. uint16_t temp[STM_SECTOR_SIZE/2];
  42. uint16_t temp1[STM_SECTOR_SIZE/2]={0}; //1024个半字
  43. const char reboot[] = "IAP-reboot...\r\n";
  44. const char update[] = "IAP-update...\r\n";
  45. const char startup[] = "APP-startup...\r\n";
  46. const char nojump[] = "APP-No Jump...\r\n";
  47. const char okjump[] = "APP-Ok Jump...\r\n";
  48. /***********************************************************************
  49. * 函 数 名: void AFL_Jump2App(void)
  50. * 功能描述: 跳转到用户程序APP
  51. * 函数说明:
  52. * 输 入: 无
  53. * 返 回:
  54. * 设 计 者:RXJ 日期:2017-04-28
  55. * 修 改 者:RXJ 日期:2017-04-28
  56. ***********************************************************************/
  57. uint8_t AFL_IsValidApp(uint32_t address)
  58. {
  59. __IO uint32_t app1st_int = (*(__IO uint32_t*)address);
  60. if ((app1st_int & 0x2FFE0000 ) == 0x20000000) { //判断栈顶地址是否正确(0x2000 0000 - 0x 2000 2000之间)
  61. return 1;
  62. }
  63. return 0;
  64. }
  65. void AFL_Jump2App(void)
  66. {
  67. if (AFL_IsValidApp(APPLICATION_PROGRAM_ADDRESS)) //判断栈顶地址是否正确(0x2000 0000 - 0x 2000 2000之间)
  68. {
  69. //printf("***Ok Jump...\r\n");
  70. //Dma_send_data((uint8_t*)okjump, 16);
  71. Dma_send_data(0, 0); //等待发送完成,如果不等待发送完,Jump将不成功
  72. delay_ms(100); //如果不delay,Jump将不成功
  73. USART_Cmd(USART_NUM, DISABLE);//失能串口
  74. // __ASM("CPSID I");
  75. __disable_irq(); //
  76. m_JumpAddress = *(__IO uint32_t*) (APPLICATION_PROGRAM_ADDRESS + 4); //让出MSP(主堆栈)空间
  77. Jump_To_Application = (pFunction) m_JumpAddress; //Jump_To_Application指向了复位函数所在的地址
  78. __set_MSP(*(__IO uint32_t*) APPLICATION_PROGRAM_ADDRESS); //设置主函数栈指针
  79. Jump_To_Application(); //跳到APP
  80. } else {
  81. printf("***No Jump...\r\n");
  82. Dma_send_data((uint8_t*)nojump, 16);
  83. Dma_send_data(0, 0); //等待发送完成
  84. //delay_ms(5);
  85. }
  86. }
  87. /**
  88. * @bieaf 进行BootLoader的启动
  89. *
  90. * @param none
  91. * @return none
  92. */
  93. void AFL_Start_BootLoader(void)
  94. {
  95. uint8_t start_flag = 0, iret= 0;
  96. uint32_t start_mode = Startup_Normol;
  97. DFL_SerialInit();
  98. Dma_send_data((uint8_t*)reboot, 15);
  99. /*==========打印消息==========*/
  100. // printf("\r\n");
  101. // printf("******************************************\r\n");
  102. // printf("* *\r\n");
  103. // printf("* ***** **** **** ******* *\r\n");
  104. // printf("* * ** * * * * * *\r\n");
  105. // printf("* * * * * * * * *\r\n");
  106. // printf("* * ** * * * * * *\r\n");
  107. // printf("* ***** * * * * * *\r\n");
  108. // printf("* * ** * * * * * *\r\n");
  109. // printf("* * * * * * * * *\r\n");
  110. // printf("* * ** * * * * * *\r\n");
  111. // printf("* ***** **** **** * *\r\n");
  112. // printf("* *\r\n");
  113. // printf("*********************** by Leaf_Fruit ****\r\n");
  114. printf("\r\n");
  115. printf("***********************************\r\n");
  116. printf("* *\r\n");
  117. printf("* Leaf_Fruit's BootLoader *\r\n");
  118. printf("* *\r\n");
  119. printf("***********************************\r\n");
  120. while(g_SysTick < 1500 || g_IAPCommondFlag == 1) //wait for 2s to run into update mode;
  121. {
  122. AFL_SerialTask();
  123. }
  124. printf("> Choose a startup method......\r\n");
  125. start_mode = AFL_Read_StartMode(); ///< 读取是否启动应用程序 */
  126. switch(start_mode) ///< 读取是否启动应用程序 */
  127. {
  128. case Startup_Normol: ///< 正常启动 */
  129. {
  130. printf("> Normal start......\r\n");
  131. break;
  132. }
  133. case Startup_Update: ///< 升级再启动 */
  134. {
  135. //break;
  136. Dma_send_data((uint8_t*)update, 15);
  137. printf("> Start update......\r\n");
  138. iret = DHL_MoveCode(APPLICATION_PROGRAM_ADDRESS, APPLICATION_UPDCODE_ADDRESS, BACKUP_CODE_CACHE_SIZE/2);
  139. if(iret == 1) { //copy ok
  140. printf("> Copy code ok......\r\n");
  141. } else {
  142. printf("> Copy code error, update failed.....\r\n");
  143. }
  144. break;
  145. }
  146. case Startup_Reset: ///< 恢复出厂设置 目前没使用 */
  147. {
  148. printf("> Restore to factory program......\r\n");
  149. break;
  150. }
  151. case Startup_Download: ///< download update files
  152. {
  153. printf("> Start download update file......\r\n");
  154. start_flag = 1;
  155. break;
  156. }
  157. default: ///< 启动失败
  158. {
  159. printf("> Error:%X!!!......\r\n", Read_Start_Mode());
  160. //start_flag = 1;
  161. //return;
  162. break;
  163. }
  164. }
  165. /* 跳转到应用程序 */
  166. Dma_send_data((uint8_t*)startup, 16);
  167. printf("> Start up......\r\n\r\n");
  168. AFL_Jump2App();
  169. }
  170. /**
  171. * @bieaf 读若干个数据
  172. *
  173. * @param addr 读数据的地址
  174. * @param buff 读出数据的数组指针
  175. * @param word_size 长度
  176. * @return
  177. */
  178. void DHL_ReadFlash_Word(uint32_t addr, uint32_t * buff, uint16_t word_size)
  179. {
  180. uint32_t i =0;
  181. for(i =0; i < word_size; i++)
  182. {
  183. buff[i] = *(__IO uint32_t*)(addr + 4 * i);
  184. }
  185. return;
  186. }
  187. /* 读取启动模式 */
  188. uint32_t AFL_Read_StartMode(void)
  189. {
  190. /* uint32_t mode = 0;
  191. DHL_ReadFlash_Word(FLASH_ADDR_UPDATE_FLAG, &mode, 1);
  192. return mode;
  193. */
  194. uint32_t modeL = 0, modeH = 0;
  195. modeL = DHL_STMFlash_ReadHalfWord(FLASH_ADDR_UPDATE_FLAG);
  196. modeH = DHL_STMFlash_ReadHalfWord(FLASH_ADDR_UPDATE_FLAG+2);
  197. return (modeH<<16 | modeL);
  198. }
  199. /* 标记升级完成 */
  200. uint8_t AFL_Write_StartMode(uint32_t mode)
  201. {
  202. //unsigned int update_flag = 0xAAAAAAAA; ///< 对应bootloader的启动步骤
  203. //WriteFlash((Application_2_Addr + Application_Size - 4), &update_flag,1 );
  204. uint32_t mode1 = 0;
  205. uint16_t pmode[2] = {0, 0};
  206. pmode[0] = (mode & 0xffff);
  207. pmode[1] = ((mode >> 16)&0xffff);
  208. DHL_STMFlash_Write(FLASH_ADDR_UPDATE_FLAG, pmode, 2);
  209. mode1 = AFL_Read_StartMode();
  210. if (mode1 == mode) {
  211. return 1;
  212. }
  213. return 0;
  214. }
  215. /**
  216. * @bieaf 进行程序的覆盖
  217. * @detail 1.擦除目的地址
  218. * 2.源地址的代码拷贝到目的地址
  219. * 3.擦除源地址
  220. *
  221. * @param 搬运的源地址
  222. * @param 搬运的目的地址
  223. * @return 搬运的程序大小
  224. */
  225. uint8_t DHL_MoveCode(uint32_t des_addr, uint32_t src_addr, uint32_t sector_count)
  226. {
  227. uint8_t compare_flag = 0;
  228. uint32_t i = 0, j = 0, rtimes = 3; //retry 3 times;
  229. //check
  230. if (!AFL_IsValidApp(src_addr)) {
  231. printf("> Invalid start address......\r\n");
  232. return 0;
  233. }
  234. /*1.擦除目的地址*/
  235. printf("> Start erase des flash......\r\n");
  236. DHL_STMFlash_Erase(des_addr, sector_count);
  237. printf("> Erase des flash down......\r\n");
  238. /*2.开始拷贝*/
  239. printf("> Start copy......\r\n");
  240. for(i = 0; i < sector_count; i++)
  241. {
  242. DHL_STMFlash_Read((src_addr + i*STM_SECTOR_SIZE), temp, STM_SECTOR_SIZE/2);
  243. for(j = 0; j<rtimes; j++) {
  244. DHL_STMFlash_Write((des_addr + i*STM_SECTOR_SIZE), temp, STM_SECTOR_SIZE/2);
  245. DHL_STMFlash_Read((des_addr + i*STM_SECTOR_SIZE), temp1, STM_SECTOR_SIZE/2);
  246. compare_flag = DHL_CompareBuffer(temp, temp1, STM_SECTOR_SIZE/2);
  247. if(compare_flag == 1) //copy error
  248. {
  249. break;
  250. }
  251. }
  252. if(compare_flag != 1) //copy error
  253. {
  254. break;
  255. }
  256. }
  257. /*3.擦除源地址*/
  258. if(compare_flag == 1) { //copy ok
  259. printf("> Copy down ok......\r\n");
  260. printf("> Start erase src flash......\r\n");
  261. AFL_Write_StartMode(Startup_Normol);
  262. //DHL_STMFlash_Erase(src_addr, sector_count);
  263. printf("> Erase src flash down......\r\n");
  264. } else { //copy error
  265. printf("> Copy down error......\r\n");
  266. }
  267. return compare_flag;
  268. }
  269. /***********************************************************************
  270. * 函 数 名: DHL_STMFlash_Erase(u32 EraseAddr, u8 NumToErase)
  271. * 功能描述: 从指定页地址擦除指定页数的数据
  272. * 函数说明:
  273. * 输 入: EraseAddr:页的起始地址 SectorNumToErase:擦除的页数
  274. * 返 回:
  275. * 设 计 者:RXJ 日期:2017-04-28
  276. * 修 改 者:RXJ 日期:2017-04-28
  277. ***********************************************************************/
  278. void DHL_STMFlash_Erase(u32 EraseAddr, u8 SectorNumToErase)
  279. {
  280. u8 i;
  281. FLASH_Unlock(); //解锁
  282. for(i = 0; i < SectorNumToErase; i++)
  283. {
  284. FLASH_ErasePage(EraseAddr); //擦除一页
  285. EraseAddr += STM_SECTOR_SIZE; //偏移一页
  286. }
  287. FLASH_Lock(); //上锁
  288. }
  289. /***********************************************************************
  290. * 函 数 名: DHL_STMFlash_ReadHalfWord(u32 faddr)
  291. * 功能描述: 读取指定地址的半字(16位数据)
  292. * 函数说明: 对应数据
  293. * 输 入: faddr:读地址(为2的倍数)
  294. * 返 回:
  295. * 设 计 者:RXJ 日期:2017-04-28
  296. * 修 改 者:RXJ 日期:2017-04-28
  297. ***********************************************************************/
  298. u16 DHL_STMFlash_ReadHalfWord(u32 faddr)
  299. {
  300. return *(__IO uint16_t*)faddr;
  301. }
  302. /***********************************************************************
  303. * 函 数 名: DHL_STMFlash_Read(u32 ReadAddr, u16 *pBuffer, u16 NumToRead)
  304. * 功能描述: 从指定地址读出指定长度的数据
  305. * 函数说明:
  306. * 输 入: ReadAddr:起始地址 pBuffer:存储数据的指针 NumToRead:半字(16位)的个数
  307. * 返 回:
  308. * 设 计 者:RXJ 日期:2017-04-28
  309. * 修 改 者:RXJ 日期:2017-04-28
  310. ***********************************************************************/
  311. void DHL_STMFlash_Read(u32 ReadAddr, u16 *pBuffer, u16 NumToRead)
  312. {
  313. u16 i;
  314. for(i = 0; i < NumToRead; i++)
  315. {
  316. pBuffer[i] = DHL_STMFlash_ReadHalfWord(ReadAddr); //读取2个字节
  317. ReadAddr += 2; //偏移2个字节
  318. }
  319. }
  320. /***********************************************************************
  321. * 函 数 名: DHL_STMFlash_Write_NoCheck(u32 WriteAddr, u16 *pBuffer, u16 NumToWrite)
  322. * 功能描述: 直接写入
  323. * 函数说明:
  324. * 输 入: WriteAddr:起始地址 pBuffer:数据指针 NumToWrite:半字(16位)的个数
  325. * 返 回:
  326. * 设 计 者:RXJ 日期:2017-04-28
  327. * 修 改 者:RXJ 日期:2017-04-28
  328. ***********************************************************************/
  329. void DHL_STMFlash_Write_NoCheck(u32 WriteAddr, u16 *pBuffer, u16 NumToWrite)
  330. {
  331. u16 i;
  332. for(i = 0; i < NumToWrite; i++)
  333. {
  334. FLASH_ProgramHalfWord(WriteAddr, pBuffer[i]); //在指定地址写入半字
  335. WriteAddr += 2; //地址偏移2
  336. }
  337. }
  338. /***********************************************************************
  339. * 函 数 名: DHL_STMFlash_Write(u32 WriteAddr, u16 *pBuffer, u16 NumToWrite)
  340. * 功能描述: 从指定地址写入指定长度的数据
  341. * 函数说明:
  342. * 输 入: WriteAddr:起始地址 pBuffer:数据指针 NumToWrite:半字(16位)的个数
  343. * 返 回:
  344. * 设 计 者:RXJ 日期:2017-04-28
  345. * 修 改 者:RXJ 日期:2017-04-28
  346. ***********************************************************************/
  347. void DHL_STMFlash_Write(u32 WriteAddr, u16 *pBuffer, u16 NumToWrite)
  348. {
  349. u16 i;
  350. u32 secpos; //扇区地址
  351. u16 secoff; //扇区内偏移地址(16位字节计算)
  352. u16 secremain; //扇区内剩余地址(16位字节计算)
  353. u32 offaddr; //去掉0X08000000后的地址
  354. //判断地址是否合法
  355. if(WriteAddr < STM32_FLASH_BASE || (WriteAddr >= (STM32_FLASH_BASE + 1024 * STM32_FLASH_SIZE - NumToWrite*2)))
  356. {
  357. return;
  358. }
  359. FLASH_Unlock(); //解锁
  360. offaddr = WriteAddr - STM32_FLASH_BASE; //实际偏移地址
  361. secpos = offaddr / STM_SECTOR_SIZE; //扇区地址 0~127 for STM32F103RBT6; 0-255 for STM32F103RCT6
  362. secoff = (offaddr % STM_SECTOR_SIZE)/2; //在扇区内的偏移(u16占两个字节,故以两个字节为基本单位)
  363. secremain = STM_SECTOR_SIZE /2 -secoff; //扇区剩余空间大小(u16 占2个字节)
  364. if(NumToWrite <= secremain)
  365. {
  366. secremain = NumToWrite; //不大于该扇区范围
  367. }
  368. while(1)
  369. {
  370. DHL_STMFlash_Read(secpos*STM_SECTOR_SIZE + STM32_FLASH_BASE, STMFLASH_BUF, STM_SECTOR_SIZE / 2); //读出整个扇区的内容
  371. for(i = 0; i < secremain; i++) //校验数据是否为0xffff,STM32内部FLASH在写前保证所写扇区被擦除,即值为0xffff
  372. {
  373. if(STMFLASH_BUF[secoff + i] != 0XFFFF)
  374. {
  375. break;
  376. }
  377. }
  378. if(i < secremain) //需要擦除
  379. {
  380. FLASH_ErasePage(secpos*STM_SECTOR_SIZE + STM32_FLASH_BASE); //擦除这个扇区
  381. for(i = 0; i < secremain; i++) //复制
  382. {
  383. STMFLASH_BUF[i+secoff] = pBuffer[i];
  384. }
  385. DHL_STMFlash_Write_NoCheck(secpos*STM_SECTOR_SIZE + STM32_FLASH_BASE, STMFLASH_BUF, STM_SECTOR_SIZE / 2); //写入这个扇区
  386. }
  387. else
  388. {
  389. DHL_STMFlash_Write_NoCheck(WriteAddr, pBuffer, secremain); //扇区已经擦除的,直接写入扇区剩余空间
  390. }
  391. if(NumToWrite == secremain)
  392. {
  393. break; //写入结束了
  394. }
  395. else //写入未结束
  396. {
  397. secpos++; //扇区地址加1
  398. secoff = 0; //偏移地址为0
  399. pBuffer += secremain; //指针偏移
  400. WriteAddr += secremain; //写地址偏移
  401. NumToWrite -= secremain; //字节数(16位)递减
  402. if(NumToWrite > (STM_SECTOR_SIZE / 2))
  403. {
  404. secremain = STM_SECTOR_SIZE / 2; //下一个扇区还是写不完
  405. }
  406. else
  407. {
  408. secremain = NumToWrite; //下一个扇区可以写完了
  409. }
  410. }
  411. }
  412. FLASH_Lock(); //上锁
  413. }
  414. /***********************************************************************
  415. * 函 数 名: DHL_CompareBuffer
  416. * 功能描述: 比较两个数组中的数
  417. * 函数说明:
  418. * 输 入:
  419. * 返 回: 不等返回0 , 相等返回1
  420. * 设 计 者:RXJ 日期:2017-04-28
  421. * 修 改 者:RXJ 日期:2017-04-28
  422. ***********************************************************************/
  423. u16 DHL_CompareBuffer(u16 *pBuf1, u16 *pBuf2, int nCount)
  424. {
  425. u16 i;
  426. for(i = 0; i < nCount; i++)
  427. {
  428. if(pBuf1[i] != pBuf2[i])
  429. return 0;
  430. }
  431. return 1;
  432. }
  433. void System_SoftReset(void)
  434. {
  435. __set_FAULTMASK(1); //close interrupt
  436. NVIC_SystemReset(); //soft-reset
  437. }
  438. /******************* (C) COPYRIGHT 2017 LECOOAI *****END OF FILE****/