611 lines
12 KiB
C
611 lines
12 KiB
C
|
||
#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;
|
||
}
|