36、深入探索NVMEM与看门狗设备驱动

深入探索NVMEM与看门狗设备驱动

1. NVMEM框架概述

NVMEM(Non-Volatile Memory)设备可从内核或用户空间进行访问。在内核中,存在生产者/消费者设计模式,其中提供者驱动作为生产者,其他驱动作为消费者。

2. 编写NVMEM提供者驱动

提供者驱动的主要任务包括:
- 依据设备的数据手册提供合适的NVMEM配置,并提供访问内存的例程。
- 向系统注册设备。
- 提供设备树绑定文档。

NVMEM设备的注册和注销可使用以下函数:

struct nvmem_device *nvmem_register(const struct nvmem_config *config)
struct nvmem_device *devm_nvmem_register(struct device *dev, const struct nvmem_config *config)
int nvmem_unregister(struct nvmem_device *nvmem)
int devm_nvmem_unregister(struct device *dev, struct nvmem_device *nvmem)

注册成功后,会在 /sys/bus/nvmem/devices/dev-name/nvmem 创建二进制条目。

3. RTC设备中的NVMEM存储

许多实时时钟(RTC)设备嵌入了非易失性存储,如EEPROM或电池备份RAM。RTC设备的数据结构包含NVMEM相关字段:

struct rtc_device {
    [...]
    struct nvmem_device *nvmem;
    /* Old ABI support */
    bool nvram_old_abi;
    struct bin_attribute *nvram;
    [...]
}
  • nvmem :抽象底层硬件内存。
  • nvram_old_abi :布尔值,指示是否使用旧的(现已弃用)NVRAM ABI注册RTC的NVMEM。
  • nvram :仅用于旧ABI支持的底层内存的二进制属性。

RTC相关的NVMEM框架API可通过 RTC_NVMEM 内核配置选项启用,定义在 drivers/rtc/nvmem.c 中,包括 rtc_nvmem_register() rtc_nvmem_unregister()

以下是DS1307 RTC驱动的探测函数示例:

static int ds1307_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
    struct ds1307 *ds1307;
    int err = -ENODEV;
    int tmp;
    const struct chip_desc *chip;

    [...]
    ds1307->rtc->ops = chip->rtc_ops ? : &ds13xx_rtc_ops;
    err = rtc_register_device(ds1307->rtc);
    if (err)
        return err;
    if (chip->nvram_size) {
        struct nvmem_config nvmem_cfg = {
            .name = " ds1307_nvram" ,
            .word_size = 1,
            .stride = 1,
            .size = chip->nvram_size,
            .reg_read = ds1307_nvram_read,
            .reg_write = ds1307_nvram_write,
            .priv = ds1307,
        };
        ds1307->rtc->nvram_old_abi = true;
        rtc_nvmem_register(ds1307->rtc, &nvmem_cfg);
    }
    [...]
}
4. 实现NVMEM读写回调

为使内核和其他框架能够读写NVMEM设备及其单元,每个NVMEM提供者必须暴露读写回调函数:

typedef int (*nvmem_reg_read_t)(void *priv, unsigned int offset, void *val, size_t bytes);
typedef int (*nvmem_reg_write_t)(void *priv, unsigned int offset, void *val, size_t bytes);
  • nvmem_reg_read_t :从NVMEM设备读取数据。
  • nvmem_reg_write_t :向NVMEM设备写入数据。
5. NVMEM提供者的设备树绑定

NVMEM数据提供者应根据其父总线的设备树绑定进行描述。例如,I2C设备应作为代表其所在I2C总线的节点的子节点进行描述。

以下是一个MMIO NVMEM设备及其子节点的示例:

ocotp: ocotp@21bc000 {
    #address-cells = <1>;
    #size-cells = <1>;
    compatible = " fsl,imx6sx-ocotp" , " syscon" ;
    reg = <0x021bc000 0x4000>;
    [...]
    tempmon_calib: calib@38 {
        reg = <0x38 4>;
    };
    tempmon_temp_grade: temp-grade@20 {
        reg = <0x20 4>;
    };
    foo: foo@6 {
        reg = <0x6 0x2> bits = <7 2>
    };
    [...]
};

