均衡擦写spiflash,数据掉电后不丢失.

线性均衡擦写spiflash,掉电后,能够找到上次的地址,接着读写。



--- 验证spi flash驱动接口 目前该驱动兼容w25q32 bh25q32
require"spiFlash"
require "pm"
require"utils"

pm.wake("testSpiFlash")

local flashlist = {
    [0xEF15] = 'w25q32',
    [0xEF16] = 'w25q64',
    [0xEF17] = 'w25q128',
    [0x6815] = 'bh25q32',
}
function HexToChar(bChar)
    if((bChar>=0x30)and(bChar<=0x39)) then
            bChar=bChar- 0x30;
    else if((bChar>=0x41)and(bChar<=0x46)) then--// Capital    
                    bChar=bChar- 0x37;             
        else if((bChar>=0x61)and(bChar<=0x66)) then --//littlecase             
                    bChar=bChar- 0x57;            
                else             
                    bChar = 0xff;             
                end
        end
    end
    return bChar;
end
-- spiflash 大小 256*16*4*1024 字节
FLASH_COUNT=10*16 --数量*4K
SPI_MAXSIZE=FLASH_COUNT*16
SPI_COUNT=0
ReadIndex=0
ReadIndex_S=1
WriteIndex=0
WriteIndex_S=1
spi_flash = spiFlash.setup(spi.SPI_1, pio.P0_10)

--把数据格式化为16进制 高位补0 ,2字节    写入spiflash指定地址
function write_Index(addr,data)
    local strhex=string.format("%04X",data)
    spi_flash:write(addr,string.fromHex(strhex))
    local readindexdata= spi_flash:read(addr, 2)
    local readdatahex=string.toHex(readindexdata)
    if(readdatahex==strhex) then
      
    else
        spi_flash:write(addr,string.fromHex(strhex))
        readindexdata= spi_flash:read(addr, 2)
         readdatahex=string.toHex(readindexdata)
         log.error("index err",readdatahex,addr,data)

    end
end

