bs_bcu_app/bsp/bsp_flash.c

155 lines
5.3 KiB
C
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
****************************************************************************************************
* @file bsp_flash.c
* @author HF_ZQ
* @brief STM32内部FLASH读写 驱动代码
* @license Copyright (c) 2020-2050
****************************************************************************************************
**/
//#include "./SYSTEM/usart/usart.h"
//#include "./SYSTEM/delay/delay.h"
#include "bsp_flash.h"
/**
* @brief 从指定地址读取一个字 (32位数据)
* @param faddr : 读取地址 (此地址必须为4倍数!!)
* @retval 读取到的数据 (32位)
*/
uint32_t stmflash_read_word(uint32_t faddr)
{
return *(volatile uint32_t *)faddr;
}
/**
* @brief 获取某个地址所在的flash扇区
* @param addr : lash地址
* @retval 0~11,即addr所在的扇区
*/
uint8_t stmflash_get_flash_sector(uint32_t addr)
{
if (addr < ADDR_FLASH_SECTOR_1) return FLASH_SECTOR_0;
else if (addr < ADDR_FLASH_SECTOR_2) return FLASH_SECTOR_1;
else if (addr < ADDR_FLASH_SECTOR_3) return FLASH_SECTOR_2;
else if (addr < ADDR_FLASH_SECTOR_4) return FLASH_SECTOR_3;
else if (addr < ADDR_FLASH_SECTOR_5) return FLASH_SECTOR_4;
else if (addr < ADDR_FLASH_SECTOR_6) return FLASH_SECTOR_5;
else if (addr < ADDR_FLASH_SECTOR_7) return FLASH_SECTOR_6;
else if (addr < ADDR_FLASH_SECTOR_8) return FLASH_SECTOR_7;
else if (addr < ADDR_FLASH_SECTOR_9) return FLASH_SECTOR_8;
else if (addr < ADDR_FLASH_SECTOR_10) return FLASH_SECTOR_9;
else if (addr < ADDR_FLASH_SECTOR_11) return FLASH_SECTOR_10;
return FLASH_SECTOR_11;
}
/**
* @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, &sectorerror) != 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(); /* 上锁 */
}
/**
* @brief 从指定地址开始读出指定长度的数据
* @param raddr : 起始地址
* @param pbuf : 数据指针
* @param length: 要读取的字(32)数,即4个字节的整数倍
* @retval 无
*/
void stmflash_read(uint32_t raddr, uint32_t *pbuf, uint32_t length)
{
uint32_t i;
for (i = 0; i < length; i++)
{
pbuf[i] = stmflash_read_word(raddr); /* 读取4个字节. */
raddr += 4; /* 偏移4个字节. */
}
}
/******************************************************************************************/
/* 测试用代码 */
/**
* @brief 测试写数据(写1个字)
* @param waddr : 起始地址
* @param wdata : 要写入的数据
* @retval 读取到的数据
*/
void test_write(uint32_t waddr, uint32_t wdata)
{
stmflash_write(waddr, &wdata, 1); /* 写入一个字 */
}