老版本GCU
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

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