|
- /************************************************************************
- * 模块名称:iap.c
- * 程序功能:
- * 编 写 者:
- * 编写日期:2017-06-22
- * 修 改 者:
- * 修改日期:
- * 编译环境:KEIL4 MDK ARM V4.74
- * 硬件平台:STM32F103ZCT6
- ************************************************************************/
- /************************************************************************/
- /* */
- /* INCLUDES */
- /* */
- /************************************************************************/
- #include "share.h"
- #include "com.h"
- #include "stm32f10x_flash.h"
-
- /************************************************************************/
- /* */
- /* DEFINITION */
- /* */
- /************************************************************************/
- typedef void (*pFunction)(void);
-
- /************************************************************************/
- /* */
- /* DECLARATION */
- /* */
- /************************************************************************/
-
- /************************************************************************/
- /* */
- /* VARIABLE */
- /* */
- /************************************************************************/
- pFunction Jump_To_Application;
- uint32_t m_JumpAddress;
- uint32_t BlockNbr = 0, UserMemoryMask = 0;
- __IO uint32_t FlashProtection = 0;
-
-
- //大容量芯片扇区大小为2K,而小容量的每个扇区是1K
- u16 STMFLASH_BUF[STM_SECTOR_SIZE/2]; //定义数组最大为2K字节
- uint16_t temp[STM_SECTOR_SIZE/2];
- uint16_t temp1[STM_SECTOR_SIZE/2]={0}; //1024个半字
-
- const char reboot[] = "IAP-reboot...\r\n";
- const char update[] = "IAP-update...\r\n";
- const char startup[] = "APP-startup...\r\n";
- const char nojump[] = "APP-No Jump...\r\n";
- const char okjump[] = "APP-Ok Jump...\r\n";
-
-
- /***********************************************************************
- * 函 数 名: void AFL_Jump2App(void)
- * 功能描述: 跳转到用户程序APP
- * 函数说明:
- * 输 入: 无
- * 返 回:
- * 设 计 者:RXJ 日期:2017-04-28
- * 修 改 者:RXJ 日期:2017-04-28
- ***********************************************************************/
- uint8_t AFL_IsValidApp(uint32_t address)
- {
- __IO uint32_t app1st_int = (*(__IO uint32_t*)address);
- if ((app1st_int & 0x2FFE0000 ) == 0x20000000) { //判断栈顶地址是否正确(0x2000 0000 - 0x 2000 2000之间)
- return 1;
- }
- return 0;
- }
- void AFL_Jump2App(void)
- {
- if (AFL_IsValidApp(APPLICATION_PROGRAM_ADDRESS)) //判断栈顶地址是否正确(0x2000 0000 - 0x 2000 2000之间)
- {
- //printf("***Ok Jump...\r\n");
- //Dma_send_data((uint8_t*)okjump, 16);
- Dma_send_data(0, 0); //等待发送完成,如果不等待发送完,Jump将不成功
- delay_ms(100); //如果不delay,Jump将不成功
-
- USART_Cmd(USART_NUM, DISABLE);//失能串口
- // __ASM("CPSID I");
- __disable_irq(); //
- m_JumpAddress = *(__IO uint32_t*) (APPLICATION_PROGRAM_ADDRESS + 4); //让出MSP(主堆栈)空间
- Jump_To_Application = (pFunction) m_JumpAddress; //Jump_To_Application指向了复位函数所在的地址
-
- __set_MSP(*(__IO uint32_t*) APPLICATION_PROGRAM_ADDRESS); //设置主函数栈指针
- Jump_To_Application(); //跳到APP
- } else {
- printf("***No Jump...\r\n");
- Dma_send_data((uint8_t*)nojump, 16);
- Dma_send_data(0, 0); //等待发送完成
- //delay_ms(5);
- }
- }
-
- /**
- * @bieaf 进行BootLoader的启动
- *
- * @param none
- * @return none
- */
- void AFL_Start_BootLoader(void)
- {
- uint8_t start_flag = 0, iret= 0;
- uint32_t start_mode = Startup_Normol;
- DFL_SerialInit();
-
- Dma_send_data((uint8_t*)reboot, 15);
- /*==========打印消息==========*/
- // printf("\r\n");
- // printf("******************************************\r\n");
- // printf("* *\r\n");
- // printf("* ***** **** **** ******* *\r\n");
- // printf("* * ** * * * * * *\r\n");
- // printf("* * * * * * * * *\r\n");
- // printf("* * ** * * * * * *\r\n");
- // printf("* ***** * * * * * *\r\n");
- // printf("* * ** * * * * * *\r\n");
- // printf("* * * * * * * * *\r\n");
- // printf("* * ** * * * * * *\r\n");
- // printf("* ***** **** **** * *\r\n");
- // printf("* *\r\n");
- // printf("*********************** by Leaf_Fruit ****\r\n");
-
- printf("\r\n");
- printf("***********************************\r\n");
- printf("* *\r\n");
- printf("* Leaf_Fruit's BootLoader *\r\n");
- printf("* *\r\n");
- printf("***********************************\r\n");
-
- while(g_SysTick < 1500 || g_IAPCommondFlag == 1) //wait for 2s to run into update mode;
- {
- AFL_SerialTask();
- }
-
- printf("> Choose a startup method......\r\n");
- start_mode = AFL_Read_StartMode(); ///< 读取是否启动应用程序 */
- switch(start_mode) ///< 读取是否启动应用程序 */
- {
- case Startup_Normol: ///< 正常启动 */
- {
- printf("> Normal start......\r\n");
- break;
- }
- case Startup_Update: ///< 升级再启动 */
- {
- //break;
- Dma_send_data((uint8_t*)update, 15);
- printf("> Start update......\r\n");
- iret = DHL_MoveCode(APPLICATION_PROGRAM_ADDRESS, APPLICATION_UPDCODE_ADDRESS, BACKUP_CODE_CACHE_SIZE/2);
- if(iret == 1) { //copy ok
- printf("> Copy code ok......\r\n");
- } else {
- printf("> Copy code error, update failed.....\r\n");
- }
- break;
- }
- case Startup_Reset: ///< 恢复出厂设置 目前没使用 */
- {
- printf("> Restore to factory program......\r\n");
- break;
- }
- case Startup_Download: ///< download update files
- {
- printf("> Start download update file......\r\n");
- start_flag = 1;
- break;
- }
- default: ///< 启动失败
- {
- printf("> Error:%X!!!......\r\n", Read_Start_Mode());
- //start_flag = 1;
- //return;
- break;
- }
- }
-
- /* 跳转到应用程序 */
- Dma_send_data((uint8_t*)startup, 16);
-
- printf("> Start up......\r\n\r\n");
- AFL_Jump2App();
- }
-
- /**
- * @bieaf 读若干个数据
- *
- * @param addr 读数据的地址
- * @param buff 读出数据的数组指针
- * @param word_size 长度
- * @return
- */
- void DHL_ReadFlash_Word(uint32_t addr, uint32_t * buff, uint16_t word_size)
- {
- uint32_t i =0;
- for(i =0; i < word_size; i++)
- {
- buff[i] = *(__IO uint32_t*)(addr + 4 * i);
- }
- return;
- }
-
- /* 读取启动模式 */
- uint32_t AFL_Read_StartMode(void)
- {
- /* uint32_t mode = 0;
- DHL_ReadFlash_Word(FLASH_ADDR_UPDATE_FLAG, &mode, 1);
- return mode;
- */
- uint32_t modeL = 0, modeH = 0;
- modeL = DHL_STMFlash_ReadHalfWord(FLASH_ADDR_UPDATE_FLAG);
- modeH = DHL_STMFlash_ReadHalfWord(FLASH_ADDR_UPDATE_FLAG+2);
- return (modeH<<16 | modeL);
- }
-
- /* 标记升级完成 */
- uint8_t AFL_Write_StartMode(uint32_t mode)
- {
- //unsigned int update_flag = 0xAAAAAAAA; ///< 对应bootloader的启动步骤
- //WriteFlash((Application_2_Addr + Application_Size - 4), &update_flag,1 );
- uint32_t mode1 = 0;
- uint16_t pmode[2] = {0, 0};
- pmode[0] = (mode & 0xffff);
- pmode[1] = ((mode >> 16)&0xffff);
- DHL_STMFlash_Write(FLASH_ADDR_UPDATE_FLAG, pmode, 2);
-
- mode1 = AFL_Read_StartMode();
- if (mode1 == mode) {
- return 1;
- }
- return 0;
- }
-
- /**
- * @bieaf 进行程序的覆盖
- * @detail 1.擦除目的地址
- * 2.源地址的代码拷贝到目的地址
- * 3.擦除源地址
- *
- * @param 搬运的源地址
- * @param 搬运的目的地址
- * @return 搬运的程序大小
- */
- uint8_t DHL_MoveCode(uint32_t des_addr, uint32_t src_addr, uint32_t sector_count)
- {
- uint8_t compare_flag = 0;
- uint32_t i = 0, j = 0, rtimes = 3; //retry 3 times;
- //check
- if (!AFL_IsValidApp(src_addr)) {
- printf("> Invalid start address......\r\n");
- return 0;
- }
- /*1.擦除目的地址*/
- printf("> Start erase des flash......\r\n");
- DHL_STMFlash_Erase(des_addr, sector_count);
- printf("> Erase des flash down......\r\n");
-
- /*2.开始拷贝*/
- printf("> Start copy......\r\n");
- for(i = 0; i < sector_count; i++)
- {
- DHL_STMFlash_Read((src_addr + i*STM_SECTOR_SIZE), temp, STM_SECTOR_SIZE/2);
- for(j = 0; j<rtimes; j++) {
- DHL_STMFlash_Write((des_addr + i*STM_SECTOR_SIZE), temp, STM_SECTOR_SIZE/2);
- DHL_STMFlash_Read((des_addr + i*STM_SECTOR_SIZE), temp1, STM_SECTOR_SIZE/2);
- compare_flag = DHL_CompareBuffer(temp, temp1, STM_SECTOR_SIZE/2);
- if(compare_flag == 1) //copy error
- {
- break;
- }
- }
- if(compare_flag != 1) //copy error
- {
- break;
- }
- }
-
- /*3.擦除源地址*/
- if(compare_flag == 1) { //copy ok
- printf("> Copy down ok......\r\n");
- printf("> Start erase src flash......\r\n");
- AFL_Write_StartMode(Startup_Normol);
- //DHL_STMFlash_Erase(src_addr, sector_count);
- printf("> Erase src flash down......\r\n");
- } else { //copy error
- printf("> Copy down error......\r\n");
- }
- return compare_flag;
- }
-
- /***********************************************************************
- * 函 数 名: DHL_STMFlash_Erase(u32 EraseAddr, u8 NumToErase)
- * 功能描述: 从指定页地址擦除指定页数的数据
- * 函数说明:
- * 输 入: EraseAddr:页的起始地址 SectorNumToErase:擦除的页数
- * 返 回:
- * 设 计 者:RXJ 日期:2017-04-28
- * 修 改 者:RXJ 日期:2017-04-28
- ***********************************************************************/
- void DHL_STMFlash_Erase(u32 EraseAddr, u8 SectorNumToErase)
- {
- u8 i;
- FLASH_Unlock(); //解锁
- for(i = 0; i < SectorNumToErase; i++)
- {
- FLASH_ErasePage(EraseAddr); //擦除一页
- EraseAddr += STM_SECTOR_SIZE; //偏移一页
- }
- FLASH_Lock(); //上锁
- }
-
- /***********************************************************************
- * 函 数 名: DHL_STMFlash_ReadHalfWord(u32 faddr)
- * 功能描述: 读取指定地址的半字(16位数据)
- * 函数说明: 对应数据
- * 输 入: faddr:读地址(为2的倍数)
- * 返 回:
- * 设 计 者:RXJ 日期:2017-04-28
- * 修 改 者:RXJ 日期:2017-04-28
- ***********************************************************************/
- u16 DHL_STMFlash_ReadHalfWord(u32 faddr)
- {
- return *(__IO uint16_t*)faddr;
- }
-
- /***********************************************************************
- * 函 数 名: DHL_STMFlash_Read(u32 ReadAddr, u16 *pBuffer, u16 NumToRead)
- * 功能描述: 从指定地址读出指定长度的数据
- * 函数说明:
- * 输 入: ReadAddr:起始地址 pBuffer:存储数据的指针 NumToRead:半字(16位)的个数
- * 返 回:
- * 设 计 者:RXJ 日期:2017-04-28
- * 修 改 者:RXJ 日期:2017-04-28
- ***********************************************************************/
- void DHL_STMFlash_Read(u32 ReadAddr, u16 *pBuffer, u16 NumToRead)
- {
- u16 i;
-
- for(i = 0; i < NumToRead; i++)
- {
- pBuffer[i] = DHL_STMFlash_ReadHalfWord(ReadAddr); //读取2个字节
- ReadAddr += 2; //偏移2个字节
- }
- }
-
- /***********************************************************************
- * 函 数 名: DHL_STMFlash_Write_NoCheck(u32 WriteAddr, u16 *pBuffer, u16 NumToWrite)
- * 功能描述: 直接写入
- * 函数说明:
- * 输 入: WriteAddr:起始地址 pBuffer:数据指针 NumToWrite:半字(16位)的个数
- * 返 回:
- * 设 计 者:RXJ 日期:2017-04-28
- * 修 改 者:RXJ 日期:2017-04-28
- ***********************************************************************/
- void DHL_STMFlash_Write_NoCheck(u32 WriteAddr, u16 *pBuffer, u16 NumToWrite)
- {
- u16 i;
-
- for(i = 0; i < NumToWrite; i++)
- {
- FLASH_ProgramHalfWord(WriteAddr, pBuffer[i]); //在指定地址写入半字
- WriteAddr += 2; //地址偏移2
- }
- }
-
- /***********************************************************************
- * 函 数 名: DHL_STMFlash_Write(u32 WriteAddr, u16 *pBuffer, u16 NumToWrite)
- * 功能描述: 从指定地址写入指定长度的数据
- * 函数说明:
- * 输 入: WriteAddr:起始地址 pBuffer:数据指针 NumToWrite:半字(16位)的个数
- * 返 回:
- * 设 计 者:RXJ 日期:2017-04-28
- * 修 改 者:RXJ 日期:2017-04-28
- ***********************************************************************/
- void DHL_STMFlash_Write(u32 WriteAddr, u16 *pBuffer, u16 NumToWrite)
- {
- u16 i;
- u32 secpos; //扇区地址
- u16 secoff; //扇区内偏移地址(16位字节计算)
- u16 secremain; //扇区内剩余地址(16位字节计算)
- u32 offaddr; //去掉0X08000000后的地址
-
- //判断地址是否合法
- if(WriteAddr < STM32_FLASH_BASE || (WriteAddr >= (STM32_FLASH_BASE + 1024 * STM32_FLASH_SIZE - NumToWrite*2)))
- {
- return;
- }
-
- FLASH_Unlock(); //解锁
-
- offaddr = WriteAddr - STM32_FLASH_BASE; //实际偏移地址
- secpos = offaddr / STM_SECTOR_SIZE; //扇区地址 0~127 for STM32F103RBT6; 0-255 for STM32F103RCT6
- secoff = (offaddr % STM_SECTOR_SIZE)/2; //在扇区内的偏移(u16占两个字节,故以两个字节为基本单位)
- secremain = STM_SECTOR_SIZE /2 -secoff; //扇区剩余空间大小(u16 占2个字节)
-
- if(NumToWrite <= secremain)
- {
- secremain = NumToWrite; //不大于该扇区范围
- }
-
- while(1)
- {
- DHL_STMFlash_Read(secpos*STM_SECTOR_SIZE + STM32_FLASH_BASE, STMFLASH_BUF, STM_SECTOR_SIZE / 2); //读出整个扇区的内容
-
- for(i = 0; i < secremain; i++) //校验数据是否为0xffff,STM32内部FLASH在写前保证所写扇区被擦除,即值为0xffff
- {
- if(STMFLASH_BUF[secoff + i] != 0XFFFF)
- {
- break;
- }
- }
-
- if(i < secremain) //需要擦除
- {
- FLASH_ErasePage(secpos*STM_SECTOR_SIZE + STM32_FLASH_BASE); //擦除这个扇区
-
- for(i = 0; i < secremain; i++) //复制
- {
- STMFLASH_BUF[i+secoff] = pBuffer[i];
- }
-
- DHL_STMFlash_Write_NoCheck(secpos*STM_SECTOR_SIZE + STM32_FLASH_BASE, STMFLASH_BUF, STM_SECTOR_SIZE / 2); //写入这个扇区
- }
- else
- {
- DHL_STMFlash_Write_NoCheck(WriteAddr, pBuffer, secremain); //扇区已经擦除的,直接写入扇区剩余空间
- }
-
- if(NumToWrite == secremain)
- {
- break; //写入结束了
- }
- else //写入未结束
- {
- secpos++; //扇区地址加1
- secoff = 0; //偏移地址为0
- pBuffer += secremain; //指针偏移
- WriteAddr += secremain; //写地址偏移
- NumToWrite -= secremain; //字节数(16位)递减
-
- if(NumToWrite > (STM_SECTOR_SIZE / 2))
- {
- secremain = STM_SECTOR_SIZE / 2; //下一个扇区还是写不完
- }
- else
- {
- secremain = NumToWrite; //下一个扇区可以写完了
- }
- }
- }
-
- FLASH_Lock(); //上锁
- }
- /***********************************************************************
- * 函 数 名: DHL_CompareBuffer
- * 功能描述: 比较两个数组中的数
- * 函数说明:
- * 输 入:
- * 返 回: 不等返回0 , 相等返回1
- * 设 计 者:RXJ 日期:2017-04-28
- * 修 改 者:RXJ 日期:2017-04-28
- ***********************************************************************/
- u16 DHL_CompareBuffer(u16 *pBuf1, u16 *pBuf2, int nCount)
- {
- u16 i;
- for(i = 0; i < nCount; i++)
- {
- if(pBuf1[i] != pBuf2[i])
- return 0;
- }
- return 1;
- }
-
- void System_SoftReset(void)
- {
- __set_FAULTMASK(1); //close interrupt
- NVIC_SystemReset(); //soft-reset
- }
- /******************* (C) COPYRIGHT 2017 LECOOAI *****END OF FILE****/
-
|