You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
172 lines
4.4 KiB
172 lines
4.4 KiB
|
3 days ago
|
#include "stmflash.h"
|
||
|
|
#ifdef USE_ONCHIP_FLASH
|
||
|
|
#include <string.h>
|
||
|
|
|
||
|
|
#ifndef STM32_FLASH_SIZE
|
||
|
|
#define STM32_FLASH_SIZE 256
|
||
|
|
#endif
|
||
|
|
|
||
|
|
extern void Flow_control_before(void);
|
||
|
|
extern void Flow_control_after(void);
|
||
|
|
|
||
|
|
const uint32_t FLASH_SECTOR_SIZE_MAP[] =
|
||
|
|
{
|
||
|
|
16 * 1024,
|
||
|
|
16 * 1024,
|
||
|
|
16 * 1024,
|
||
|
|
16 * 1024, // 0-3
|
||
|
|
64 * 1024, // 4
|
||
|
|
128 * 1024,
|
||
|
|
128 * 1024,
|
||
|
|
128 * 1024,
|
||
|
|
128 * 1024, // 5-8
|
||
|
|
128 * 1024,
|
||
|
|
128 * 1024,
|
||
|
|
128 * 1024,
|
||
|
|
128 * 1024 // 9-11
|
||
|
|
};
|
||
|
|
#define TOTAL_SECTORS (sizeof(FLASH_SECTOR_SIZE_MAP) / sizeof(FLASH_SECTOR_SIZE_MAP[0]))
|
||
|
|
|
||
|
|
static uint8_t STMFLASH_GetSectorNumber(uint32_t Address)
|
||
|
|
{
|
||
|
|
if (Address < FLASH_BASE) return 0xFF;
|
||
|
|
uint32_t offset = Address - FLASH_BASE;
|
||
|
|
uint32_t current_addr = 0;
|
||
|
|
|
||
|
|
for (uint8_t i = 0; i < TOTAL_SECTORS; i++)
|
||
|
|
{
|
||
|
|
if (offset < current_addr + FLASH_SECTOR_SIZE_MAP[i])
|
||
|
|
return i;
|
||
|
|
current_addr += FLASH_SECTOR_SIZE_MAP[i];
|
||
|
|
if (current_addr >= (STM32_FLASH_SIZE * 1024)) break;
|
||
|
|
}
|
||
|
|
return 0xFF;
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
static uint32_t STMFLASH_GetSectorStartAddr(uint8_t Sector_Num)
|
||
|
|
{
|
||
|
|
if (Sector_Num >= TOTAL_SECTORS) return 0;
|
||
|
|
uint32_t addr = FLASH_BASE;
|
||
|
|
for (uint8_t i = 0; i < Sector_Num; i++)
|
||
|
|
addr += FLASH_SECTOR_SIZE_MAP[i];
|
||
|
|
return addr;
|
||
|
|
}
|
||
|
|
|
||
|
|
static uint32_t STMFLASH_GetSectorSize(uint8_t Sector_Num)
|
||
|
|
{
|
||
|
|
if (Sector_Num >= TOTAL_SECTORS) return 0;
|
||
|
|
return FLASH_SECTOR_SIZE_MAP[Sector_Num];
|
||
|
|
}*/
|
||
|
|
|
||
|
|
static uint8_t STMFLASH_CheckBlank(uint32_t StartAddr, uint32_t NumToCheck)
|
||
|
|
{
|
||
|
|
volatile uint8_t *p = (volatile uint8_t *)StartAddr;
|
||
|
|
for (uint32_t i = 0; i < NumToCheck; i++)
|
||
|
|
{
|
||
|
|
if (p[i] != 0xFF)
|
||
|
|
return 0; // 有数据
|
||
|
|
}
|
||
|
|
return 1; // 空白
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* @brief 读取单字节
|
||
|
|
*/
|
||
|
|
uint8_t STMFLASH_ReadByte(uint32_t faddr)
|
||
|
|
{
|
||
|
|
return *(volatile uint8_t *)faddr;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* @brief 读取多个字节
|
||
|
|
* @param ReadAddr: 起始地址
|
||
|
|
* @param pBuffer: 数据缓冲区 (uint8_t*)
|
||
|
|
* @param NumToRead: 读取字节数
|
||
|
|
*/
|
||
|
|
void STMFLASH_Read(uint32_t ReadAddr, uint8_t *pBuffer, uint32_t NumToRead)
|
||
|
|
{
|
||
|
|
volatile uint8_t *p = (volatile uint8_t *)ReadAddr;
|
||
|
|
for (uint32_t i = 0; i < NumToRead; i++)
|
||
|
|
{
|
||
|
|
pBuffer[i] = p[i];
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* @brief 底层写入 (无检查) - 支持字节写入
|
||
|
|
* @note 调用前必须确保扇区已擦除!
|
||
|
|
*/
|
||
|
|
HAL_StatusTypeDef STMFLASH_Write_NoCheck(uint32_t WriteAddr, uint8_t *pBuffer, uint32_t NumToWrite)
|
||
|
|
{
|
||
|
|
HAL_StatusTypeDef status = HAL_OK;
|
||
|
|
|
||
|
|
// F4 支持字节写入,但地址最好是偶数。如果是奇数地址,HAL 库通常也能处理,但性能稍差。
|
||
|
|
// 这里直接使用 HAL_FLASH_Program 的 BYTE 模式
|
||
|
|
|
||
|
|
for (uint32_t i = 0; i < NumToWrite; i++)
|
||
|
|
{
|
||
|
|
__disable_irq();
|
||
|
|
|
||
|
|
// 使用 FLASH_TYPEPROGRAM_BYTE 进行 8 位写入
|
||
|
|
status = HAL_FLASH_Program(FLASH_TYPEPROGRAM_BYTE, WriteAddr, pBuffer[i]);
|
||
|
|
|
||
|
|
__enable_irq();
|
||
|
|
|
||
|
|
if (status != HAL_OK)
|
||
|
|
break;
|
||
|
|
|
||
|
|
WriteAddr++;
|
||
|
|
}
|
||
|
|
return status;
|
||
|
|
}
|
||
|
|
|
||
|
|
HAL_StatusTypeDef STMFLASH_EraseSector(uint8_t Sector_Num)
|
||
|
|
{
|
||
|
|
FLASH_EraseInitTypeDef EraseInitStruct;
|
||
|
|
uint32_t SectorError = 0;
|
||
|
|
|
||
|
|
if (Sector_Num >= TOTAL_SECTORS) return HAL_ERROR;
|
||
|
|
|
||
|
|
EraseInitStruct.TypeErase = FLASH_TYPEERASE_SECTORS;
|
||
|
|
EraseInitStruct.Sector = Sector_Num;
|
||
|
|
EraseInitStruct.NbSectors = 1;
|
||
|
|
EraseInitStruct.VoltageRange = FLASH_VOLTAGE_RANGE_3;
|
||
|
|
|
||
|
|
HAL_FLASH_Unlock();
|
||
|
|
HAL_StatusTypeDef status = HAL_FLASHEx_Erase(&EraseInitStruct, &SectorError);
|
||
|
|
HAL_FLASH_Lock();
|
||
|
|
|
||
|
|
return status;
|
||
|
|
}
|
||
|
|
|
||
|
|
HAL_StatusTypeDef STMFLASH_EraseByAddress(uint32_t Address)
|
||
|
|
{
|
||
|
|
uint8_t sectorNum = STMFLASH_GetSectorNumber(Address);
|
||
|
|
if (sectorNum == 0xFF) return HAL_ERROR;
|
||
|
|
return STMFLASH_EraseSector(sectorNum);
|
||
|
|
}
|
||
|
|
|
||
|
|
HAL_StatusTypeDef STMFLASH_Write(uint32_t WriteAddr, uint8_t *pBuffer, uint32_t NumToWrite)
|
||
|
|
{
|
||
|
|
if (NumToWrite == 0) return HAL_OK;
|
||
|
|
if (WriteAddr < FLASH_BASE) return HAL_ERROR;
|
||
|
|
|
||
|
|
uint32_t endAddr = WriteAddr + NumToWrite;
|
||
|
|
if (endAddr > (FLASH_BASE + (STM32_FLASH_SIZE * 1024))) return HAL_ERROR;
|
||
|
|
|
||
|
|
// 检查是否为空
|
||
|
|
if (!STMFLASH_CheckBlank(WriteAddr, NumToWrite))
|
||
|
|
{
|
||
|
|
return HAL_ERROR; // 区域未擦除,拒绝写入
|
||
|
|
}
|
||
|
|
|
||
|
|
Flow_control_before();
|
||
|
|
HAL_FLASH_Unlock();
|
||
|
|
HAL_StatusTypeDef status = STMFLASH_Write_NoCheck(WriteAddr, pBuffer, NumToWrite);
|
||
|
|
HAL_FLASH_Lock();
|
||
|
|
Flow_control_after();
|
||
|
|
return status;
|
||
|
|
}
|
||
|
|
#endif
|