#include "leaf_ota.h" #include "usart.h" #include "stdio.h" #include "string.h" #include "TerminalSlave485.h" #include "md5c.h" #include "main.h" /** * @brief 根据输入的地址给出它所在的sector * 例如: uwStartSector = GetSector(FLASH_USER_START_ADDR); uwEndSector = GetSector(FLASH_USER_END_ADDR); * @param Address:地址 * @retval 地址所在的sector */ static uint32_t GetSector(uint32_t Address) { uint32_t sector = 0; if((Address < ADDR_FLASH_SECTOR_1) && (Address >= ADDR_FLASH_SECTOR_0)) { sector = FLASH_SECTOR_0; } else if((Address < ADDR_FLASH_SECTOR_2) && (Address >= ADDR_FLASH_SECTOR_1)) { sector = FLASH_SECTOR_1; } else if((Address < ADDR_FLASH_SECTOR_3) && (Address >= ADDR_FLASH_SECTOR_2)) { sector = FLASH_SECTOR_2; } else if((Address < ADDR_FLASH_SECTOR_4) && (Address >= ADDR_FLASH_SECTOR_3)) { sector = FLASH_SECTOR_3; } else if((Address < ADDR_FLASH_SECTOR_5) && (Address >= ADDR_FLASH_SECTOR_4)) { sector = FLASH_SECTOR_4; } else if((Address < ADDR_FLASH_SECTOR_6) && (Address >= ADDR_FLASH_SECTOR_5)) { sector = FLASH_SECTOR_5; } else if((Address < ADDR_FLASH_SECTOR_7) && (Address >= ADDR_FLASH_SECTOR_6)) { sector = FLASH_SECTOR_6; } else/*(Address < FLASH_END_ADDR) && (Address >= ADDR_FLASH_SECTOR_23))*/ { sector = FLASH_SECTOR_7; } return sector; } //uint8_t Erase_page(uint32_t pageaddr, uint32_t num) //{ // /*要擦除的起始扇区(包含)及结束扇区(不包含),如8-12,表示擦除8、9、10、11扇区*/ // uint32_t FirstSector = 0; // uint32_t NbOfSectors = 0; // uint32_t SECTORError = 0; // static FLASH_EraseInitTypeDef EraseInitStruct; // __disable_irq(); // HAL_FLASH_Unlock(); // // FirstSector = GetSector(pageaddr); // NbOfSectors = GetSector(num)- FirstSector + 1; // /* 擦除用户区域 (用户区域指程序本身没有使用的空间,可以自定义)**/ // /* Fill EraseInit structure*/ // EraseInitStruct.TypeErase = FLASH_TYPEERASE_SECTORS; // EraseInitStruct.VoltageRange = FLASH_VOLTAGE_RANGE_3;/* 以“字”的大小进行操作 */ // EraseInitStruct.Sector = FirstSector; // EraseInitStruct.NbSectors = 1; // /* 开始擦除操作 */ // if (HAL_FLASHEx_Erase(&EraseInitStruct, &SECTORError) != HAL_OK) // { // /*擦除出错,返回,实际应用中可加入处理 */ // return -1; // } // // // HAL_FLASH_Lock(); // __enable_irq(); // return 1; //} int App2_MD5_Check(uint32_t addr,unsigned int all_len) { unsigned char digest[16]; // unsigned char *md5_ptr=(unsigned char *)(StartMode_Addr+72); unsigned int i,update_len; MD5_CTX md5c; all_len -= 16; MD5Init(&md5c); for(i=0;i(i+512)) update_len = 512; else update_len = all_len-i; memcpy(USART1_TX_BUF,(const void *)(addr+i),update_len); MD5Update (&md5c, USART1_TX_BUF, update_len); i += update_len; HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_2);//看门狗sp706 } MD5Final(digest,&md5c); memcpy(USART1_TX_BUF,(const void *)(addr+all_len),16); for(i=0;i<16;++i) { if(digest[i]!=USART1_TX_BUF[i]) break; } if(i>=16) return 1; else return 0; } /** * @bieaf 擦除页 * * @param pageaddr 起始地址 * @param num 擦除的页数 * @return 1 */ uint8_t Erase_page(uint32_t pageaddr, uint32_t num) { __disable_irq(); HAL_FLASH_Unlock(); /* 擦除FLASH*/ FLASH_EraseInitTypeDef FlashSet; FlashSet.TypeErase = FLASH_TYPEERASE_SECTORS; FlashSet.VoltageRange = FLASH_VOLTAGE_RANGE_3; FlashSet.Sector = GetSector(pageaddr); //FlashSet.NbSectors =(pageaddr+num-1); FlashSet.NbSectors=1; /*设置PageError,调用擦除函数*/ uint32_t PageError = 0; HAL_FLASHEx_Erase(&FlashSet, &PageError); HAL_FLASH_Lock(); __enable_irq(); return 1; } /** * @bieaf 写若干个数据 * * @param addr 写入的地址 * @param buff 写入数据的起始地址 * @param word_size 长度 * @return */ static void WriteFlash(uint32_t addr, uint32_t * buff, int word_size) { /* 1/4解锁FLASH*/ HAL_FLASH_Unlock(); for(int i = 0; i < word_size; i++) { /* 3/4对FLASH烧写*/ HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, addr + 4 * i, buff[i]); } /* 4/4锁住FLASH*/ HAL_FLASH_Lock(); } /** * @bieaf 读若干个数据 * * @param addr 读数据的地址 * @param buff 读出数据的数组指针 * @param word_size 长度 * @return */ static void ReadFlash(uint32_t addr, uint32_t * buff, uint16_t word_size) { //uint32_t get=0; for(int i =0; i < word_size; i++) { buff[i] = *(__IO uint32_t*)(addr + 4 * i); //buff[i] =((get&0x000000ff)<< 24)| ((get&0x0000ff00 ) << 8 )| (( get&0x00ff0000 ) >> 8 ) | ((get&0xff000000 )>> 24 ); } return; } /* 读取启动模式 */ unsigned int Read_Start_Mode(void) { unsigned int mode = 0; //ReadFlash((Application_2_Addr + Application_Size - 4), &mode, 1); ReadFlash(StartMode_Addr, &mode, 1); return mode; } /** * @bieaf 写若干个数据 * * @param addr 写入的地址 * @param buff 写入数据的起始地址 * @param word_size 长度 * @return */ void WriteFlash2(uint32_t addr, uint32_t *buff, int word_size) { /* 1/4解锁FLASH*/ HAL_FLASH_Unlock(); for(int i = 0; i < word_size; i++) { /* 3/4对FLASH烧写*/ HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, addr + 4 * i, buff[i]); } /* 4/4锁住FLASH*/ HAL_FLASH_Lock(); } /* 标记升级完成 */ void Set_Update_Down(void) { unsigned int update_flag = Startup_Update; ///< 对应bootloader的启动步骤 memcpy(USART1_TX_BUF,(void *)StartMode_Addr,256); memcpy(USART1_TX_BUF,&update_flag,4); Erase_page(StartMode_Addr, Appear_si); WriteFlash2(StartMode_Addr, (uint32_t *)USART1_TX_BUF, 64); } /** * @bieaf 进行程序的覆盖 * @detail 1.擦除目的地址 * 2.源地址的代码拷贝到目的地址 * 3.擦除源地址 * * @param 搬运的源地址 * @param 搬运的目的地址 * @return 搬运的程序大小 */ void MoveCode(unsigned int src_addr, unsigned int des_addr, unsigned int byte_size) { /*1.擦除目的地址*/ //printf("> Start erase des flash......\r\n"); //Erase_page(des_addr, (byte_size/PageSize)); HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_2);//看门狗sp706 Erase_page(des_addr, Appear_si); HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_2);//看门狗sp706 //printf("> Erase des flash down......\r\n"); /*2.开始拷贝*/ unsigned int temp[128]={0}; //printf("> Start copy......\r\n"); for(int i = 0; i < (byte_size+511)/512; i++) { HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_2);//看门狗sp706 ReadFlash((src_addr + i*512), temp, 128); HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_2);//看门狗sp706 WriteFlash((des_addr + i*512), temp, 128); HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_2);//看门狗sp706 } //printf("> Copy down......\r\n"); /*3.擦除源地址*/ //printf("> Start erase src flash......\r\n"); //Erase_page(src_addr, (byte_size/PageSize)); HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_2);//看门狗sp706 ;//Erase_page(src_addr, Appear_si); HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_2);//看门狗sp706 //HAL_NVIC_SystemReset(); //printf("> Erase src flash down......\r\n"); } ///* 采用汇编设置栈的值 */ //__asm void MSR_MSP (uint32_t ulAddr) //{ // MSR MSP, r0 //set Main Stack value // BX r14 //} ///* 程序跳转函数 */ //typedef void (*Jump_Fun)(void); //void IAP_ExecuteApp (uint32_t App_Addr) //{ // Jump_Fun JumpToApp; // //// if ( ( ( * ( __IO uint32_t * ) App_Addr ) & 0x2FE00000 ) == 0x20000000 ) //检查栈顶地址是否合法. //// { // JumpToApp = (Jump_Fun) * ( __IO uint32_t *)(App_Addr + 4); //用户代码区第二个字为程序开始地址(复位地址) // MSR_MSP( * ( __IO uint32_t * ) App_Addr ); //初始化APP堆栈指针(用户代码区的第一个字用于存放栈顶地址) // __disable_irq(); // JumpToApp(); //跳转到APP. //// } //} /* ********************************************************************************************************* * 函 数 名: JumpToBootloader * 功能说明: 跳转到系统BootLoader * 形 参: 无 * 返 回 值: 无 ********************************************************************************************************* */ static void JumpToBootloader(void) { uint32_t i=0; GPIO_InitTypeDef GPIO_InitStruct = {0}; void (*SysMemBootJump)(void); /* 声明一个函数指针 */ __IO uint32_t BootAddr = Application_1_Addr; /* STM32F4的系统BootLoader地址 */ HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_2);//看门狗sp706 /* 关闭全局中断 */ DISABLE_INT(); /* 关闭滴答定时器,复位到默认值 */ SysTick->CTRL = 0; SysTick->LOAD = 0; SysTick->VAL = 0; HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_2);//看门狗sp706 /* 设置所有时钟到默认状态,使用HSI时钟 */ HAL_RCC_DeInit(); __HAL_RCC_GPIOC_CLK_ENABLE(); //看门狗配置 初始化 /*Configure GPIO pin : PtPin */ GPIO_InitStruct.Pin = GPIO_PIN_2; if(0)//看门狗sp706 //if(1)//打开看门狗sp706 { // GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; } else { GPIO_InitStruct.Mode = GPIO_MODE_INPUT; } GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; HAL_GPIO_Init(GPIOC, &GPIO_InitStruct); // HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_2);//看门狗sp706 /* 关闭所有中断,清除所有中断挂起标志 */ for (i = 0; i < 8; i++) { NVIC->ICER[i]=0xFFFFFFFF; NVIC->ICPR[i]=0xFFFFFFFF; } // HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_2);//看门狗sp706 /* 使能全局中断 */ ENABLE_INT(); /* 跳转到系统BootLoader,首地址是MSP,地址+4是复位中断服务程序地址 */ SysMemBootJump = (void (*)(void)) (*((uint32_t *) (BootAddr + 4))); /* 设置主堆栈指针 */ __set_MSP(*(uint32_t *)BootAddr); // /* 在RTOS工程,这条语句很重要,设置为特权级模式,使用MSP指针 */ __set_CONTROL(0); /* 跳转到系统BootLoader */ // HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_2);//看门狗sp706 SysMemBootJump(); /* 跳转成功的话,不会执行到这里,用户可以在这里添加代码 */ while (1) { } } /** * @bieaf 进行BootLoader的启动 * * @param none * @return none */ void Start_BootLoader(void) { unsigned int update_flag = 0xAAAAAAAA; ///< 对应bootloader的启动步骤 unsigned int ModeStart; unsigned int i,all_len; // HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_2);//看门狗sp706 ModeStart=Read_Start_Mode(); switch(ModeStart) ///< 读取是否启动应用程序 */ { case Startup_Normal: ///< 正常启动 */ //在APP2中可以设定此标志位 使得下次重启之后进入APP1 { ;//printf("> Normal start......\r\n"); break; } case Startup_Update: ///< 升级再启动 */ { HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_2); //看门狗sp706 for (i = 0, all_len = 0; i < 4; ++i) { all_len = all_len << 8; all_len |= *(unsigned char *)(StartMode_Addr + 68 + i); } if ((*(unsigned int*)(Application_Buffer_Addr+6144)==Application_2_Addr) && App2_MD5_Check(Application_Buffer_Addr,all_len)) { MoveCode(Application_Buffer_Addr, Application_2_Addr, all_len);//假定程序大小为100k HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_2);//看门狗sp706 // printf("> Update down......\r\n"); update_flag = Startup_APP2; memcpy(USART1_TX_BUF,(void *)StartMode_Addr,256); Erase_page(StartMode_Addr, Appear_si); memcpy(USART1_TX_BUF,&update_flag,4); memcpy(USART1_TX_BUF+132,USART1_TX_BUF+68,4); WriteFlash2(StartMode_Addr, (uint32_t *)USART1_TX_BUF, 64); HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_2); /*for (i = 0, all_len = 0; i < 4; ++i) { all_len = all_len << 8; all_len |= *(unsigned char *)(StartMode_Addr + 68 + i); } if(App2_MD5_Check(Application_2_Addr,all_len)) JumpToAPP2();//*/ } // break; } case Startup_APP2: ///跳转到APP2 { for (i = 0, all_len = 0; i < 4; ++i) { all_len = all_len << 8; all_len |= *(unsigned char *)(StartMode_Addr + 132 + i); } if((*(unsigned int*)(Application_2_Addr+6144)==Application_2_Addr) && App2_MD5_Check(Application_2_Addr,all_len)) JumpToAPP2();// break; } case Startup_Reset: ///< 恢复出厂设置 目前没使用 */ { // printf("> Restore to factory program......\r\n"); break; } default: ///< 启动失败 { // printf("> Error:%X!!!......\r\n", Read_Start_Mode()); return; } } // /* 跳转到应用程序 */ //// HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_2);//看门狗sp706 // printf("> Start up......\r\n\r\n"); // //IAP_ExecuteApp(Application_1_Addr); // JumpToBootloader(); }