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();}
}

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/34185.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

go sync包(三) 读写锁(一)

读写锁 RWMutex 读操作是天生的幂等操作&#xff0c;因为不涉及到数据的修改&#xff0c;如果在一个读多写少的场景使用普通的互斥锁&#xff0c;每个读、写操作都要加索&#xff0c;会影响性能。 type RWMutex struct {w Mutex // held if there are pendi…

AIGC发展方向和前景

引言 背景介绍 AIGC的定义及其发展历程 AIGC&#xff0c;即人工智能生成内容&#xff0c;是近年来在人工智能领域兴起的一项重要技术。它通过使用机器学习和深度学习等技术&#xff0c;使得计算机能够自动生成各种形式的数字内容&#xff0c;如文本、图像、音频和视频等。 …

【UIDynamic-动力学-UIAttachmentBehavior-附着行为-弹性附着 Objective-C语言】

一、弹性附着啊,我们来看一下, 1.刚才我们说了刚性附着,弹性附着,怎么着做啊,实际上,只需要多添加两个属性,就可以了, 实际上,添加一个,也可以啊, 我们把这个length,先注释掉, 先注释掉,self.attach.length = 100;这句话, 固定的长度啊,给它注释掉, 然后呢…

vue3中h函数的使用

h函数是用于创建一个 vnodes &#xff0c;它既可以用于创建原生元素&#xff0c;也可以创建组件&#xff0c;其渲染后的效果等同于使用模版语言来进行创建。 h函数的传参如下&#xff1a; // 完整参数签名 function h(type: string | Component,props?: object | null,child…

Docker配置国内镜像加速-2

Docker 官方镜像仓库&#xff08;如 Docker Hub&#xff09;可能由于网络原因&#xff0c;在某些地区或网络环境下下载速度较慢。使用镜像加速可以从距离用户更近、网络条件更好的镜像服务器获取镜像&#xff0c;从而显著提高下载速度&#xff0c;节省时间。 1.测试是否安装 d…

RedHat运维-Linux文本操作基础-AWK基础

你不用整理&#xff0c;跟着敲一遍&#xff0c;有个印象&#xff0c;然后把它保存到本地&#xff0c;以后要用再去看&#xff0c;如果有了新东西&#xff0c;你自个再添加。这是我参考同行的&#xff0c;只不过换成了问答的方式而已。不用背&#xff0c;就算是我自己亲自敲&…

MongoDB可视化工具全面指南

MongoDB可视化工具概述 1.1 什么是MongoDB可视化工具 MongoDB可视化工具是指那些通过图形用户界面&#xff08;GUI&#xff09;来管理和操作MongoDB数据库的软件工具。这些工具提供了一种直观的方式来执行数据库管理任务&#xff0c;如数据查询、索引管理、性能监控和数据导入…

探索Elastic Search:强大的开源搜索引擎,详解及使用

&#x1f3ac; 鸽芷咕&#xff1a;个人主页 &#x1f525; 个人专栏: 《C干货基地》《粉丝福利》 ⛺️生活的理想&#xff0c;就是为了理想的生活! 引入 全文搜索属于最常见的需求&#xff0c;开源的 Elasticsearch &#xff08;以下简称 Elastic&#xff09;是目前全文搜索引…

三维点云目标识别对抗攻击研究综述

源自&#xff1a;电子与信息学报 作者&#xff1a;刘伟权 郑世均 郭宇 王程 注&#xff1a;若出现无法显示完全的情况&#xff0c;可 V 搜索“人工智能技术与咨询”查看完整文章 摘 要 当前&#xff0c;人工智能系统在诸多领域都取得了巨大的成功&#xff0c;其中深度学…

TensorRT-LLM加速框架的基本使用

TensorRT-LLM是英伟达发布的针对大模型的加速框架&#xff0c;TensorRT-LLM是TensorRT的延申。TensorRT-LLM的GitHub地址是 https://github.com/NVIDIA/TensorRT-LLM 这个框架在0.8版本有一个比较大的更新&#xff0c;原先的逻辑被统一了&#xff0c;所以早期的版本就不介绍了…

