FLASH仿真EEPROM---基于智芯Z20K11XM

一、介绍

        电可擦和可编程只读存储器(EEPROM)可以对字节或字编程和擦除。EEPROM中的数据即使断电也能保持,但Z20K1xx芯片不含EEPROM。然而,闪存可以通过EEPROM仿真软件来模拟EEPROM。Z20K1xx包含两个flash阵列。编程和擦除操作可以在一个数组上进行,同时在另一个数组上执行代码。     

二、存储原理

        EEPROM仿真包含两个或多个扇区,每个扇区都包含一组闪存扇区。只有一个扇区被选为活动块。存储在活动扇区中的记录列表用于访问数据。每条记录都有一个ID,用来区别于其他记录。记录是一组变量。数据记录的长度是可变的。

        记录按顺序编入活动扇区。为了更新记录,软件将新版本的记录写入活动扇区中下一个可用的位置。当读取记录时,软件检索具有匹配ID的最近写入的记录。当活动扇区没有足够的空间容纳新记录时,软件将活动扇区内的所有有效记录复制到其他EE扇区之一。这个新扇区成为活动扇区,之前的活动扇区失效。由于旧记录在交换期间被清除,新的活动扇区应该有空间用于记录更新。交换后,新记录将被写入新的活动扇区。 后续会详细描述,这一交换原理。

三、内存组成

下图为扇区的内存组成列表图包含扇区+记录+数据存储区。

1.扇区

每个扇区包含一个扇区报头,它包括以下部分

sectorlD:扇区标识。每当有一个新的扇区,这个数字就增加1变得活跃。它从1开始。sectorlD最大的部门是活跃的部门。
sectorstart address:扇区起始地址扇区大小:扇区的大小,以字节为单位。

checksum:扇区id、扇区起始地址和扇区大小字段之和。

sector valid flag:扇区的有效标志,如果等于一个特殊的值,则表示该扇区有效

sector invalid flag:扇区的无效标志,如果等于特殊值,则表示该扇区为失效。

2.记录

每条记录包含一个记录头,它包括以下部分:

recordlD:记录的标识。
data address:记录的数据地址
record size:记录大小(以字节为单位)。
check sum:recordID、数据地址和记录大小字段之和。
record valid flag:记录的有效标志,如果它等于一个特殊值,则该记录是有效的。

record invalid flag:记录的无效标志,如果它等于一个特殊值,则该记录无效。

 四、扇区交换

        前面提到过存储的原理实际就是活动扇区的交换,实际上扇区的交换就是在活动扇区满足以下这三点时:

①当活动扇区没有足够的空间来写入新记录时

②当在EE初始化期间检测到无效记录头时(可选)。

③当最后一个记录头无效时。

把所有的有效记录从一个活动扇区复制到另一个扇区,下图举例了三个扇区的交换: 

初始时,Sector0是活动扇区,

第一次交换后,Sector0变为“invalid”,Sector1变为活动扇区。

第二次交换后,Sector1变为“invalid”,Sector2变为活动扇区。

再了解了存储结构和交换原理后我们就可以理解代码并写一段demo例子了。 

五、代码编程

1.结构体初始化

static uint32_t cacheTable[EE_CACHE_RECORD_NUM];
static EE_cache_t cacheConf =
{
    cacheTable,               /* cache 起始地址 */
    EE_CACHE_RECORD_NUM       /* cache 缓存大小 */
};

/* 扇区0配置 */
static const EE_SectorConfig_t sectorConf0 =
{
    EE_SECTOR_0_ADDR,          /* 起始地址 */
    EE_SECTOR_SIZE,            /* 大小 */
};

/* 扇区1配置 */
static const EE_SectorConfig_t sectorConf1 =
{
    EE_SECTOR_1_ADDR,          /* 起始地址 */
    EE_SECTOR_SIZE,            /* 大小 */
};

/* 扇区2配置 */
static const EE_SectorConfig_t sectorConf2 =
{
    EE_SECTOR_2_ADDR,          /* 起始地址 */
    EE_SECTOR_SIZE,            /* 大小 */
};

/* 扇区配置数组 */
static const EE_SectorConfig_t* sectorConfig[EE_SECTOR_NUM] =
{
    &sectorConf0,
    &sectorConf1, 
    &sectorConf2, 
};

