498 lines
13 KiB
C
498 lines
13 KiB
C
#include "spiflash.h"
|
|
#include "rtthread.h"
|
|
#include "DebugCmd.h"
|
|
#include "Public.h"
|
|
|
|
//#define FLASH_TEST
|
|
|
|
#ifdef FLASH_TEST
|
|
uint8_t flashtestbuff[SPIFLASH_SIZE];
|
|
#endif
|
|
|
|
static uint8_t SpiFlashReadByte(void)
|
|
{
|
|
return Spi1SendReceive(0);
|
|
}
|
|
|
|
static void SpiFlashSendByte(uint8_t sData)
|
|
{
|
|
Spi1SendReceive(sData);
|
|
}
|
|
|
|
static void SpiFlashWriteEnable(void)
|
|
{
|
|
SpiFlashClrNss();
|
|
SpiFlashSendByte(SPIFLASH_CMD_WREN);
|
|
SpiFlashSetNss();
|
|
}
|
|
|
|
static void SpiFlashWaitForWriteEnd(void)
|
|
{
|
|
uint8_t flashstatus = 0;
|
|
SpiFlashClrNss();
|
|
SpiFlashSendByte(SPIFLASH_CMD_RDSR);
|
|
do{
|
|
flashstatus = SpiFlashReadByte();
|
|
}
|
|
while ((flashstatus & SPIFLASH_WIP_FLAG) == SPIFLASH_WIP_FLAG);
|
|
SpiFlashSetNss();
|
|
}
|
|
|
|
//扇区擦除
|
|
void SpiFlashEraseSector(uint32_t SectorAddr)
|
|
{
|
|
#ifdef FLASH_TEST
|
|
memset(&flashtestbuff[SectorAddr], 0xff, 4096);
|
|
#else
|
|
SpiFlashWriteEnable();
|
|
SpiFlashWaitForWriteEnd();
|
|
SpiFlashClrNss();
|
|
SpiFlashSendByte(SPIFLASH_CMD_SE);
|
|
SpiFlashSendByte((SectorAddr >> 16) & 0x00FF);
|
|
SpiFlashSendByte((SectorAddr >> 8) & 0x00FF);
|
|
SpiFlashSendByte(SectorAddr & 0x00FF);
|
|
SpiFlashSetNss();
|
|
SpiFlashWaitForWriteEnd();
|
|
#endif
|
|
}
|
|
|
|
//整片擦除
|
|
void SpiFlashEraseChip(void)
|
|
{
|
|
SpiFlashWriteEnable();
|
|
SpiFlashClrNss();
|
|
SpiFlashSendByte(SPIFLASH_CMD_BE);
|
|
SpiFlashSetNss();
|
|
SpiFlashWaitForWriteEnd();
|
|
}
|
|
|
|
//写数据
|
|
void SpiFlashWriteData(uint8_t* wData, uint32_t wAddr, uint16_t wLen)
|
|
{
|
|
#ifdef FLASH_TEST
|
|
memcpy(&flashtestbuff[wAddr], wData, wLen);
|
|
#else
|
|
SpiFlashWriteEnable();
|
|
SpiFlashClrNss();
|
|
SpiFlashSendByte(SPIFLASH_CMD_WRITE);
|
|
SpiFlashSendByte((wAddr >> 16) & 0x00FF);
|
|
SpiFlashSendByte((wAddr >> 8) & 0x00FF);
|
|
SpiFlashSendByte(wAddr & 0x00FF);
|
|
for(int i = 0; i < wLen; i++) {
|
|
SpiFlashSendByte(wData[i]);
|
|
}
|
|
SpiFlashSetNss();
|
|
SpiFlashWaitForWriteEnd();
|
|
#endif
|
|
}
|
|
|
|
void SpiFlashWriteAnyLengthData(uint8_t* wData, uint32_t wAddr, uint16_t wLen)
|
|
{
|
|
uint16_t PageCnt; //需要写入页数
|
|
uint16_t FirstPageWriteSize; //在起始地址不为页起始地址的情况下,先写入当前页剩余空间
|
|
uint16_t LastPageWriteSize; //最后一页写入长度
|
|
uint32_t AddrOffset = 0;
|
|
uint32_t WriteAddr;
|
|
LogHeader LogH;
|
|
WriteAddr = wAddr;
|
|
|
|
//写入的长度超出最大空间,从起始开始写起
|
|
if((WriteAddr + wLen) > SPIFLASH_SIZE) {
|
|
LogH = (LogHeader)wData;
|
|
WriteAddr = LOG_SAV_START_SECTOR * SPIFLASH_SECTORSIZE;
|
|
LogH->LogEndAddr = WriteAddr + wLen;
|
|
}
|
|
|
|
uint16_t FirstPageRemainSpace = SPIFLASH_PAGESIZE - (WriteAddr % SPIFLASH_PAGESIZE);
|
|
|
|
// //判断是否跨扇区,跨扇区需要先擦除下一扇区
|
|
// CheckDelSecter(wAddr, wLen);
|
|
|
|
if(wLen < FirstPageRemainSpace) {
|
|
FirstPageWriteSize = wLen; //计算首页写入长度
|
|
PageCnt = 0;
|
|
LastPageWriteSize = 0;
|
|
}
|
|
else {
|
|
// FirstPageWriteSize = FirstPageRemainSpace % SPIFLASH_PAGESIZE;
|
|
// PageCnt = (wLen - (FirstPageWriteSize % SPIFLASH_PAGESIZE)) / SPIFLASH_PAGESIZE; //计算需要写入多少整页
|
|
// LastPageWriteSize = (wLen - (FirstPageWriteSize % SPIFLASH_PAGESIZE)) % SPIFLASH_PAGESIZE; //计算剩余需要写入的长度
|
|
FirstPageWriteSize = FirstPageRemainSpace;
|
|
PageCnt = (wLen - FirstPageWriteSize) / SPIFLASH_PAGESIZE; //计算需要写入多少整页
|
|
LastPageWriteSize = (wLen - FirstPageWriteSize) % SPIFLASH_PAGESIZE; //计算剩余需要写入的长度
|
|
}
|
|
|
|
if(FirstPageWriteSize > 0) {
|
|
SpiFlashWriteData(&wData[AddrOffset], WriteAddr, FirstPageWriteSize);
|
|
AddrOffset += FirstPageWriteSize;
|
|
WriteAddr += FirstPageWriteSize;
|
|
}
|
|
for(int i = 0; i < PageCnt; i++) {
|
|
SpiFlashWriteData(&wData[AddrOffset], WriteAddr, SPIFLASH_PAGESIZE);
|
|
AddrOffset += SPIFLASH_PAGESIZE;
|
|
WriteAddr += SPIFLASH_PAGESIZE;
|
|
}
|
|
if(LastPageWriteSize > 0) {
|
|
SpiFlashWriteData(&wData[AddrOffset], WriteAddr, LastPageWriteSize);
|
|
}
|
|
}
|
|
|
|
void SpiFlashReadAnyLengthData(uint8_t* rData, uint32_t rAddr, uint16_t rLen)
|
|
{
|
|
#ifdef FLASH_TEST
|
|
memcpy(rData, &flashtestbuff[rAddr], rLen);
|
|
#else
|
|
SpiFlashClrNss();
|
|
SpiFlashSendByte(SPIFLASH_CMD_READ);
|
|
SpiFlashSendByte((rAddr >> 16) & 0x00FF);
|
|
SpiFlashSendByte((rAddr >> 8) & 0x00FF);
|
|
SpiFlashSendByte(rAddr & 0x00FF);
|
|
for(int i = 0; i < rLen; i++) {
|
|
rData[i] = SpiFlashReadByte();
|
|
}
|
|
SpiFlashSetNss();
|
|
#endif
|
|
}
|
|
|
|
uint32_t SpiFlashReadId(void)
|
|
{
|
|
uint32_t Temp = 0, Temp0 = 0, Temp1 = 0, Temp2 = 0;
|
|
SpiFlashClrNss();
|
|
SpiFlashSendByte(0x9F);
|
|
Temp0 = SpiFlashReadByte();
|
|
Temp1 = SpiFlashReadByte();
|
|
Temp2 = SpiFlashReadByte();
|
|
SpiFlashSetNss();
|
|
Temp = (Temp0 << 16) | (Temp1 << 8) | Temp2;
|
|
return Temp;
|
|
}
|
|
|
|
typedef struct {
|
|
uint16_t Flag;
|
|
uint16_t LoopSavFlag; //循环存储标志
|
|
uint32_t LogCnt; //日志最大数量
|
|
uint32_t FirstLogStartAddr; //第一个数据的起始地址
|
|
uint32_t LastLogEndAddr; //最后一个数据的结束地址
|
|
}LogNumSav_t;
|
|
|
|
static LogNumSav_t LogNumArray[256];
|
|
static __IO uint32_t gLogCnt = 0;
|
|
static __IO uint32_t FirstLogStartAddr = 0; //第一个日志起始地址
|
|
static __IO uint32_t LastLogEndAddr = 0; //最后一个日志结束地址
|
|
static __IO uint16_t LoopSavFlag = 0; //循环存储标志
|
|
static uint16_t LogNumIdx;
|
|
|
|
uint16_t ReadLoopSavFlag(void)
|
|
{
|
|
return LoopSavFlag;
|
|
}
|
|
|
|
void SetLoopSavFlag(uint16_t LoopFlag)
|
|
{
|
|
LoopSavFlag = LoopFlag;
|
|
}
|
|
|
|
uint32_t ReadLogNum(void)
|
|
{
|
|
return gLogCnt;
|
|
}
|
|
|
|
void SetLogNum(uint32_t LogCnt)
|
|
{
|
|
gLogCnt = LogCnt;
|
|
}
|
|
|
|
uint32_t ReadFirstLogStartAddr(void)
|
|
{
|
|
return FirstLogStartAddr;
|
|
}
|
|
|
|
void SetFirstLogStartAddr(uint32_t FLStartAddr)
|
|
{
|
|
FirstLogStartAddr = FLStartAddr;
|
|
}
|
|
|
|
|
|
uint32_t ReadLastLogEndAddr(void)
|
|
{
|
|
return LastLogEndAddr;
|
|
}
|
|
|
|
void SetLastLogEndAddr(uint32_t LLEndAddr)
|
|
{
|
|
LastLogEndAddr = LLEndAddr;
|
|
}
|
|
|
|
void LogInit(void)
|
|
{
|
|
LogNumIdx = 0xffff;
|
|
SpiFlashReadId();
|
|
SpiFlashReadAnyLengthData((uint8_t *)&LogNumArray, LOG_INFO_START_SECTOR * SPIFLASH_SECTORSIZE, sizeof(LogNumArray));
|
|
for(int i = 0; i < 256; i++) {
|
|
if(LogNumArray[i].Flag != LOG_INFO_SAV_FLAG) {
|
|
LogNumIdx = i;
|
|
break;
|
|
}
|
|
}
|
|
if(LogNumIdx == 0xffff) { //256条记录满,读最后一条记录
|
|
LogNumIdx = 0;
|
|
SetLogNum(LogNumArray[255].LogCnt);
|
|
SetLoopSavFlag(LogNumArray[255].LoopSavFlag);
|
|
SetFirstLogStartAddr(LogNumArray[255].FirstLogStartAddr);
|
|
SetLastLogEndAddr(LogNumArray[255].LastLogEndAddr);
|
|
return;
|
|
}
|
|
if(LogNumIdx == 0) { //没有记录
|
|
LogNumIdx = 0;
|
|
SetLogNum(0);
|
|
SetLoopSavFlag(0);
|
|
SetFirstLogStartAddr(LOG_SAV_START_SECTOR * SPIFLASH_SECTORSIZE);
|
|
SetLastLogEndAddr(LOG_SAV_START_SECTOR * SPIFLASH_SECTORSIZE);
|
|
return;
|
|
}
|
|
SetLogNum(LogNumArray[LogNumIdx-1].LogCnt);
|
|
SetLoopSavFlag(LogNumArray[LogNumIdx-1].LoopSavFlag);
|
|
SetFirstLogStartAddr(LogNumArray[LogNumIdx-1].FirstLogStartAddr);
|
|
SetLastLogEndAddr(LogNumArray[LogNumIdx-1].LastLogEndAddr);
|
|
}
|
|
|
|
void SavLogNum(uint32_t LogNum)
|
|
{
|
|
LogNumSav_t CLogSav;
|
|
|
|
if(LogNum == 0) {
|
|
LogNumIdx = 0;
|
|
SetLogNum(0);
|
|
SetLoopSavFlag(0);
|
|
SetFirstLogStartAddr(LOG_SAV_START_SECTOR * SPIFLASH_SECTORSIZE);
|
|
SetLastLogEndAddr(LOG_SAV_START_SECTOR * SPIFLASH_SECTORSIZE);
|
|
SpiFlashEraseSector(LOG_INFO_START_SECTOR * SPIFLASH_SECTORSIZE);
|
|
return;
|
|
}
|
|
|
|
SetLogNum(LogNum);
|
|
CLogSav.Flag = LOG_INFO_SAV_FLAG;
|
|
CLogSav.LogCnt = LogNum;
|
|
CLogSav.FirstLogStartAddr = ReadFirstLogStartAddr();
|
|
CLogSav.LastLogEndAddr = ReadLastLogEndAddr();
|
|
|
|
if(LogNumIdx == 256) {
|
|
SpiFlashEraseSector(LOG_INFO_START_SECTOR * SPIFLASH_SECTORSIZE);
|
|
LogNumIdx = 0;
|
|
}
|
|
SpiFlashWriteData((uint8_t *)&CLogSav, LogNumIdx * sizeof(LogNumSav_t) + LOG_INFO_START_SECTOR * SPIFLASH_SECTORSIZE, sizeof(LogNumSav_t));
|
|
LogNumIdx++;
|
|
}
|
|
|
|
/*****************************************************************************************
|
|
* 函数名称: CheckDelSecter
|
|
* 功能描述: 检查需要删除的扇区,跨扇区删除下一扇区,如果到了删除最后一个扇区,循环到起始扇区
|
|
* 参 数: wAddr, 写入地址
|
|
wLen, 写入长度
|
|
* 返 回 值: 返回写入起始地址
|
|
*****************************************************************************************/
|
|
uint8_t LogBuff[LOG_SAV_SIZE_MAX];
|
|
const uint8_t SavFlag[4] ={0xAA, 0x55, 0x55, 0xAA};
|
|
void CheckDelSecter(uint32_t wAddr, uint16_t wLen)
|
|
{
|
|
uint32_t DelOffsetAddr, FindFirstLogAddr; //存储起始地址
|
|
uint32_t DelSectorNum = 0;
|
|
uint32_t SurplusSpace = SPIFLASH_SECTORSIZE - (wAddr % SPIFLASH_SECTORSIZE);
|
|
|
|
if((wAddr + wLen) > SPIFLASH_SIZE) {
|
|
DelOffsetAddr = LOG_SAV_START_SECTOR * SPIFLASH_SECTORSIZE;
|
|
SetLastLogEndAddr(DelOffsetAddr + wLen);
|
|
SetLoopSavFlag(1);
|
|
SpiFlashEraseSector(DelOffsetAddr);
|
|
FindFirstLogAddr = DelOffsetAddr + SPIFLASH_SECTORSIZE;
|
|
}
|
|
else {
|
|
if(wLen < SurplusSpace) { //长度没有超过扇区剩余容量
|
|
SetLastLogEndAddr(wAddr + wLen);
|
|
return;
|
|
}
|
|
DelOffsetAddr = (wAddr / SPIFLASH_SECTORSIZE + 1) * SPIFLASH_SECTORSIZE;
|
|
DelSectorNum = (wLen - SurplusSpace) / SPIFLASH_SECTORSIZE + 1;
|
|
SetLastLogEndAddr(wAddr + wLen);
|
|
for(int i = 0; i < DelSectorNum; i++) {
|
|
SpiFlashEraseSector(DelOffsetAddr);
|
|
DelOffsetAddr += SPIFLASH_SECTORSIZE;
|
|
}
|
|
if(DelOffsetAddr == SPIFLASH_SIZE) {
|
|
DelOffsetAddr = LOG_SAV_START_SECTOR * SPIFLASH_SECTORSIZE;
|
|
}
|
|
FindFirstLogAddr = DelOffsetAddr;
|
|
}
|
|
|
|
if(!ReadLoopSavFlag())
|
|
return;
|
|
|
|
uint32_t ReadAddr = FindFirstLogAddr;
|
|
while(1) {
|
|
SpiFlashReadAnyLengthData(LogBuff, ReadAddr, LOG_SAV_SIZE_MAX);
|
|
int i;
|
|
for(i = 0; i < LOG_SAV_SIZE_MAX; i++) {
|
|
if(memcmp(&LogBuff[i], SavFlag, 4) == 0) {
|
|
SetFirstLogStartAddr(ReadAddr + i);
|
|
return;;
|
|
}
|
|
}
|
|
if(i == LOG_SAV_SIZE_MAX) {
|
|
ReadAddr += LOG_SAV_SIZE_MAX;
|
|
if(ReadAddr >= SPIFLASH_SIZE) { //找不到下一条数据,重置flash
|
|
Debug_Printf("Add LOG Error, Next Data No Find!\r\n");
|
|
SetLogNum(0);
|
|
SetLoopSavFlag(0);
|
|
SetFirstLogStartAddr(LOG_SAV_START_SECTOR * SPIFLASH_SECTORSIZE);
|
|
SetLastLogEndAddr(LOG_SAV_START_SECTOR * SPIFLASH_SECTORSIZE);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
uint8_t LogBuffTemp[LOG_SAV_SIZE_MAX];
|
|
void AddLog(uint8_t *wData, uint32_t wLen)
|
|
{
|
|
//const uint8_t SavFlag[4] ={0xAA, 0x55, 0x55, 0xAA};
|
|
uint32_t LogNum;
|
|
uint32_t LogSize;
|
|
//uint32_t FLStartAddr;
|
|
uint32_t LLEndAddr;
|
|
// uint32_t SectorN;
|
|
LogHeader LogH;
|
|
|
|
LogH = (LogHeader)LogBuffTemp;
|
|
|
|
LogNum = ReadLogNum();
|
|
if(LogNum == 0) {
|
|
SetFirstLogStartAddr(LOG_SAV_START_SECTOR * SPIFLASH_SECTORSIZE);
|
|
SetLastLogEndAddr(LOG_SAV_START_SECTOR * SPIFLASH_SECTORSIZE);
|
|
SpiFlashEraseSector(LOG_SAV_START_SECTOR * SPIFLASH_SECTORSIZE);
|
|
}
|
|
//FLStartAddr = ReadFirstLogStartAddr();
|
|
LLEndAddr = ReadLastLogEndAddr();
|
|
LogNum++;
|
|
LogH->LogSavFlag = LOG_SAV_FLAG;
|
|
LogH->LogIdx = LogNum;
|
|
LogSize = wLen + sizeof(LogHeader_t);
|
|
LogH->LogEndAddr = LLEndAddr + LogSize;
|
|
LogH->TimeStamp = TimeTs();
|
|
memcpy(&LogBuffTemp[sizeof(LogHeader_t)], wData, wLen);
|
|
|
|
//判断是否跨扇区,跨扇区需要先擦除下一扇区
|
|
CheckDelSecter(LLEndAddr, LogSize);
|
|
if(LogH->LogEndAddr > SPIFLASH_SIZE) {
|
|
LLEndAddr = LOG_SAV_START_SECTOR * SPIFLASH_SECTORSIZE;
|
|
LogH->LogEndAddr = ReadLastLogEndAddr();
|
|
}
|
|
SpiFlashWriteAnyLengthData(LogBuffTemp, LLEndAddr, LogSize);
|
|
|
|
SavLogNum(LogNum);
|
|
//Debug_Printf("Add LOG: %d,endaddr = %d\r\n", LogNum, ReadLastLogEndAddr());
|
|
}
|
|
|
|
|
|
/*****************************************************************************************
|
|
* 函数名称: ReadLog
|
|
* 功能描述: 读取日志
|
|
* 参 数: Header, 上一包日志头信息,连续读取时传入上一包数据信息,缩短日志遍历时间,
|
|
Header->LogEndAddr为0读取第一包数据,LogIdx数据无效
|
|
rData, 日志出口,需要释放
|
|
LogIdx, 读取的日志的序号,为0读取Header->LogEndAddr对应日志
|
|
* 返 回 值: 返回数据长度
|
|
*****************************************************************************************/
|
|
int ReadLog(LogHeader Header, uint8_t **rData, uint32_t LogIdx)
|
|
{
|
|
uint32_t FSAddr;
|
|
int LogLen = 0;
|
|
//bool FirstIdx = false;
|
|
|
|
if(Header == NULL)
|
|
return 0;
|
|
|
|
if(Header->LogEndAddr == 0) {
|
|
Header->LogEndAddr = ReadFirstLogStartAddr();
|
|
LogIdx = 0;
|
|
}
|
|
|
|
if(LogIdx == 1) {
|
|
FSAddr = ReadFirstLogStartAddr();
|
|
}
|
|
else
|
|
FSAddr = Header->LogEndAddr;
|
|
|
|
while(1) {
|
|
SpiFlashReadAnyLengthData((uint8_t *)Header, FSAddr, sizeof(LogHeader_t));
|
|
if(Header->LogSavFlag != LOG_SAV_FLAG) {
|
|
if((SPIFLASH_SIZE - FSAddr) < LOG_SAV_SIZE_MAX) { //判断是否到片尾
|
|
FSAddr = LOG_SAV_START_SECTOR * SPIFLASH_SECTOR_NUM;
|
|
continue;
|
|
}
|
|
else
|
|
return 0;
|
|
}
|
|
if(LogIdx == 0) {
|
|
LogIdx = Header->LogIdx;
|
|
}
|
|
else if(Header->LogIdx != LogIdx) {
|
|
FSAddr = Header->LogEndAddr;
|
|
continue;
|
|
}
|
|
|
|
if(Header->LogIdx == LogIdx) {
|
|
if(*rData == NULL)
|
|
return sizeof(LogHeader_t);
|
|
|
|
SpiFlashReadAnyLengthData(LogBuffTemp, FSAddr, Header->LogEndAddr - FSAddr);
|
|
LogLen = Header->LogEndAddr - FSAddr - sizeof(LogHeader_t);
|
|
void *pTemp = rt_malloc(LogLen);
|
|
if(pTemp == NULL)
|
|
return 0;
|
|
|
|
*rData =pTemp;
|
|
memcpy(*rData, &LogBuffTemp[sizeof(LogHeader_t)], LogLen);
|
|
break;
|
|
}
|
|
}
|
|
return LogLen;
|
|
}
|
|
|
|
|
|
/*****************************************************************************************
|
|
* 函数名称: ReadPara
|
|
* 功能描述: 读取参数
|
|
* 参 数: Para, 网关参数
|
|
ParaLen, 参数长度
|
|
* 返 回 值: 无
|
|
*****************************************************************************************/
|
|
int ReadPara(uint8_t *Para, uint32_t ParaLen)
|
|
{
|
|
SpiFlashReadAnyLengthData(Para, GATEWEY_PARA_SAV_ADDR, ParaLen); //读取片尾数据
|
|
uint16_t Check = CRC_Modbus(0xA001, Para, ParaLen - 2);
|
|
GWConfigPara CfgPara = (GWConfigPara)Para;
|
|
if(CfgPara->crc16 != Check)
|
|
return -1;
|
|
return 0;
|
|
}
|
|
|
|
/*****************************************************************************************
|
|
* 函数名称: WritePara
|
|
* 功能描述: 写入参数
|
|
* 参 数: Para, 网关参数
|
|
ParaLen, 参数长度
|
|
* 返 回 值: 无
|
|
*****************************************************************************************/
|
|
int WritePara(uint8_t *Para, uint32_t ParaLen)
|
|
{
|
|
SpiFlashEraseSector(GATEWEY_PARA_SAV_ADDR);
|
|
|
|
uint16_t Check = CRC_Modbus(0xA001, Para, ParaLen - 2);
|
|
GWConfigPara CfgPara = (GWConfigPara)Para;
|
|
CfgPara->crc16 = Check;
|
|
SpiFlashWriteAnyLengthData(Para, GATEWEY_PARA_SAV_ADDR, ParaLen); //读取片尾数据
|
|
return 0;
|
|
}
|
|
|
|
/* USER CODE END */
|