金牌会员
 
- 积分
- 2999
- 金钱
- 2999
- 注册时间
- 2016-5-13
- 在线时间
- 189 小时
|
发表于 2026-4-15 11:10:31
|
显示全部楼层
/**
* @brief 在FLASH 指定位置, 写入指定长度的数据(自动擦除)
* @note 因为STM32F4的扇区实在太大,没办法本地保存扇区数据,所以本函数写地址如果非0XFF
* ,那么会先擦除整个扇区且不保存扇区数据.所以写非0XFF的地址,将导致整个扇区数据丢失.
* 建议写之前确保扇区里没有重要数据,最好是整个扇区先擦除了,然后慢慢往后写.
* 该函数对OTP区域也有效!可以用来写OTP区!
* OTP区域地址范围:0X1FFF7800~0X1FFF7A0F(注意:最后16字节,用于OTP数据块锁定,别乱写!!)
* @param waddr : 起始地址 (此地址必须为4的倍数!!,否则写入出错!)
* @param pbuf : 数据指针
* @param length : 要写入的 字(32位)数(就是要写入的32位数据的个数)
* @retval 无
*/
void stmflash_write(uint32_t waddr, uint32_t *pbuf, uint32_t length)
{
FLASH_EraseInitTypeDef flasheraseinit;
HAL_StatusTypeDef FlashStatus=HAL_OK;
uint32_t addrx = 0;
uint32_t endaddr = 0;
uint32_t sectorerror=0;
if (waddr < STM32_FLASH_BASE || waddr % 4 || /* 写入地址小于 STM32_FLASH_BASE, 或不是4的整数倍, 非法. */
waddr > (STM32_FLASH_BASE + STM32_FLASH_SIZE)) /* 写入地址大于 STM32_FLASH_BASE + STM32_FLASH_SIZE, 非法. */
{
return;
}
HAL_FLASH_Unlock(); /* 解锁 */
FLASH->ACR &= ~(1 << 10); /* FLASH擦除期间,必须禁止数据缓存!!! */
addrx = waddr; /* 写入的起始地址 */
endaddr = waddr + length * 4; /* 写入的结束地址 */
if (addrx < 0X1FFF0000) /* 只有主存储区,才需要执行擦除操作!! */
{
while (addrx < endaddr) /* 扫清一切障碍.(对非FFFFFFFF的地方,先擦除) */
{
if (stmflash_read_word(addrx) != 0XFFFFFFFF) /* 有非0XFFFFFFFF的地方,要擦除这个扇区 */
{
flasheraseinit.TypeErase=FLASH_TYPEERASE_SECTORS; /* 擦除类型,扇区擦除 */
flasheraseinit.Sector=stmflash_get_flash_sector(addrx); /* 要擦除的扇区 */
flasheraseinit.NbSectors=1; /* 一次只擦除一个扇区 */
flasheraseinit.VoltageRange=FLASH_VOLTAGE_RANGE_3; /* 电压范围,VCC=2.7~3.6V之间!! */
if(HAL_FLASHEx_Erase(&flasheraseinit, §orerror) != HAL_OK)
{
break;/* 发生错误了 */
}
}
else
{
addrx += 4;
}
FLASH_WaitForLastOperation(FLASH_WAITETIME); /* 等待上次操作完成 */
}
}
FlashStatus=FLASH_WaitForLastOperation(FLASH_WAITETIME); /* 等待上次操作完成 */
if (FlashStatus==HAL_OK)
{
while (waddr < endaddr) /* 写数据 */
{
if (HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, waddr, *pbuf) != HAL_OK) /* 写入数据 */
{
break; /* 写入异常 */
}
waddr += 4;
pbuf++;
}
}
FLASH->ACR |= 1 << 10; /* FLASH擦除结束,开启数据fetch */
HAL_FLASH_Lock(); /* 上锁 */
} |
|