使用某种文件分配表在EEPROM中存储结构体



我在富士通16位微控制器上的EEPROM中存储数据有问题。写入字节到EEPROM不是问题,我可以按字节方式写入和读取数据,没有问题。

我们使用dword s的枚举在EEPROM中存储不同的变量,它们都是4字节长。对于每个变量,我们希望存储最多4字节的空间。这是非常不好的,因为当我只想存储一个标志(一个位)或一个只有一个字节长的变量时,它仍然会使用四个字节。

我们使用这个四字节技术的原因是这样我们就知道我想访问的变量存储在哪个地址上。这工作得很好,但是它有一些缺点。

一个是浪费的空间,另一个是当我使用结构体时出现的问题。

例如我有一个像

这样的结构体
typedef struct {
    attenuator_whichone_t attenuator;
    char*                 attenuatorname;
    servo_whichone_t     associated_servo;
    ad_ad7683_whichone_t associated_adconverter;
    word                 item_control;
    word                 item_mode;
    word                 item_position;
} attenuator_info_t;

并初始化它:

static attenuator_info_t constinfo[_NUM_ATTENUATOR_WHICHONE_] = {...}

对于我们现在使用的代码,我们需要单独保存每个值。因此将结构分开。我真的想要按原样存储那个结构。(代码中还有更多)。

根据我的理解,我需要一个文件系统。谷歌搜索给了我一些例子,比如microFAT等等。在我看来,这太过分了。

用sizeof存储结构体并迭代所有字节就可以了,但是,我如何处理知道结构在EEPROM中的位置的问题?因此,可能需要某种文件系统。没有小一点的吗?还是什么把戏?变量的长度是固定的。这就是为什么我想知道是否有一些好的和简单的方法来存储这些结构。

我希望我能详细说明我的问题。

根据我的理解,我需要一个文件系统。谷歌搜索给了我一些例子,比如microFAT等等。在我看来,这太过分了。

不,文件系统与您描述的任务无关。文件系统定义了文件名称文件之间的映射,可以任意创建、访问、删除和调整大小。您没有提到在运行时进行修改的名称或需求。这看起来有点小题大做,因为定义文件系统的基本服务是您不需要的东西。

我们使用dword s的枚举在EEPROM中存储不同的变量,它们都是4字节长。

我想你指的是一组dword s。

如果这引起了问题,为什么不考虑改变它呢?

听起来你只知道如何初始化EEPROM与形式的定义

static attenuator_info_t constinfo[_NUM_ATTENUATOR_WHICHONE_] = {...}

EEPROM没有技术限制要求它这样做。struct是一个字节序列,就像array一样。大多数嵌入式编译器还允许您将struct、数组和其他定义的序列视为字节序列,方法是在它们周围加上适当的#pragma

对EEPROM一无所知,也不知道constinfo在你构建程序后是否会改变,我无法告诉你如何写入它。但它看起来就像是你想把一堆命名变量映射到一个字节序列。这可能需要文件格式,但不需要文件系统。

如果EEPROM是内存映射,那么你可以编译指针到它:

extern struct foo_info_type foo_info;
extern struct bar_info_type bar_info;
/* EEPROM table of contents */
struct foo_info_type *foo_ptr = & foo_info;
struct bar_info_type *bar_ptr = & bar_info;
/* ... more pointers ... */
/* Actual data in EEPROM, pointers point here */
struct foo_info_type foo_info;
struct bar_info_type bar_info;

如果您有一个结构数组,您应该能够将数据写入EEPROM并在稍后相当容易地将其读出。这里的关键是确切地知道数据存储在EEPROM中的位置。

您可以通过多种方式做到这一点。对于简单的项目,您可以简单地定义一个常量,表示存储表的内存范围的起始地址:

#define ATTENUATOR_INFO_START 0x0100 // Indicates table starts at address 256
#define ATTENUATOR_INFO_SIZE (sizeof(constinfo)/sizeof(*constinfo))
// Store table in EEPROM
memcpy(EEPROM_START + ATTENUATOR_INFO_START, constinfo, ATTENUATOR_INFO_SIZE);
// Load table from EEPROM
memcpy(constinfo, EEPROM_START + ATTENUATOR_INFO_START, ATTENUATOR_INFO_SIZE);

上面假设EEPROM被映射到内存中,常数EEPROM_START表示映射到EEPROM偏移量为0的内存地址。如果您的项目没有将EEPROM映射到内存中,那么您的过程将略有不同,但总体思路是相同的。

如果你不想以固定的偏移量存储表,另一种选择是在EEPROM中记录表的偏移量。过程大致相同:

// Offset/length information is stored in the first few bytes of the EEPROM
#define TABLE_INFO_LOCATION 0x0000
struct table_info {
    unsigned int offset;
    unsigned int num_entries;
} table_info;
// Retrieve table offset
memcpy(&table_info, EEPROM_START + TABLE_INFO_LOCATION, sizeof(table_info));
// Load table from EEPROM
memcpy(constinfo,
       EEPROM_START + table_info.offset,
       table_info.num_entries * sizeof(*constinfo));

这种方法允许更大的灵活性,因为表可以位于EEPROM中的任何位置,但仍然需要一个已知的位置来存储表信息。

如果你不能存储任何在一个预先确定的偏移量,你可以创建一个页眉/页脚签名来包装数据结构。对于未使用的字节,大多数内存设备默认为0x000xFF。您可以在表前面立即写入32个字节的模式0xBE(用于"before"),然后在表后面立即写入32个字节的模式0xAF(用于"after")。这将允许您扫描EEPROM的内存,并找到表的开始和结束,无论它在哪里。缺点是,如果内存模式出现在EEPROM的其他任何地方,您可能会寻求错误的位置,因此明智地选择您的页眉/页脚模式和大小。

最新更新