optical/NxFuncs/stiap/stflash.c
2025-09-04 09:45:08 +08:00

611 lines
12 KiB
C
Raw 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.

#include "stflash.h"
#include "trigger.h"
//--------------------------------------------------------------------
#define STM32_FLASH_TIMOUT -1 // 超时
#define STM32_FLASH_OK 0 // 操作完成
#define STM32_FLASH_BUSY 1 // 忙
#define STM32_FLASH_ERROR 2 // 错误
//--------------------------------------------------------------------
#define MAX_WAIT_TIME 2000 // 最大等待时间2秒
//--------------------------------------------------------------------
// 等待操作完成
// waitms等待时间(ms)
int FlashWaitNoBusy(int waitms)
{
int timout = waitms;
u32 timer;
u32 tick = GetMsSoftTimer();
do
{
if (READ_BIT(FLASH->SR, FLASH_SR_BSY) != (FLASH_SR_BSY))
{
break;
}
timer = GetMsSoftTimer();
if ((timer - tick) > timout)
{
return STM32_FLASH_TIMOUT;
}
}while (1);
if ((FLASH->SR & (FLASH_SR_EOP)) != 0)
{
CLEAR_BIT(FLASH->SR, FLASH_SR_EOP);
}
#if (0)
timer = GetMsSoftTimer();
printf("FlashWaitNoBusy time=%d\r\n", timer - tick);
#endif
return STM32_FLASH_OK;
}
// 读取状态
int FLASHGetStatus(void)
{
u32 temp = FLASH->SR;
if ((temp & FLASH_SR_BSY) != 0)
{
return STM32_FLASH_BUSY; // 忙
}
#if (__CORTEX_M == 0 || __CORTEX_M == 3)
if ((temp & ( FLASH_SR_WRPRTERR | // 写保护错误
FLASH_SR_PGERR | // 编程错误
0 ) ) != 0)
#elif (__CORTEX_M == 4)
else if ((temp & ( FLASH_SR_WRPERR | // 写保护错误
FLASH_SR_PGAERR | // 编程对齐错误
FLASH_SR_PGPERR | // 并行位数错误
FLASH_SR_PGSERR | // 编程顺序错误
// FLASH_SR_RDERR |
0 ) ) != 0)
#endif
{
return STM32_FLASH_ERROR; // 操作错误
}
return STM32_FLASH_OK; // 操作完成
}
// 得到扇区编号
int GetFlashSectorIdx(u32 faddr)
{
#if (__CORTEX_M == 0 || __CORTEX_M == 3)
if (faddr >= STM32_FLASH_BASE)
{
faddr -= STM32_FLASH_BASE;
if (faddr <= STM32_FLASH_SIZE)
{
faddr /= STM32_FLASH_SEC_SIZE;
if (faddr < STM32_FLASH_SEC_NUM)
{
return faddr;
}
}
}
#elif (__CORTEX_M == 4)
#define FLS_RGCK(ad) \
if (faddr < STM32_FLASH_ADDR_SECTOR_##ad)\
{\
return (ad-1);\
}\
else \
//------
FLS_RGCK(0)
FLS_RGCK(1)
FLS_RGCK(2)
FLS_RGCK(3)
FLS_RGCK(4)
FLS_RGCK(5)
FLS_RGCK(6)
FLS_RGCK(7)
if (faddr < STM32_FLASH_ADDR_SECTOR_7 + STM32_FLASH_SIZE_SECTOR_7)
{
return 7;
}
#endif
return -1;
}
u32 GetFlashSectorBegAddr(u32 sidx)
{
u32 addr = STM32_FLASH_BASE;
#if (__CORTEX_M == 0 || __CORTEX_M == 3)
if (sidx < STM32_FLASH_SEC_NUM)
{
addr += sidx * STM32_FLASH_SEC_SIZE;
}
else
{
addr += STM32_FLASH_SIZE;
}
#elif (__CORTEX_M == 4)
switch (sidx)
{
case 0:
addr = STM32_FLASH_ADDR_SECTOR_0;
break;
case 1:
addr = STM32_FLASH_ADDR_SECTOR_1;
break;
case 2:
addr = STM32_FLASH_ADDR_SECTOR_2;
break;
case 3:
addr = STM32_FLASH_ADDR_SECTOR_3;
break;
case 4:
addr = STM32_FLASH_ADDR_SECTOR_4;
break;
case 5:
addr = STM32_FLASH_ADDR_SECTOR_5;
break;
case 6:
addr = STM32_FLASH_ADDR_SECTOR_6;
break;
case 7:
addr = STM32_FLASH_ADDR_SECTOR_7;
break;
default:
break;
}
#endif
return addr;
}
int GetFlashSectorSize(u32 sidx)
{
int size = 0;
#if (__CORTEX_M == 0 || __CORTEX_M == 3)
size = STM32_FLASH_SEC_SIZE;
#elif (__CORTEX_M == 4)
switch (sidx)
{
case 0:
size = STM32_FLASH_SIZE_SECTOR_0;
break;
case 1:
size = STM32_FLASH_SIZE_SECTOR_1;
break;
case 2:
size = STM32_FLASH_SIZE_SECTOR_2;
break;
case 3:
size = STM32_FLASH_SIZE_SECTOR_3;
break;
case 4:
size = STM32_FLASH_SIZE_SECTOR_4;
break;
case 5:
size = STM32_FLASH_SIZE_SECTOR_5;
break;
case 6:
size = STM32_FLASH_SIZE_SECTOR_6;
break;
case 7:
size = STM32_FLASH_SIZE_SECTOR_7;
break;
default:
break;
}
#endif
return size;
}
int GetSecRemainSize(u32 faddr)
{
int sidx = GetFlashSectorIdx(faddr);
int slen = GetFlashSectorSize(sidx);
u32 baddr = GetFlashSectorBegAddr(sidx);
if (sidx < 0 || slen <= 0)
{
return -1;
}
return (baddr + slen - faddr);
}
//--------------------------------------------------------------------
// 解锁
void FLASHUnlock()
{
// printf("FLASHUnlock beg\r\n");
if (READ_BIT(FLASH->CR, FLASH_CR_LOCK) != RESET)
{
WRITE_REG(FLASH->KEYR, FLASH_KEY1);
WRITE_REG(FLASH->KEYR, FLASH_KEY2);
}
while((READ_BIT(FLASH->CR, FLASH_CR_LOCK) != RESET))
{}
// printf("FLASHUnlock ok\r\n");
}
// 锁定
void FLASHLock()
{
// printf("FLASHLock\r\n");
SET_BIT(FLASH->CR, FLASH_CR_LOCK); // 锁定
}
// STM32 flash 写入代码
// 读取指定地址的半字
// faddr:读地址(此地址必须为2的倍数)
// data: 数据
void FLASHProgramHalfWord(uint32_t faddr, uint16_t data)
{
#if (__CORTEX_M == 4)
CLEAR_BIT(FLASH->CR, FLASH_CR_PSIZE);
SET_BIT(FLASH->CR, FLASH_PSIZE_HALF_WORD); // 按半字写入
#endif
SET_BIT(FLASH->CR, FLASH_CR_PG); // 编程
*(__IO uint16_t*)faddr = data;
}
// STM32 flash 读出代码
// 读取指定地址的半字(16位数据)
// faddr:读地址(此地址必须为2的倍数)
// 返回值:对应数据
u16 FlashRDHalfWord(u32 faddr)
{
return *( __IO uint16_t*)faddr;
}
// 擦除扇区
void FLASHEraseSector(uint32_t secIdx)
{
#if (__CORTEX_M == 0 || __CORTEX_M == 3)
SET_BIT(FLASH->CR, FLASH_CR_PER);
WRITE_REG(FLASH->AR, secIdx * STM32_FLASH_SEC_SIZE + STM32_FLASH_BASE);
SET_BIT(FLASH->CR, FLASH_CR_STRT);
#elif (__CORTEX_M == 4)
CLEAR_BIT(FLASH->CR, FLASH_CR_PSIZE);
SET_BIT(FLASH->CR, FLASH_PSIZE_HALF_WORD); // 按半字写入
SET_BIT(FLASH->CR, FLASH_CR_SER); // 设置擦除方式
CLEAR_BIT(FLASH->CR, FLASH_CR_SNB); // 清除地址
FLASH->CR |= (secIdx << FLASH_CR_SNB_Pos); // 设置地址
SET_BIT(FLASH->CR, FLASH_CR_STRT); // 开始擦除
#endif
}
//-----------------------------------------------
// 不检查的写入
// wrAddr: 起始地址
// pBuffer: 数据指针
// hwNumToWrite: 半字(16位)数
int STMFlashWrNoCheck(u32 wrAddr, u16 *pBuffer, u16 hwNumToWrite)
{
int rslt;
u16 i;
for (i = 0; i < hwNumToWrite; i++)
{
FLASHProgramHalfWord(wrAddr, *pBuffer);
pBuffer++;
wrAddr += 2; // 地址增加2
// 等待写入完成
rslt = FlashWaitNoBusy(MAX_WAIT_TIME);
if (rslt != STM32_FLASH_OK)
{
rslt = FLASHGetStatus();
break;
}
FLASH->CR &= (~FLASH_CR_PG);
}
return rslt;
}
//-----------------------------------------------
// 擦除扇区过程
int FLASHEraseSectorProc(uint32_t secIdx)
{
int rslt;
if (secIdx < 0 || secIdx >= STM32_FLASH_SEC_NUM)
{
return STM32_FLASH_ERROR;
}
rslt = FlashWaitNoBusy(MAX_WAIT_TIME);
if (rslt != STM32_FLASH_OK)
{
rslt = FLASHGetStatus();
return rslt;
}
FLASHEraseSector(secIdx);
rslt = FlashWaitNoBusy(MAX_WAIT_TIME);
if (rslt != STM32_FLASH_OK)
{
rslt = FLASHGetStatus();
return rslt;
}
#if (__CORTEX_M == 0 || __CORTEX_M == 3)
CLEAR_BIT(FLASH->CR, FLASH_CR_PER);
#elif (__CORTEX_M == 4)
CLEAR_BIT(FLASH->CR, (FLASH_CR_SER | FLASH_CR_SNB));
#endif
return STM32_FLASH_OK;
}
//-----------------------------------------------
void STMFlashUnlock()
{
FLASHUnlock();
}
void STMFlashLock()
{
FLASHLock();
}
int STMFlashErase(u32 secIdx, int secnums)
{
int rslt = 0;
FLASHUnlock();
for (int i = 0; i < secnums; i++)
{
rslt = FLASHEraseSectorProc(secIdx);
if (rslt != STM32_FLASH_OK)
{
printf("STMFlashErase error, rslt=%d\r\n", rslt);
rslt = -1;
break;
}
#if (0)
if (STMFlashCheck(secIdx * STM32_FLASH_SEC_SIZE + STM32_FLASH_BASE, 0, STM32_FLASH_SEC_SIZE) != 0)
{
printf("STMFlashErase and STMFlashCheck err, \r\n");
}
#endif
secIdx++;
}
FLASHLock(); // 上锁
return rslt;
}
//-----------------------------------------------
// 从指定地址开始读出指定长度的数据
// rdAddr: 起始地址
// pBuffer: 数据指针
// hwNumOfRead: 半字(16位)数
int STMFlashRead(u32 rdAddr, u16 * pBuffer, u16 hwNumOfRead)
{
u16 i;
if (pBuffer == NULL ||
rdAddr < STM32_FLASH_BASE ||
rdAddr + hwNumOfRead*2 > STM32_FLASH_BASE+STM32_FLASH_SIZE)
{
return -1;
}
for (i = 0; i < hwNumOfRead; i++)
{
*pBuffer = FlashRDHalfWord(rdAddr); // 读取2个字节
pBuffer++;
rdAddr += 2; // 地址增加2
}
return 0;
}
// 从指定地址开始比较指定长度的数据是否一致
// ckAddr: 起始地址
// pBuffer: 数据指针
// hwNumOfChekc: 半字(16位)数
// 返回值: 0, 全部符合
// 其他,不符合
int STMFlashCheck(u32 ckAddr, u16 * pBuffer, u16 hwNumOfChekc)
{
int i;
u16 tprd, tpdat;
for(i = 0; i < hwNumOfChekc; i++)
{
tprd = FlashRDHalfWord(ckAddr); // 读取2个字节
if (pBuffer != NULL)
{
tpdat = *pBuffer;
}
else
{
tpdat = 0xffff;
}
if (tpdat != tprd)
{
printf("STMFlashCheck error, tpdat=0x%x, tprd=0x%x, i=%d\r\n", tpdat, tprd, i);
return 1;
}
if (pBuffer != NULL)
{
pBuffer++;
}
ckAddr += 2; // 地址增加2
}
return 0;
}
// 从指定地址开始写入指定长度的数据
// wrAddr: 起始地址(此地址必须为2的倍数)
// pBuffer: 数据指针
// hwNumToWrite: 半字(16位)数(就是要写入的16位数据的个数)
// svwhenera == 0, 擦除时不保留写入区域之外的数据
// svwhenera == 1, 擦除时保留写入区域之前的数据
// svwhenera == 2, 擦除时保留写入区域之后的数据
// svwhenera == 3, 擦除时保留写入区域之外的数据
// 使用sdram 的一段空间最大128K
int STMFlashWrite(u32 wrAddr, u16 * pBuffer, u16 hwNumToWrite, int svwhenera)
{
int rslt;
u16 * thiswrbuff;
u32 addr, addrEnd, thiswraddr;
u32 wrlen, thiswrlen;
int thissidx, thisslen;
u32 thisaddr, thislen;
#if (NO_BUFF_WHEN_WT == 0)
u32 i;
u16 tempbuf[STM32_FLASH_SEC_SIZE/2];
#endif
addr = wrAddr;
wrlen = hwNumToWrite * 2;
addrEnd = wrAddr + wrlen;
if (wrAddr < STM32_FLASH_BASE || (addrEnd > (STM32_FLASH_BASE + STM32_FLASH_SIZE)))
{
return -1; // 非法地址
}
FLASHUnlock(); // 解锁flash
//
while (addr < addrEnd)
{
thisaddr = addr; // 起始地址
thissidx = GetFlashSectorIdx(thisaddr);
thisslen = GetFlashSectorSize(thissidx);
if (thissidx < 0 || thisslen <= 0)
{
return -1;
}
thislen = GetSecRemainSize(thisaddr); // 剩余长度
if (thislen > wrlen)
{
thislen = wrlen;
}
rslt = FlashWaitNoBusy(MAX_WAIT_TIME);
if (rslt != STM32_FLASH_OK)
{
rslt = FLASHGetStatus();
printf("STMFlashWrite error, FlashWaitNoBusy=%d\r\n", rslt);
return rslt;
}
#if (NO_BUFF_WHEN_WT == 0)
// 判断是否需要擦除
STMFlashRead(thisaddr, tempbuf, thislen/2); // 读出内容
for (i = 0; i < thislen/2; i++) // 检验数据是否需要擦除
{
#if (1) // st 内部 flash 不支持写过后的flash把某些1位变成0位外置 flash支持
if (tempbuf[i] != 0xffff) // 只要不是全1, 就擦除
#else
if ((tempbuf[i] & pBuffer[i]) != pBuffer[i]) // 与之后,和要写入数据相同,可以不擦除
#endif
{
break; // 需要擦除
}
}
if (i < thislen/2) // 需要擦除
{
u32 secbegaddr;
u8* wrbufaddr;
// printf("\r\nErase sector %d\r\n", thissidx);
secbegaddr = GetFlashSectorBegAddr(thissidx);
// 读取扇区所有数据
if (thisaddr != secbegaddr || thislen != thisslen)
{
STMFlashRead(secbegaddr, tempbuf, thisslen/2);
}
// 擦除扇区
if (FLASHEraseSectorProc(thissidx) != STM32_FLASH_OK) // 擦除这个扇区
{
printf("\r\nErase sector %d error\r\n", thissidx);
break;
}
// 复制要写入的数据到缓冲区
wrbufaddr = (u8*)tempbuf;
wrbufaddr += thisaddr-secbegaddr;
memcpy(wrbufaddr, pBuffer, thislen);
if (svwhenera == 0) // 擦除时不保留写入区域之外的数据
{
thiswraddr = thisaddr;
thiswrbuff = pBuffer;
thiswrlen = thislen;
}
else if (svwhenera == 1) // 擦除时保留写入区域之前的数据
{
thiswraddr = secbegaddr;
thiswrbuff = tempbuf;
thiswrlen = thislen + (thisaddr - secbegaddr);
}
else if (svwhenera == 2) // 擦除时保留写入区域之后的数据
{
thiswraddr = thisaddr;
thiswrbuff = (u16*)wrbufaddr;
thiswrlen = thisslen - (thisaddr - secbegaddr);
}
else // if (svwhenera == 3) // 擦除时保留写入区域之外的数据
{
thiswraddr = secbegaddr;
thiswrbuff = tempbuf;
thiswrlen = thisslen; // 扇区长度
}
}
else
#endif
{
thiswraddr = thisaddr;
thiswrbuff = pBuffer;
thiswrlen = thislen;
}
// 写入数据
STMFlashWrNoCheck(thiswraddr, thiswrbuff, thiswrlen / 2); // 写入数据
pBuffer += thislen;
addr += thislen;
wrlen -= thislen;
}
FLASHLock(); // 上锁
return 0;
}