#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; }