function SPI_READ()
   local indexaddr=0
    if (ReadIndex==WriteIndex) then --  //空队列,直接返回
        log.info("empty")
    else
       -- local readSPIdata_pre= spi_flash:read(ReadIndex*256, 10)
       -- local readSPIdata_pre_hex=string.toHex(readSPIdata_pre)
    
        --if( (readSPIdata_pre_hex~='30303030303030303030') and (readSPIdata_pre_hex~='FFFFFFFFFFFFFFFFFFFF') ) then   --预读 不等于空 或者 0
            readSPIdata= spi_flash:read(ReadIndex*256, 60)
           -- STRLENGTH=string.len(readSPIdata)
           -- log.info("leng:",STRLENGTH)
           spi_flash:write(ReadIndex*256,"000000000000"--读取完毕后清零

          -- log.debug("W",WriteIndex)
          
       -- else  --队列非空  但是预读不准确,强制清零
           -- log.error("RF:",ReadIndex)
           -- log.info("W",WriteIndex)
            --log.error("RFF:",readSPIdata_pre_hex)
          
          -- spi_flash:write(ReadIndex*256,"000000000000")
       -- end

        ReadIndex= (ReadIndex+ 1) %SPI_MAXSIZE;
        if(ReadIndex%16==0) then
            if(ReadIndex==0) then    --第一次读地址
                spi_flash:erase4K((FLASH_COUNT-1)*4096)
            else  --   >=16
             spi_flash:erase4K((ReadIndex-1)*256)
            end
             log.error("erase4K",ReadIndex)
        end
         if(ReadIndex%2048==0) then
            spi_flash:erase4K((FLASH_COUNT+6)*4*1024)
            spi_flash:erase4K((FLASH_COUNT+7)*4*1024)
            spi_flash:erase4K((FLASH_COUNT+8)*4*1024)
         end  --索引写完了一遍
            indexaddr=ReadIndex%2048
            write_Index(indexaddr*2+(FLASH_COUNT+6)*4096,ReadIndex)
            write_Index(indexaddr*2+(FLASH_COUNT+7)*4096,ReadIndex)
            write_Index(indexaddr*2+(FLASH_COUNT+8)*4096,ReadIndex)

        --strhex_index=string.format("%04X",ReadIndex)
       -- spi_flash:write(ReadIndex*2+(FLASH_COUNT+4)*4096,string.fromHex(strhex_index))
        log.debug("+",readSPIdata)
        log.debug("R",ReadIndex)
    end

   -- return readSPIdata

end

--判断spiflash 是否有剩余空间   返回 0-没有空间    1-有空间
function SPI_Free()
    local result=0
    --注意: WriteIndex+16不可以大于65535  否则为nil 报错!!!!!!
    if((WriteIndex+16)% SPI_MAXSIZE==ReadIndex)   then -- //队列已满时,不执行入队操作
        result=0
    else  --队列空
        result=1
    end
    return result
end

function SPI_WRITE(SPI_user_data)
local result=0

         writeDataLength=string.len(SPI_user_data)
        local readSPIdata_pre= spi_flash:read((WriteIndex)*256, 10)
        local readSPIdata_pre_hex=string.toHex(readSPIdata_pre)
        local indexaddr=0
        if(readSPIdata_pre_hex=='FFFFFFFFFFFFFFFFFFFF') then  -- 预写地址数据正确
            spi_flash:write(WriteIndex*256,SPI_user_data)
            DATA01= spi_flash:read(WriteIndex*256, writeDataLength)
            if( DATA01==SPI_user_data) then  --写入正确
                result=1
            else   --写入错误
                result=0
            end

        else
            result=0
        end

        WriteIndex= (WriteIndex+1) % SPI_MAXSIZE; --//尾部元素指向下一个空间位置,取模运算保证了索引不越界(余数一定小于除数)
        if(WriteIndex%2048==0) then
            spi_flash:erase4K((FLASH_COUNT+3)*4*1024)
             spi_flash:erase4K((FLASH_COUNT+4)*4*1024)
             spi_flash:erase4K((FLASH_COUNT+5)*4*1024)
           

        end  --索引写完了一遍
             indexaddr=WriteIndex%2048
             write_Index(indexaddr*2+(FLASH_COUNT+3)*4096,WriteIndex)
            write_Index(indexaddr*2+(FLASH_COUNT+4)*4096,WriteIndex)
            write_Index(indexaddr*2+(FLASH_COUNT+5)*4096,WriteIndex)
        
        --local strhex=string.format("%04X",WriteIndex)
        --spi_flash:write(WriteIndex*2+(FLASH_COUNT+3)*4096,string.fromHex(strhex))   --记录下一个地址索引
        log.debug("W",WriteIndex)
   

    return result
end
--带比较写入spiflash   返回 0-满了    1-写入成功
function spiWriteDataCheck(userdata)
    local result=0
    if(SPI_Free()==1) then  --有空间
        result=SPI_WRITE(userdata)
        if(result==0) then  --写入错误 再写一遍
             if(SPI_Free()==1) then
                 SPI_WRITE(teststr)
             else
                result=0          
            end
        end
    else
        result=0
    end 
    return result
end
-- 从spiflash读qu size个字节数据 转为16进制
function spiHexToDec(address,size)
    local hexdata=spi_flash:read(address,size)
    local readdatahex=string.toHex(hexdata)
    return readdatahex
end
--二分查找索引
function findIndex(MAXINDEX,baseAddress1,baseAddress2,baseAddress3,W_R_index)
    local miniindex=0
    local maxindex=MAXINDEX
    local read_flags1='0000'
    local read_flags2='0000'
    local read_flags3='0000'
    local offsetAddress=0
    local erFenCount=11  --分11段查找
   
    while(erFenCount>0) do
        offsetAddress=(maxindex-miniindex)/2+miniindex  -- 重新确定偏移量 对于基地址的绝对位置
        read_flags1=spiHexToDec(baseAddress1+offsetAddress,2)
        read_flags2=spiHexToDec(baseAddress2+offsetAddress,2)
        read_flags3=spiHexToDec(baseAddress3+offsetAddress,2)
        if((read_flags1==read_flags2) and (read_flags2==read_flags3) and (read_flags1=='FFFF')) then  --全部相等
                maxindex=offsetAddress
        else   --取后半部分
            miniindex=offsetAddress
        end

        erFenCount=erFenCount-1
        sys.wait(2)
    end
        if((maxindex-miniindex)==2) then  log.info('%%%%%',miniindex,maxindex) end

        readflags1=spi_flash:read(baseAddress1+miniindex,2)
        readflags2=spi_flash:read(baseAddress2+miniindex,2)
        readflags3=spi_flash:read(baseAddress3+miniindex,2)
        readIndex_fromhex1=string.toHex(readflags1)
        readIndex_fromhex2=string.toHex(readflags2)
        readIndex_fromhex3=string.toHex(readflags3)
        readIndex1=tonumber(readIndex_fromhex1,16--十进制数
        readIndex2=tonumber(readIndex_fromhex2,16--十进制数
        readIndex3=tonumber(readIndex_fromhex3,16--十进制数
        if((readIndex_fromhex1==readIndex_fromhex2)   and (readIndex_fromhex1~='FFFF') ) then
           -- readIndex1=tonumber(readIndex_fromhex1,16)  --十进制数
            if(W_R_index==1) then   --写索引            
                WriteIndex=readIndex1
                log.error("W index1",readIndex_fromhex1)
                log.error("writeIndex1",readIndex1)
                spi_flash:erase4K((FLASH_COUNT+5)*4*1024)                  
                findresult=1
            else    --读索引
                ReadIndex=readIndex1
                log.error("R index1",readIndex_fromhex1)
                log.error("readIndex1",readIndex1)
                spi_flash:erase4K((FLASH_COUNT+8)*4*1024)
                findresult=1
            end
        else
            if((readIndex_fromhex2==readIndex_fromhex3)   and (readIndex_fromhex2~='FFFF') ) then
               -- readIndex2=tonumber(readIndex_fromhex2,16)  --十进制数
                if(W_R_index==1) then   --写索引            
                    WriteIndex=readIndex2
                    log.error("W index2",readIndex_fromhex2)
                    log.error("writeIndex2",readIndex2)
                    spi_flash:erase4K((FLASH_COUNT+4)*4*1024)                  
                    findresult=1
                else    --读索引
                    ReadIndex=readIndex2
                    log.error("R index2",readIndex_fromhex2)
                    log.error("readIndex2",readIndex2)
                    spi_flash:erase4K((FLASH_COUNT+7)*4*1024)
                    findresult=1
                end
            else
                if((readIndex_fromhex1==readIndex_fromhex3)   and (readIndex_fromhex1~='FFFF') ) then
                   -- readIndex3=tonumber(readIndex_fromhex3,16)  --十进制数
                    if(W_R_index==1) then   --写索引            
                        WriteIndex=readIndex3
                        log.error("W index3",readIndex_fromhex3)
                        log.error("writeIndex3",readIndex3)
                        spi_flash:erase4K((FLASH_COUNT+4)*4*1024)
                        findresult=1
                    else    --读索引
                        ReadIndex=readIndex3
                        log.error("R index3",readIndex_fromhex3)
                        log.error("readIndex3",readIndex3)
                        spi_flash:erase4K((FLASH_COUNT+7)*4*1024)
                   
                        findresult=1
                    end
                else
                    if(miniindex>=2) then
                        readflags1=spi_flash:read(baseAddress1+miniindex-2,2)
                        readflags2=spi_flash:read(baseAddress2+miniindex-2,2)
                        readflags3=spi_flash:read(baseAddress3+miniindex-2,2)
                        readIndex_fromhex1=string.toHex(readflags1)
                        readIndex_fromhex2=string.toHex(readflags2)
                        readIndex_fromhex3=string.toHex(readflags3)
                        if((readIndex_fromhex1==readIndex_fromhex2) and (readIndex_fromhex2==readIndex_fromhex3) and (readIndex_fromhex1~='FFFF') ) then
                            --这是最后的救命稻草了
                            readIndex1=tonumber(readIndex_fromhex1,16--十进制数
                            if(W_R_index==1) then   --写索引            
                                WriteIndex=readIndex1
                                log.error("W index_pre",readIndex_fromhex1)
                                log.error("writeIndex_pre",readIndex1)                 
                                findresult=1
                            else    --读索引
                                ReadIndex=readIndex1
                                log.error("R index_pre",readIndex_fromhex1)
                                log.error("readIndex_pre",readIndex1)
                                findresult=1
                            end 

                        else -- 前一个也不对  死定了
                            findresult=0
                        end
                    else --接收死刑吧,确实找不到索引了  重新初始化。
                        findresult=0
                    end
                end
            end
        end
        --出现异常情况,理论上不可能为nil 
        if((readIndex1==nil) or (readIndex2==nil) or (readIndex3==nil) ) then  log.error("nil  err  err")  findresult=0  end
end
--;预读初始化
flash_Inint_Flags="17513167902"
function SPI_ININT_PRE()
    ReadIndex=0
    WriteIndex=0
    spi_flash:erase4K((FLASH_COUNT+1)*4*1024--清除必须操作  必须清楚后才能写数据
    local writeOK_flag= spi_flash:read((FLASH_COUNT+2)*4*1024,11--是否第一次写入数据
    local next_step=0
    print("writeOK_flag",writeOK_flag)
    if(writeOK_flag==flash_Inint_Flags) then
        next_step=1
    else
        spi_flash:erase4K((FLASH_COUNT+2)*4*1024)
        print("writeOK_flag14", spi_flash:write((FLASH_COUNT+2)*4*1024,flash_Inint_Flags))
        next_step=2
    end
    print("next_step=",next_step)
    local count=0
    local readindex_start=0
    local writeindex_start=0
    local readIndex_flag=0
    if(next_step==1) then


               if(findIndex(4096,(FLASH_COUNT+3)*4096,(FLASH_COUNT+4)*4096,(FLASH_COUNT+5)*4096,1)==0) then --没有找到上次的 写索引 全部清除
                        next_step=2
               end
               print("========================")
               if(findIndex(4096,(FLASH_COUNT+6)*4096,(FLASH_COUNT+7)*4096,(FLASH_COUNT+8)*4096,0)==0) then --没有找到上次的 读索引 全部清除
                         next_step=2
                end
                if(next_step==1) then
                    log.error("indexR_W1",ReadIndex,WriteIndex)
                end
             count=0
             readIndex_flag=0
    end
   
  
     count=0
    if(next_step==2) then
        log.error("indexR_W2",ReadIndex,WriteIndex)
        print('spi flash erase..........')
        while(count<(FLASH_COUNT/16)) do             
            spi_flash:erase64K(count*1024*4*16) count=count+1  sys.wait(1)    --清除数据区
        end
        --清除读写索引区
         spi_flash:erase4K((FLASH_COUNT+3)*4*1024)
         spi_flash:erase4K((FLASH_COUNT+4)*4*1024)
         spi_flash:erase4K((FLASH_COUNT+5)*4*1024)
         spi_flash:erase4K((FLASH_COUNT+6)*4*1024)
         spi_flash:erase4K((FLASH_COUNT+7)*4*1024)
         spi_flash:erase4K((FLASH_COUNT+8)*4*1024)
         --第一次读写flash 索引置零
        ReadIndex=0
        WriteIndex=0
        --把下一次预读写的索引写入spiflash
        write_Index(WriteIndex*2+(FLASH_COUNT+3)*4096,WriteIndex)
        write_Index(WriteIndex*2+(FLASH_COUNT+4)*4096,WriteIndex)
        write_Index(WriteIndex*2+(FLASH_COUNT+5)*4096,WriteIndex)

        write_Index(ReadIndex*2+(FLASH_COUNT+6)*4096,ReadIndex)
        write_Index(ReadIndex*2+(FLASH_COUNT+7)*4096,ReadIndex)
        write_Index(ReadIndex*2+(FLASH_COUNT+8)*4096,ReadIndex)
        print('spi flash eraseinit OK')
        sys.wait(1000)
    end
end


SPI_ININT_OK=0
SPI_ININT_PRE()
SPI_ININT_OK=2

yesycount=1
xinhaoliang=0
function writespiflashtest()
    syserrrcode=0
    while(true) do
       --- if(xinhaoliang==0) then
            if(SPI_ININT_OK==2) then
                teststr=string.format("test adcde:ftydtyfdfdfgurgjfdhguirhgujgh#>:      %d", yesycount)
                if(spiWriteDataCheck(teststr)==1) then  --写入正确
                    yesycount=yesycount+1
                else --满了
                    print("full",WriteIndex)
                end                                      
            end
        sys.wait(5)
    end
end
sys.taskInit(writespiflashtest)
    while true do
        if(SPI_ININT_OK==2) then            
      SPI_READ()
            end
        sys.wait(15)
    end
end)




上次更新 2021-01-28