数据单元绑定的可能属性:
| 属性 | 描述 |
| ---- | ---- |
| reg | 必需属性,描述数据区域的偏移量和大小。 |
| bits | 可选属性,指定位偏移和位数。 |

6. NVMEM消费者驱动API

NVMEM消费者驱动可通过包含 <linux/nvmem-consumer.h> 来使用以下基于单元的API:

struct nvmem_cell *nvmem_cell_get(struct device *dev, const char *name);
struct nvmem_cell *devm_nvmem_cell_get(struct device *dev, const char *name);
void nvmem_cell_put(struct nvmem_cell *cell);
void devm_nvmem_cell_put(struct device *dev, struct nvmem_cell *cell);
void *nvmem_cell_read(struct nvmem_cell *cell, size_t *len);
int nvmem_cell_write(struct nvmem_cell *cell, void *buf, size_t len);
int nvmem_cell_read_u32(struct device *dev, const char *cell_id, u32 *val);

以下是读取 tempmon 节点分配的单元内容的代码示例:

static int imx_init_from_nvmem_cells(struct platform_device *pdev)
{
    int ret; u32 val;
    ret = nvmem_cell_read_u32(&pdev->dev, " calib" , &val);
    if (ret)
        return ret;
    ret = imx_init_calib(pdev, val);
    if (ret)
        return ret;
    ret = nvmem_cell_read_u32(&pdev->dev, " temp_grade" , &val);
    if (ret)
        return ret;
    imx_init_temp_grade(pdev, val);
    return 0;
}
7. 用户空间的NVMEM

NVMEM用户空间接口依赖于sysfs。每个注册的NVMEM设备在 /sys/bus/nvmem/devices 下有一个目录条目,其中包含一个 nvmem 二进制文件。

以下是读写NVMEM内容的示例:

cat /sys/bus/nvmem/devices/2-00550/nvmem
echo " foo"  > /sys/bus/nvmem/devices/2-00550/nvmem
cat /sys/bus/nvmem/devices/2-00550/nvmem
8. 看门狗设备驱动概述

看门狗是一种硬件(有时由软件模拟)设备,用于确保系统的可用性。它本质上是一个定时器,在系统出现故障时触发硬件复位。

9. 技术要求

在开始学习看门狗设备驱动之前,需要具备以下条件:
- C编程技能
- 基本电子知识
- Linux内核v4.19.X源代码,可从 https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/refs/tags 获取

10. 看门狗数据结构和API

看门狗子系统的主要数据结构是 struct watchdog_device

struct watchdog_device {
    int id;
    struct device *parent;
    const struct watchdog_info *info;
    const struct watchdog_ops *ops;
    const struct watchdog_governor *gov;
    unsigned int bootstatus;
    unsigned int timeout;
    unsigned int pretimeout;
    unsigned int min_timeout;
    struct watchdog_core_data *wd_data;
    unsigned long status;
    [...]
};

各字段含义如下:
| 字段 | 描述 |
| ---- | ---- |
| id | 内核在设备注册时分配的看门狗ID。 |
| parent | 设备的父设备。 |
| info | 指向 struct watchdog_info 的指针,提供看门狗定时器的额外信息。 |
| ops | 指向看门狗操作列表的指针。 |
| gov | 指向看门狗预超时调节器的指针。 |
| bootstatus | 看门狗设备在启动时的状态。 |
| timeout | 看门狗设备的超时值(秒)。 |
| pretimeout | 预超时时间间隔(秒)。 |
| min_timeout | 看门狗设备的最小超时值(秒)。 |
| wd_data | 指向看门狗核心内部数据的指针。 |
| status | 包含设备内部状态位的字段。 |

struct watchdog_info 结构定义如下:

struct watchdog_info {
    u32 options;
    u32 firmware_version;
    u8 identity[32];
};

struct watchdog_ops 结构定义如下:

struct watchdog_ops {
    struct module *owner;
    /* mandatory operations */
    int (*start)(struct watchdog_device *);
    int (*stop)(struct watchdog_device *);
    /* optional operations */
    int (*ping)(struct watchdog_device *);
    unsigned int (*status)(struct watchdog_device *);
    int (*set_timeout)(struct watchdog_device *, unsigned int);
    int (*set_pretimeout)(struct watchdog_device *, unsigned int);
    unsigned int (*get_timeleft)(struct watchdog_device *);
    int (*restart)(struct watchdog_device *, unsigned long, void *);
    long (*ioctl)(struct watchdog_device *, unsigned int, unsigned long);
};

其中, start stop 是启动和停止看门狗的必需操作。

通过以上内容,我们详细介绍了NVMEM框架和看门狗设备驱动的相关知识,包括数据结构、API以及使用方法。这些知识对于开发和维护嵌入式系统具有重要意义。

深入探索NVMEM与看门狗设备驱动

11. 看门狗设备的状态标志

struct watchdog_device 中的 status 字段包含了设备的内部状态位,以下是各状态标志的详细说明:
| 状态标志 | 描述 |
| ---- | ---- |
| WDOG_ACTIVE | 指示看门狗是否正在运行/激活。 |
| WDOG_NO_WAY_OUT | 表示是否设置了 “无退出” 功能,可使用 watchdog_set_nowayout() 函数设置。 |
| WDOG_STOP_ON_REBOOT | 表示在系统重启时应停止看门狗。 |
| WDOG_HW_RUNNING | 指示硬件看门狗是否正在运行,可使用 watchdog_hw_running() 函数检查。 |
| WDOG_STOP_ON_UNREGISTER | 指定在设备注销时应停止看门狗,可使用 watchdog_stop_on_unregister() 函数设置。 |

12. struct watchdog_info 结构详解

struct watchdog_info 结构是用户空间 API 的一部分,在 WDIOC_GETSUPPORT ioctl 成功时返回给用户空间。该结构各字段含义如下:
| 字段 | 描述 |
| ---- | ---- |
| options | 表示卡/驱动程序支持的功能,是一个位掩码。 |
| firmware_version | 卡的固件版本。 |
| identity | 描述设备的字符串。 |

options 字段的可能标志及含义:
| 标志 | 描述 |
| ---- | ---- |
| WDIOF_SETTIMEOUT | 表示看门狗设备可以设置超时值,若设置此标志,则必须定义 set_timeout 回调函数。 |
| WDIOF_MAGICCLOSE | 表示驱动程序支持 “魔术关闭” 功能,即写入 V 字符可在下次关闭时关闭看门狗(前提是未设置 nowayout )。 |
| WDIOF_POWERUNDER | 表示设备可以监测/检测电源故障,在 watchdog_device.bootstatus 中设置时,表示系统因欠压而复位。 |
| WDIOF_POWEROVER | 表示设备可以监测工作电压,在 watchdog_device.bootstatus 中设置时,表示系统可能因过压而复位。 |
| WDIOF_OVERHEAT | 表示看门狗设备可以监测芯片/SoC 温度,在 watchdog_device.bootstatus 中设置时,表示上次系统重启是由于超过热限。 |
| WDIOF_FANFAULT | 表示看门狗设备可以监测风扇,设置时表示由看门狗卡监测的系统风扇发生故障。 |
| WDIOF_EXTERN1 WDIOF_EXTERN2 | 表示设备有单独的事件输入,在 watchdog_device.bootstatus 中设置时,表示系统上次重启是由于外部继电器/源 1 或 2。 |
| WDIOF_PRETIMEOUT | 表示看门狗设备支持预超时功能。 |
| WDIOF_KEEPALIVEPING | 表示驱动程序支持 WDIOC_KEEPALIVE ioctl,在 watchdog_device.bootstatus 中设置时,表示自上次查询以来看门狗收到了保活 ping。 |
| WDIOF_CARDRESET | 仅在 watchdog_device.bootstatus 中出现,表示上次重启是由看门狗本身(实际上是其超时)引起的。 |