告别繁琐代码,迈向编程新境界—Java集合与泛型全面解析

在Java编程的征途中&#xff0c;集合&#xff08;Collection&#xff09;与泛型&#xff08;Generics&#xff09;是两大里程碑式的特性&#xff0c;它们不仅极大地提升了代码的灵活性和安全性&#xff0c;还帮助开发者简化了数据结构的处理逻辑&#xff0c;让编程之旅变得更加…

Hadoop 2.0 大家族(四)

目录 七、Flume&#xff08;一&#xff09;Flume简介&#xff08;二&#xff09;Flume入门 八、Mahout&#xff08;一&#xff09;Mahout简介&#xff08;二&#xff09;Mahout入门 七、Flume Flume是一个分布式高性能、高可靠的数据传输工具&#xff0c;它可用简单的方式将不同…

Langchain实战:构建高效的知识问答系统

引言 知识问答系统&#xff08;KQA&#xff09;是自然语言处理领域的核心技术之一&#xff0c;它能够帮助用户从大量数据中快速准确地检索到所需信息。知识问答系统成为了帮助个人和企业快速获取、筛选和处理信息的重要工具。它们在很多领域都发挥着重要作用&#xff0c;例如在…

《计算机英语》Unit 1 Computer Overview 计算机概述

期末试卷组成 1、选择20道 2、判断20道 3、词汇翻译&#xff08;单词词组&#xff0c;参照课后习题&#xff09; 4、翻译2道&#xff08;一道原题&#xff0c;参照作业&#xff09; SectionA About Computer 关于计算机 algorithm n. 算法 operate v.…

邦芒贴士:领导最反感下属这6种表现

在单位里面&#xff0c;如果在工作上出现了下面六种情况&#xff0c;就说明领导已经开始嫌弃你了&#xff0c;你的工作方式和方法一定要发生一些变化&#xff0c;及时的适应领导&#xff0c;如果再按部就班&#xff0c;那可就是真的犯傻。 1.安排事情时你总是排在第一个 安排任…

爬虫阶段思考

内容&#xff1a;写这篇文章是因为最近帮同学改了很多的爬虫代码&#xff0c;感触良多。 我用豆瓣为例&#xff0c;并不是不会用别的&#xff0c;而是这个我个人感觉最经典。然后还会写我遇到的一些问题以及解决方法。 首先&#xff0c;我们得先知道怎样爬取。我用的scrapy框…

2024广东省职业技能大赛云计算赛项实战——容器化部署MariaDB

容器化部署MariaDB 前言 今年比赛的容器化部署第一道考的好像就是这个&#xff0c;是往年国赛的题&#xff0c;直接给照搬过来了&#xff0c;今天就做做这道题&#xff1a; 编写Dockerfile构建镜像erp-mysql:v1.0&#xff0c;要求使用centos7.9.2009镜像作为基础镜像&#xf…

深入探讨Redis集群方案

一、什么是Redis集群 Redis集群&#xff08;Redis Cluster&#xff09;是Redis官方提供的分布式数据库解决方案&#xff0c;旨在通过将数据分散到多个节点上来实现水平扩展和高可用性。Redis集群提供了以下几个核心功能&#xff1a; 数据分片&#xff1a;将数据分布到多个节点…

Java变量命名规则

局部变量 使用驼峰命名以小写字母开头int myLocalVariable 实例变量&#xff08;成员变量&#xff09; 使用驼峰命名法小写字母开头myInstanceVariable 静态变量 使用驼峰命名法&#xff0c;以小写字母开头也可以使用大写蛇形命名法&#xff0c;全大写字母&#xff0c;单词…

护眼灯和普通台灯有什么区别?劣质护眼台灯宣传的三大套路

护眼灯和普通台灯有什么区别&#xff1f;围绕这一问题的讨论颇多。然而&#xff0c;真正体验过护眼台灯的人会深知&#xff0c;它与普通台灯之间的差异远非一般&#xff0c;涉及照明效果、色温调节、蓝光控制、闪烁问题及功能性设计等诸多层面。为了让更多人透彻理解这两者之间…