嵌入式C数据存储模块设计

Jef*_*amb 8 c database embedded

我正在设计嵌入式C数据存储模块.它将包含在希望访问此"共享"系统范围数据的文件/模块中.多个任务聚合了数十个输入(GPIO,CAN,I2C/SPI/SSP数据等),并使用API​​存储这些值.然后,其他任务可以通过API安全地访问数据.该系统是带有RTOS的嵌入式应用程序,因此互斥锁用于保护数据.无论实施如何,都将使用这些想法

我过去曾设计过这样的东西,我正在努力改进它.我目前正处于一个新实施的中途,我遇到了一些小问题,并且会从一个全新的视角中受益.

快速了解该模块的要求:

  • 理想情况下,会有一个接口可以访问变量(一个获取,一个集合).
  • 我想返回不同的变量类型(浮点数,整数等).这意味着可能需要宏.
  • 我并没有为代码空间而努力,但它始终是一个问题
  • 快速获取/设置绝对是最重要的(这意味着存储在字符串ala xml/json中)
  • 在运行时期间不需要添加新变量.一切都是在启动时静态定义的

    问题是你将如何设计这样的东西?枚举,结构,访问器,宏等?我不是在这里寻找代码,只讨论一般的整体设计思路.如果互联网上有一个解决这些问题的解决方案,甚至只需一个链接即可.

  • Dan*_*Dan 5

    我自己曾经遇到过这种情况.每当我结束"滚动自己"时,我绝对不会患有"不发明"(NIH)综合症.有时,空间,处理周转时间或可靠性/可恢复性要求只会使这条路成为最不痛苦的路径.

    所以,不要在这个主题上写出伟大的美国小说,我只会在这里抛出一些想法,因为你的问题相当广泛(但感谢你至少形成一个问题并提供背景).

    桌面上有C++吗?内联函数,模板和一些Boost库在这里可能很有用.但我猜这是直截了当的C.

    如果您使用的是C99,则至少可以使用内联函数,这在函数类型安全性方面比宏高出一步.

    您可能想要考虑使用多个互斥锁来保护数据的不同部分; 即使更新很快,您可能希望将数据拆分为多个部分(例如配置数据,初始化数据,错误记录数据,跟踪数据等),并为每个部分提供自己的互斥锁,从而减少漏斗/阻塞点.

    您还可以考虑使对数据的所有访问都通过服务器任务.所有读取和写入都通过API与服务器任务进行通信.服务器任务从其队列中按顺序提取读取和写入请求,通过写入RAM镜像快速处理它们,如果需要(至少对于读取请求)发送响应,然后在必要时在后台将数据缓冲到NVM.与简单的互斥体相比,它听起来很重,但它在某些用例中具有优势.对您的应用程序了解不足以了解这是否可能.

    我要说的一件事是,通过标签获取/设置的想法(例如,可能是CONFIG_DATA,ADDRESS_DATA等枚举列表)是直接寻址数据的一大步(例如"在地址处给我256个字节) ox42000).我看到许多商店在整个物理寻址方案最终崩溃并且需要重新设计/重新设计时遭受巨大的痛苦.尽量保持与"如何"脱离的"什么" - 客户不应该知道或关心存储的东西,它有多大等等.(你可能已经知道这一切,对不起,如果是这样,我只是一直看到它......)

    最后一件事.你提到过互斥体.谨防优先级倒置......在某些情况下,可以使这些"快速访问"需要很长时间.大多数内核互斥锁实现允许您对此进行说明,但通常默认情况下不会启用它.再次,对不起,如果这是旧消息......


    Jef*_*amb 0

    我想我会更新我唯一未接受的问题之一。这是我的最终实现。使用这个已经一年多了,效果非常好。添加变量非常容易,而且它给我们带来的好处非常少。

    lib_data.h:

    #ifndef __LIB_DATA_H
    #define __LIB_DATA_H
    
    #include <type.h>
    
    /****************************************************************************************
     * Constant Definitions
     ***************************************************************************************/
    
    /* Varname, default value (uint32_t) */
    #define DATA_LIST                                                                       \
      DM(D_VAR1, 0)                                                                         \
      DM(D_VAR2, 1)                                                                         \
      DM(D_VAR3, 43)
    
    #define DM(y, z)    y,
    
    /* create data structure from the macro */
    typedef enum {
        DATA_LIST
        NUM_DATA_VARIABLES
    } dataNames_t;
    
    typedef struct {
        dataNames_t name;
        uint32_t value;
    } dataPair_t;
    
    /* the macro has to be undefined to allow the fault list to be reused without being
     * defined multiple times
     *
     * this requires:
     * a file specific lint option to suppress the rule for use of #undef
     */
    #undef DM
    
    /****************************************************************************************
     * Data Prototypes
     ***************************************************************************************/
    
    /****************************************************************************************
     * External Function Prototypes
     ***************************************************************************************/
    
    /**
     * Fetch a machine parameter
     *
     * \param dataName The variable from DATA_LIST that you want to fetch
     *
     * \return The value of the requested parameter
     *
     */
    uint32_t lib_data_Get(dataNames_t dataName);
    
    /**
     * Set a machine parameter
     *
     * \param dataName The variable from DATA_LIST that you want to set
     * \param dataVal The value you want to set the variable to
     *
     * \return void
     *
     */
    void lib_data_Set(dataNames_t dataName, uint32_t dataVal);
    
    #endif /* __LIB_DATA_H */
    
    Run Code Online (Sandbox Code Playgroud)

    lib_data.c:

    #include <type.h>
    #include "lib_data.h"
    
    /****************************************************************************************
     * Variable Declarations
    ***************************************************************************************/
    /* Used to initialize the data array with defaults ##U appends a 'U' to the bare
     * integer specified in the DM macro */
    
    #define DM(y, z)               \
        dataArray[y].name = y;     \
        dataArray[y].value = z##U;
    
    static bool_t dataInitialized = FALSE;
    static dataPair_t dataArray[NUM_DATA_VARIABLES];
    
    /****************************************************************************************
     * Private Function Prototypes
     ***************************************************************************************/
    static void lib_data_Init(void);
    
    /****************************************************************************************
     * Public Functions
     ***************************************************************************************/
    uint32_t lib_data_Get(dataNames_t dataName) {
        if(!dataInitialized) {
            lib_data_Init();
        }
    
        /* Should only be used on systems that do word-sized asm reads/writes.
         * If the lib gets extended to multi-word storage capabilities, a mutex
         * is necessary to protect against multi-threaded access */
        return dataArray[dataName].value;
    }
    
    void lib_data_Set(dataNames_t dataName, uint32_t dataVal) {
        if(!dataInitialized) {
            lib_data_Init();
        }
    
        /* Should only be used on systems that do word-sized asm reads/writes.
         * If the lib gets extended to multi-word storage capabilities, a mutex
         * is necessary to protect against multi-threaded access */
        dataArray[dataName].value = dataVal;
    }
    
    /****************************************************************************************
     * Private Functions
     ***************************************************************************************/
    
    /**
     * initialize the machine data tables
     *
     * \param none
     *
     * \return none
     *
     */
    static void lib_data_Init(void) {
        /* Invoke the macro to initialize dataArray */
        DATA_LIST
        dataInitialized = TRUE;
    }
    
    Run Code Online (Sandbox Code Playgroud)