13. struct watchdog_ops 结构详解

struct watchdog_ops 结构包含了允许对看门狗设备进行的操作列表,各操作含义如下:
| 操作 | 描述 |
| ---- | ---- |
| start | 启动看门狗,必需操作。 |
| stop | 停止看门狗,必需操作。 |
| ping | 可选操作,用于向看门狗发送保活信号。 |
| status | 可选操作,用于获取看门狗的状态。 |
| set_timeout | 可选操作,用于设置看门狗的超时值。 |
| set_pretimeout | 可选操作,用于设置看门狗的预超时值。 |
| get_timeleft | 可选操作,用于获取看门狗剩余的时间。 |
| restart | 可选操作,用于重启看门狗。 |
| ioctl | 可选操作,用于处理自定义的 ioctl 命令。 |

14. 看门狗设备驱动开发流程

以下是开发看门狗设备驱动的基本流程:

graph TD;
    A[初始化看门狗设备结构] --> B[设置看门狗操作函数];
    B --> C[注册看门狗设备];
    C --> D[处理看门狗事件];
    D --> E[注销看门狗设备];

具体步骤如下:
1. 初始化看门狗设备结构 :创建并初始化 struct watchdog_device 结构,设置各字段的值。
2. 设置看门狗操作函数 :填充 struct watchdog_ops 结构,实现必要的操作函数,如 start stop
3. 注册看门狗设备 :使用相应的函数将看门狗设备注册到系统中。
4. 处理看门狗事件 :在驱动程序中处理看门狗的各种事件,如超时、预超时等。
5. 注销看门狗设备 :在驱动程序卸载时,注销看门狗设备。

15. 总结

本文详细介绍了 NVMEM 框架和看门狗设备驱动的相关知识。在 NVMEM 方面,我们了解了提供者驱动和消费者驱动的开发,包括设备注册、读写回调实现、设备树绑定以及用户空间访问等内容。在看门狗设备驱动方面,我们学习了看门狗的基本原理、数据结构、API 以及开发流程。掌握这些知识对于开发和维护嵌入式系统具有重要意义,能够帮助我们更好地管理非易失性内存和确保系统的可靠性。

通过对 NVMEM 框架和看门狗设备驱动的深入学习,我们可以在实际项目中灵活运用这些技术,提高系统的性能和稳定性。例如,在嵌入式系统中使用 NVMEM 存储重要的配置信息,使用看门狗设备确保系统在出现故障时能够自动复位,从而保证系统的正常运行。

【SCI级别】多策略改进鲸鱼优化算法(HHWOA)和鲸鱼优化算法(WOA)在CEC2017测试集函数F1-F30寻优对比内容概要:本文档主要介绍了一项关于多策略改进鲸鱼优化算法(HHWOA)标准鲸鱼优化算法(WOA)在CEC2017测试集函数F1-F30上进行寻优性能对比的研究,属于智能优化算法领域的高水平科研工作。文中通过Matlab代码实现算法仿真,重点展示了HHWOA在收敛速度、寻优精度和稳定性方面的优势,体现了多策略改进的有效性。该研究适用于复杂优化问题求解,尤其在工程优化、参数辨识、机器学习超参数调优等领域具有应用潜力。; 适合人群:具备一定算法基础和Matlab编程能力的研究生、科研人员及从事智能优化算法开发应用的工程技术人员,尤其适合致力于SCI论文写作算法创新的研究者。; 使用场景及目标:①用于理解鲸鱼优化算法的基本原理及多策略改进思路(如种群初始化、非线性收敛因子、精英反向学习等);②为智能优化算法的性能测试对比实验提供CEC2017标准测试平台的实现参考;③支撑学术研究中的算法创新论文复现工作。; 阅读建议:建议结合提供的Matlab代码进行实践操作,重点关注HHWOA的改进策略模块WOA的差异,通过重复实验验证算法性能,并可将其思想迁移至其他优化算法的改进中,提升科研创新能力。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值