/* ********************************************************************************************************* * * 模块名称 : cpu内部falsh操作模块(for STM32H743 H750) * 文件名称 : bsp_cpu_flash.c * 版 本 : V1.1 * 说 明 : 提供读写CPU内部Flash的函数 * 修改记录 : * 版本号 日期 作者 说明 * V1.0 2019-09-20 armfly 正式发布 * V1.1 2019-10-03 armfly 写flash函数,修正长度不是32字节整数倍的bug,末尾补0写入。 * 解决HAL库函数的 HAL_FLASH_Program()的bug, * 问题现象是大批量连续编程失败(报编程指令顺序错, PGSERR1、 PGSERR2) * Copyright (C), 2019-2030, 安富莱电子 www.armfly.com * ********************************************************************************************************* */ #include "bsp_cpu_flash.h" #include /* ********************************************************************************************************* * 函数 ********************************************************************************************************* */ /* ********************************************************************************************************* * 宏定义 ********************************************************************************************************* */ //0x08020000 - 0x08000000 = 128k;//bootload 128k // every sector 448k /* ********************************************************************************************************* * 变量 ********************************************************************************************************* */ __IO uint32_t uwCRCValue; __IO uint32_t uwExpectedCRCValue; __IO uint32_t uwAppSize; uint8_t buf[1024]; uint32_t RecCount = 0; uint32_t RecCount0 = 0; uint32_t RecSize = 0; uint8_t RecCplt = 0; uint32_t filesize = 0; uint32_t Bus_Error=0; uint32_t update_index = 0; uint32_t update_index_true = 0; uint32_t update_sum = 0; uint32_t update_sum_true = 0; /* ********************************************************************************************************* * 函 数 名: bsp_GetSector * 功能说明: 根据地址计算扇区首地址 * 形 参: 无 * 返 回 值: 扇区号(0-7) ********************************************************************************************************* */ uint32_t bsp_GetSector(uint32_t Address) { uint32_t sector = 0; if (((Address < ADDR_FLASH_SECTOR_1_BANK1) && (Address >= ADDR_FLASH_SECTOR_0_BANK1)) || \ ((Address < ADDR_FLASH_SECTOR_1_BANK2) && (Address >= ADDR_FLASH_SECTOR_0_BANK2))) { sector = FLASH_SECTOR_0; } else if (((Address < ADDR_FLASH_SECTOR_2_BANK1) && (Address >= ADDR_FLASH_SECTOR_1_BANK1)) || \ ((Address < ADDR_FLASH_SECTOR_2_BANK2) && (Address >= ADDR_FLASH_SECTOR_1_BANK2))) { sector = FLASH_SECTOR_1; } else if (((Address < ADDR_FLASH_SECTOR_3_BANK1) && (Address >= ADDR_FLASH_SECTOR_2_BANK1)) || \ ((Address < ADDR_FLASH_SECTOR_3_BANK2) && (Address >= ADDR_FLASH_SECTOR_2_BANK2))) { sector = FLASH_SECTOR_2; } else if (((Address < ADDR_FLASH_SECTOR_4_BANK1) && (Address >= ADDR_FLASH_SECTOR_3_BANK1)) || \ ((Address < ADDR_FLASH_SECTOR_4_BANK2) && (Address >= ADDR_FLASH_SECTOR_3_BANK2))) { sector = FLASH_SECTOR_3; } else if (((Address < ADDR_FLASH_SECTOR_5_BANK1) && (Address >= ADDR_FLASH_SECTOR_4_BANK1)) || \ ((Address < ADDR_FLASH_SECTOR_5_BANK2) && (Address >= ADDR_FLASH_SECTOR_4_BANK2))) { sector = FLASH_SECTOR_4; } else if (((Address < ADDR_FLASH_SECTOR_6_BANK1) && (Address >= ADDR_FLASH_SECTOR_5_BANK1)) || \ ((Address < ADDR_FLASH_SECTOR_6_BANK2) && (Address >= ADDR_FLASH_SECTOR_5_BANK2))) { sector = FLASH_SECTOR_5; } else if (((Address < ADDR_FLASH_SECTOR_7_BANK1) && (Address >= ADDR_FLASH_SECTOR_6_BANK1)) || \ ((Address < ADDR_FLASH_SECTOR_7_BANK2) && (Address >= ADDR_FLASH_SECTOR_6_BANK2))) { sector = FLASH_SECTOR_6; } else if (((Address < ADDR_FLASH_SECTOR_0_BANK2) && (Address >= ADDR_FLASH_SECTOR_7_BANK1)) || \ ((Address < CPU_FLASH_END_ADDR) && (Address >= ADDR_FLASH_SECTOR_7_BANK2))) { sector = FLASH_SECTOR_7; } else { sector = FLASH_SECTOR_7; } return sector; } /* ********************************************************************************************************* * 函 数 名: bsp_ReadCpuFlash * 功能说明: 读取CPU Flash的内容 * 形 参: _ucpDst : 目标缓冲区 * _ulFlashAddr : 起始地址 * _ulSize : 数据大小(单位是字节) * 返 回 值: 0=成功,1=失败 ********************************************************************************************************* */ uint8_t bsp_ReadCpuFlash(uint32_t _ulFlashAddr, uint8_t *_ucpDst, uint32_t _ulSize) { uint32_t i; if (_ulFlashAddr + _ulSize > CPU_FLASH_BASE_ADDR + CPU_FLASH_SIZE) { return 1; } /* 长度为0时不继续操作,否则起始地址为奇地址会出错 */ if (_ulSize == 0) { return 1; } for (i = 0; i < _ulSize; i++) { *_ucpDst++ = *(uint8_t *)_ulFlashAddr++; } return 0; } /* ********************************************************************************************************* * 函 数 名: bsp_CmpCpuFlash * 功能说明: 比较Flash指定地址的数据. * 形 参: _ulFlashAddr : Flash地址 * _ucpBuf : 数据缓冲区 * _ulSize : 数据大小(单位是字节) * 返 回 值: * FLASH_IS_EQU 0 Flash内容和待写入的数据相等,不需要擦除和写操作 * FLASH_REQ_WRITE 1 Flash不需要擦除,直接写 * FLASH_REQ_ERASE 2 Flash需要先擦除,再写 * FLASH_PARAM_ERR 3 函数参数错误 ********************************************************************************************************* */ uint8_t bsp_CmpCpuFlash(uint32_t _ulFlashAddr, uint8_t *_ucpBuf, uint32_t _ulSize) { uint32_t i; uint8_t ucIsEqu; /* 相等标志 */ uint8_t ucByte; /* 如果偏移地址超过芯片容量,则不改写输出缓冲区 */ if (_ulFlashAddr + _ulSize > CPU_FLASH_BASE_ADDR + CPU_FLASH_SIZE) { return FLASH_PARAM_ERR; /* 函数参数错误 */ } /* 长度为0时返回正确 */ if (_ulSize == 0) { return FLASH_IS_EQU; /* Flash内容和待写入的数据相等 */ } ucIsEqu = 1; /* 先假设所有字节和待写入的数据相等,如果遇到任何一个不相等,则设置为 0 */ for (i = 0; i < _ulSize; i++) { ucByte = *(uint8_t *)_ulFlashAddr; if (ucByte != *_ucpBuf) { if (ucByte != 0xFF) { return FLASH_REQ_ERASE; /* 需要擦除后再写 */ } else { ucIsEqu = 0; /* 不相等,需要写 */ } } _ulFlashAddr++; _ucpBuf++; } if (ucIsEqu == 1) { return FLASH_IS_EQU; /* Flash内容和待写入的数据相等,不需要擦除和写操作 */ } else { return FLASH_REQ_WRITE; /* Flash不需要擦除,直接写 */ } } /* ********************************************************************************************************* * 函 数 名: bsp_EraseCpuFlash * 功能说明: 擦除CPU FLASH一个扇区 (128KB) * 形 参: _ulFlashAddr : Flash地址 * 返 回 值: 0 成功, 1 失败 * HAL_OK = 0x00, * HAL_ERROR = 0x01, * HAL_BUSY = 0x02, * HAL_TIMEOUT = 0x03 * ********************************************************************************************************* */ uint8_t bsp_EraseCpuFlash(uint32_t _ulFlashAddr) { uint32_t FirstSector = 0, NbOfSectors = 0; FLASH_EraseInitTypeDef EraseInitStruct; uint32_t SECTORError = 0; uint8_t re; /* 解锁 */ HAL_FLASH_Unlock(); /* 获取此地址所在的扇区 */ FirstSector = bsp_GetSector(_ulFlashAddr); /* 固定1个扇区 */ NbOfSectors = 1; /* 擦除扇区配置 */ EraseInitStruct.TypeErase = FLASH_TYPEERASE_SECTORS; EraseInitStruct.VoltageRange = FLASH_VOLTAGE_RANGE_3; if (_ulFlashAddr >= ADDR_FLASH_SECTOR_0_BANK2) { EraseInitStruct.Banks = FLASH_BANK_2; } else { EraseInitStruct.Banks = FLASH_BANK_1; } EraseInitStruct.Sector = FirstSector; EraseInitStruct.NbSectors = NbOfSectors; /* 扇区擦除 */ re = HAL_FLASHEx_Erase(&EraseInitStruct, &SECTORError); /* 擦除完毕后,上锁 */ HAL_FLASH_Lock(); return re; } /* ********************************************************************************************************* * 函 数 名: bsp_WriteCpuFlash * 功能说明: 写数据到CPU 内部Flash。 必须按32字节整数倍写。不支持跨扇区。扇区大小128KB. \ * 写之前需要擦除扇区. 长度不是32字节整数倍时,最后几个字节末尾补0写入. * 形 参: _ulFlashAddr : Flash地址 * _ucpSrc : 数据缓冲区 * _ulSize : 数据大小(单位是字节, 必须是32字节整数倍) * 返 回 值: 0-成功,1-数据长度或地址溢出,2-写Flash出错(估计Flash寿命到) ********************************************************************************************************* */ uint8_t bsp_WriteCpuFlash(uint32_t _ulFlashAddr, uint8_t *_ucpSrc, uint32_t _ulSize) { uint32_t i; uint8_t ucRet; /* 如果偏移地址超过芯片容量,则不改写输出缓冲区 */ if (_ulFlashAddr + _ulSize > CPU_FLASH_BASE_ADDR + CPU_FLASH_SIZE) { return 1; } /* 长度为0时不继续操作 */ if (_ulSize == 0) { return 0; } ucRet = bsp_CmpCpuFlash(_ulFlashAddr, _ucpSrc, _ulSize); if (ucRet == FLASH_IS_EQU) { return 0; } __set_PRIMASK(1); /* 关中断 */ /* FLASH 解锁 */ HAL_FLASH_Unlock(); for (i = 0; i < _ulSize / 32; i++) { uint64_t FlashWord[4]; memcpy((char *)FlashWord, _ucpSrc, 32); _ucpSrc += 32; if (HAL_FLASH_Program(FLASH_TYPEPROGRAM_FLASHWORD, _ulFlashAddr, (uint64_t)((uint32_t)FlashWord)) == HAL_OK) { _ulFlashAddr = _ulFlashAddr + 32; /* 递增,操作下一个256bit */ } else { goto err; } } /* 长度不是32字节整数倍 */ if (_ulSize % 32) { uint64_t FlashWord[4]; FlashWord[0] = 0; FlashWord[1] = 0; FlashWord[2] = 0; FlashWord[3] = 0; memcpy((char *)FlashWord, _ucpSrc, _ulSize % 32); if (HAL_FLASH_Program(FLASH_TYPEPROGRAM_FLASHWORD, _ulFlashAddr, (uint64_t)((uint32_t)FlashWord)) == HAL_OK) { ; // _ulFlashAddr = _ulFlashAddr + 32; } else { goto err; } } /* Flash 加锁,禁止写Flash控制寄存器 */ HAL_FLASH_Lock(); __set_PRIMASK(0); /* 开中断 */ return 0; err: /* Flash 加锁,禁止写Flash控制寄存器 */ HAL_FLASH_Lock(); __set_PRIMASK(0); /* 开中断 */ return 1; } /* ********************************************************************************************************* * 函 数 名: JumpToApp * 功能说明: 跳转到应用JumpToApp * 形 参: 无 * 返 回 值: 无 ********************************************************************************************************* */ void JumpToApp(void) { uint32_t i=0; void (*AppJump)(void); /* 声明一个函数指针 */ /* 关闭全局中断 */ DISABLE_INT(); /* 设置所有时钟到默认状态,使用HSI时钟 */ __HAL_RCC_GPIOH_CLK_DISABLE(); __HAL_RCC_GPIOB_CLK_DISABLE(); HAL_RCC_DeInit(); /* 关闭滴答定时器,复位到默认值 */ SysTick->CTRL = 0; SysTick->LOAD = 0; SysTick->VAL = 0; /* 关闭所有中断,清除所有中断挂起标志 */ for (i = 0; i < 8; i++) { NVIC->ICER[i]=0xFFFFFFFF; NVIC->ICPR[i]=0xFFFFFFFF; } /* 使能全局中断 */ ENABLE_INT(); /* 跳转到应用程序,首地址是MSP,地址+4是复位中断服务程序地址 */ AppJump = (void (*)(void)) (*((uint32_t *) (App_Run_Addr + 4))); /* 设置主堆栈指针 */ __set_MSP(*(uint32_t *)App_Run_Addr); /* 在RTOS工程,这条语句很重要,设置为特权级模式,使用MSP指针 */ __set_CONTROL(0); /* 跳转到系统BootLoader */ AppJump(); /* 跳转成功的话,不会执行到这里,用户可以在这里添加代码 */ while (1) { } } /* ********************************************************************************************************* * 函 数 名: JumpToApp * 功能说明: 跳转到应用JumpToApp * 形 参: 无 * 返 回 值: 无 ********************************************************************************************************* */ void Copy_Download_Flash_to_Start() { uint32_t startIndex=0; for(startIndex = 0; startIndex < 3; startIndex++) { bsp_EraseCpuFlash((uint32_t)(App_Run_Addr + startIndex*128*1024));//Erase this function } uint8_t readData[32]; uint32_t total=3*128*1024/sizeof(readData); uint8_t retult=0; for(startIndex=0;startIndex