/* EEPROM配置 */
EE_Config_t eeConf =
{
    .sectorNum = EE_SECTOR_NUM,  /* 扇区数量 */
    .sectors = sectorConfig,     /* 扇区配置 */
    .cacheEn = ENABLE,           /* cache 使能 */
    .cTable = &cacheConf,        /* cache 结构体 */
    .busyFlag = RESET,
    .maxRecordId = EE_MAX_RECORD_ID,         /* 最大记录ID */
};

2.系统初始化

static void system_init(void)
{  
    WDOG_Config_t wdogCfg = 
    {
        .winEnable = DISABLE,
        .wait = DISABLE,
        .stop = DISABLE,
        .debug = DISABLE,
        .windowValue = 0,
        .timeoutValue = 9600,
        .clkSource = WDOG_LPO_CLOCK,
        .testMode = WDOG_TST_NORMAL,        
    };
    
    CLK_SetClkDivider(CLK_CORE, CLK_DIV_1);
    CLK_SetClkDivider(CLK_BUS, CLK_DIV_1);
    CLK_SetClkDivider(CLK_SLOW, CLK_DIV_8);
    
    if(ERR == WDOG_Init(&wdogCfg))
    {
        ErrorTrap();
    }
    
    if(ERR == WDOG_Enable())
    {
        ErrorTrap();
    }
}

3.初始化EEPROM

EEPROM仿真初始化,最多尝试三次,错误处理判断

while ((i < 3U) && (ret != EE_OK))
{
    ret = EE_Init(&eeConf, ENABLE, &CallBack);
    i++;
}
if(ret != EE_OK)
{
   ErrorTrap();
}

4.写入数据到EEPROM

        写入数据到EEPROM,每个记录的ID从0到最大记录ID(EE_MAX_RECORD_ID),数据大小从1字节到缓冲区大小(BUFFER_SIZE),验证写入的数据,确保读取的数据与写入的数据一致。 

    for(id = 0U; id <= eeConf.maxRecordId; id++)
    {
        size = id + 1U;
        if(size > BUFFER_SIZE)
        {
            size = BUFFER_SIZE;
        }
        /* Init buffer*/
        for (i = 0; i < size; i++)
        {
            buffer[i] = (uint8_t)(i + id);
        }

        ret = EE_WriteRecord(&eeConf,id, size, buffer,0, CallBack);
        if(ret != EE_OK)
        {
            /* if writing fails, re-initialize and try again */
            ret = EE_Init(&eeConf, ENABLE, &CallBack);
            if(ret != EE_OK)
            {
                ErrorTrap();
            }
            else
            {
                ret = EE_WriteRecord(&eeConf,id, size, buffer, 0, CallBack);
                if(ret != EE_OK)
                {
                    /* still error after reinitialization */
                    ErrorTrap();
                }
            } 
        }
        
        for (i = 0; i < BUFFER_SIZE; i++)
        {
            buffer[i] = 0U;
        }

        ret = EE_ReadRecord(&eeConf,id,size,buffer,&readOutSize,CallBack);
        if(ret != EE_OK)
        {
            ErrorTrap();
        }
        else
        {
            if(size != readOutSize)
            {
                ErrorTrap();
            }
                    
            for(i = 0; i < readOutSize; i++)
            {
                if(buffer[i] != i + id)
                {
                    ErrorTrap();
                }
            }
        }
    }

5.验证写入的数据

验证写入的数据,确保读取的数据与写入的数据一致。

    ret = EE_DeleteRecord(&eeConf,EE_TEST_RECORD_ID,CallBack);
    if(ret != EE_OK)
    {
        ErrorTrap();
    }

    for(i = 0; i < BUFFER_SIZE; i++)
    {
        buffer[i] = 0;
    }
    size = BUFFER_SIZE;
    ret = EE_ReadRecord(&eeConf,EE_TEST_RECORD_ID,size,buffer,&readOutSize,

6.验证删除操作

    if(ret != EE_ERROR_DATA_NOT_FOUND)
    {
        ErrorTrap();
    }
    while(true)
    {
        CallBack();
    }

7.回调函数与错误处理函数

void CallBack(void);
static void ErrorTrap(void);

void CallBack(void)
{
    WDOG_Refresh();
}


static void ErrorTrap(void)
{
    while(true)
    {
        CallBack();
    }
}

 

  • 27
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值