嵌入式驱动开发详解6(RTC)

文章目录

  • 前言
  • RTC简介
  • RTC驱动分析
    • RTC驱动框架
    • RTC驱动实现
  • RTC应用
  • 后续

前言

实时时钟是很常用的一个外设,通过实时时钟我们就可以知道年、月、日和时间等信息。 因此在需要记录时间的场合就需要实时时钟,可以使用专用的实时时钟芯片来完成此功能,但 是现在大多数的 MCU 或者 MPU 内部就已经自带了实时时钟外设模块。

RTC简介

STM32 内部有一个 RTC 外设模块,这个模块需要一个 32.768KHz 的晶振,对这个 RTC 模块进行初始化就可以得到一个实时时钟。I.MX6U 内部也有 个 RTC 模块,但是不叫作“RTC”,而是叫做“SNVS”,这一点要注意
SNVS 直译过来就是安全的非易性存储,SNVS 里面主要是一些低功耗的外设,包括一个 安全的实时计数器(RTC)、一个单调计数器(monotonic counter)和一些通用的寄存器。SNVS 里面的外设在芯片掉电以后由电池供电继续运行,这个纽扣电池就是在主电源关闭以后为 SNVS 供电的。

SNVS 分为两个子模块:SNVS_HP 和 SNVS_LP,也就是高功耗域(SNVS_HP)和低功耗域 (SNVS_LP),系统主电源断电以后SNVS_HP也会断电,但是在后备电源支持下,SNVS_LP 是不会断电的,而且SNVS_LP是和芯片复位隔离开的,因此SNVS_LP相关的寄存器的值会一直保存着。
在这里插入图片描述
①、VDD_HIGH_IN 是系统(芯片)主电源,这个电源会同时供给给 SNVS_HP 和 SNVS_LP。
②、VDD_SNVS_IN 是纽扣电池供电的电源,这个电源只会供给给 SNVS_LP,保证在系 统主电源 VDD_HIGH_IN 掉电以后 SNVS_LP 会继续运行。
③、SNVS_HP 部分。
④、SNVS_LP 部分,此部分有个 SRTC,这个就是我们本章要使用的 RTC。

其实不管是 SNVS_HP 还是 SNVS_LP,其内部都有一个 SRTC,但是因为 SNVS_HP 在系 统电源掉电以后就会关闭,所以我们使用的是 SNVS_LP内部的SRTC,不管是 SNVS_HP 里面的SRTC,还是 SNVS_LP 里面的 SRTC,其本质就是一个定时 器,SRTC需要外界提供一个32.768KHz 的时钟,寄存器 SNVS_LPSRTCMR 和 SNVS_LPSRTCLR 保存着秒数,直接读取这两个寄存 器的值就知道过了多长时间了。一般以 1970 年 1 月 1 日为起点,加上经过的秒数即可得到现在 的时间和日期,原理还是很简单的。SRTC 也是带有闹钟功能的,可以在寄存器 SNVS_LPAR 中 写入闹钟时间值,当时钟值和闹钟值匹配的时候就会产生闹钟中断,要使用时钟功能的话还需要进行一些设置。

RTC驱动分析

RTC驱动框架

Linux内核中的RTC设备不仅用于获取当前时间,还可以用于设置系统时间。内核提供了一套API,允许用户空间程序与RTC设备进行交互,实现时间的读取和设置。
RTC 设备驱动是一个标准的字符设备驱动,应用程序通过 open、release、read、write 和 ioctl 等函数完成对 RTC 设备的操作,如下图所示:
在这里插入图片描述
内核将 RTC 设备抽象为 rtc_device 结构体,定义在include/linux/rtc.h:

struct rtc_device
{struct device dev;struct module *owner;int id;char name[RTC_DEVICE_NAME_SIZE];const struct rtc_class_ops *ops;struct mutex ops_lock;struct cdev char_dev;unsigned long flags;…………
};

我们需要重点关注的是 ops 成员变量,这是一个 rtc_class_ops 类型的指针变量,定义在include/linux/rtc.h,rtc_class_ops 为 RTC 设备的最底层操作函数集合,包括从 RTC 设备中读取时间、向 RTC 设备写入新的时间值等。

struct rtc_class_ops {int (*open)(struct device *);void (*release)(struct device *);int (*ioctl)(struct device *, unsigned int, unsigned long);int (*read_time)(struct device *, struct rtc_time *);int (*set_time)(struct device *, struct rtc_time *);int (*read_alarm)(struct device *, struct rtc_wkalrm *);int (*set_alarm)(struct device *, struct rtc_wkalrm *);int (*proc)(struct device *, struct seq_file *);int (*set_mmss64)(struct device *, time64_t secs);int (*set_mmss)(struct device *, unsigned long secs);int (*read_callback)(struct device *, int data);int (*alarm_irq_enable)(struct device *, unsigned int enabled);
};

rtc_class_ops 中 的这 些 函数只最底层的RTC设备操作函数, 并不是提供给应用层的 file_operations 函数操作集。RTC 是个字符设备,那么肯定有字符设备的 file_operations 函数操作集,Linux 内核提供了一个 RTC 通用字符设备驱动文件,文件名为 drivers/rtc/rtc-dev.c,rtcdev.c 文件提供了所有 RTC 设备共用的 file_operations 函数操作集。之所以称之为通用,是因为二次开发的驱动是建立在这个通用字符设备驱动文件和linux内核的基础上开发的

static const struct file_operations rtc_dev_fops = {.owner		= THIS_MODULE,.llseek		= no_llseek,.read		= rtc_dev_read,.poll		= rtc_dev_poll,.unlocked_ioctl	= rtc_dev_ioctl,.open		= rtc_dev_open,.release	= rtc_dev_release,.fasync		= rtc_dev_fasync,
};

应用程序可以通过 ioctl 函 数来设置/读取时间、设置/读取闹钟的操作,那么对应的 rtc_dev_ioctl 函数就会执行, rtc_dev_ioctl 最终会通过操作 rtc_class_ops 中的 read_time、set_time 等函数来对具体 RTC 设备 的读写操作。具体的源码详细分析就不展示了,需要时可以自行查看。
字符设备的file_operations结构体设置好以后需要调用rtc_class_ops里的指针函数,但是rtc_class_ops的函数仅仅只是设置好了形式没有注册,因此需要将其注册到 Linux 内核中,这里我们可以使用 rtc_device_register 函数完成注册工作,rtc_device_unregister 函数来注销注册的 rtc_device。

struct rtc_device *rtc_device_register(const char *name, struct device *dev, const struct rtc_class_ops *ops, struct module *owner)
void rtc_device_unregister(struct rtc_device *rtc)

还有另外一对rtc_device注册函数devm_rtc_device_register和devm_rtc_device_unregister, 分别为注册和注销 rtc_device。

RTC驱动实现

一般情况下,内部 RTC 驱动都不需要我们去编写,半导体厂商会编写好,这里就只学习原厂已经写好的驱动是怎么写的,以NXP的imx6ull为例,分析驱动,先从设备树入手,打开 imx6ull.dtsi,在里面找到如下 snvs_rtc 设备节点,节点 内容如下所示:

/{soc{aips1: aips-bus@2000000{snvs: snvs@020cc000 {compatible = "fsl,sec-v4.0-mon", "syscon", "simple-mfd";reg = <0x020cc000 0x4000>;snvs_rtc: snvs-rtc-lp {compatible = "fsl,sec-v4.0-mon-rtc-lp";regmap = <&snvs>;offset = <0x34>;interrupts = <GIC_SPI 19 IRQ_TYPE_LEVEL_HIGH>, <GIC_SPI 20 		IRQ_TYPE_LEVEL_HIGH>;};};}};
};

通过兼容属性 compatible 的值“fsl,sec-v4.0-mon-rtc-lp”可以在Linux内核源码中搜索到对应的驱动文件,此文件为 drivers/rtc/rtc-snvs.c,如下所示,可以看出该驱动对应的也是platform架构:

static const struct of_device_id snvs_dt_ids[] = {{ .compatible = "fsl,sec-v4.0-mon-rtc-lp", },{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, snvs_dt_ids);static struct platform_driver snvs_rtc_driver = {.driver = {.name	= "snvs_rtc",.pm	= SNVS_RTC_PM_OPS,.of_match_table = snvs_dt_ids,},.probe		= snvs_rtc_probe,
};

在.snvs_rtc_probe函数中,主要做了以下几个事件,代码就不在展示了:

  • platform_get_resource 函数从设备树中获取到 RTC 外设寄存器基地址
  • devm_ioremap_resource 完成内存映射,得到 RTC 外设寄存器物理基 地址对应的虚拟地址
  • devm_regmap_init_mmio 函数将 RTC 的硬件寄存器转化为 regmap 形式,这样 regmap 机制的 regmap_write、regmap_read 等 API 函数才能操作寄存器。==具体有关regmap机制的说明后面会出相关笔记
  • 从设备树中获取 RTC 的中断号
  • 设置对应的寄存器
  • 用 snvs_rtc_enable 函数使能 RTC
  • devm_request_irq 函数请求 RTC 中断
  • devm_rtc_device_register 函数向系统注册 rtc_devcie,此函数会设置snvs_rtc_ops操作集
    最后需要原厂驱动开发人员把snvs_rtc_ops对应的函数完成:
static const struct rtc_class_ops snvs_rtc_ops = {.read_time = snvs_rtc_read_time,.set_time = snvs_rtc_set_time,.read_alarm = snvs_rtc_read_alarm,.set_alarm = snvs_rtc_set_alarm,.alarm_irq_enable = snvs_rtc_alarm_irq_enable,
};

RTC应用

  • 如果要查看时间的话输入“date”命令即可
date
  • RTC 时间设置也是使用的date命令,输入“date --help”命令即可查看 date 命令如何设置系统 时间,设置当前时间为 2019 年 8 月 31 日 18:13:00,因此输入如下命令:
date -s "2019-08-31 18:13:00"
  • “date -s”命令仅仅是将当前系统时间设置了,此时间还没有写入到 I.MX6U 内部 RTC 里面或其他的 RTC 芯片里面,因此系统重启以后时间又会丢失。我们需要将 当前的时间写入到 RTC 里面,这里要用到 hwclock 命令,输入如下命令将系统时间写入到 RTC 里面:
hwclock -w //将当前系统时间写入到 RTC 里面

后续

到这里对RTC的笔记记录大致结束了,后面有新的相关的重要的内容会继续进行更新。

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

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

相关文章

传输层7——TCP拥塞控制(重点!!!)

目录 一、认识拥塞控制 1、什么叫做拥塞&#xff1f; 2、拥塞的特点 3、流量控制 VS 拥塞控制 二、TCP如何防止拥塞&#xff1f; 1、慢开始 2、拥塞避免 3、3重复确认 和 快重传算法 4、快恢复算法 5、总结 三、主动队列管理AQM 1、技术背景 2、AQM思 想和实现策略…

轮播(css+js)

目录 1.实现效果 2.基础代码演示 2.1js代码 2.1css样式 2.3实现效果 3.实现点击切换 3.1给button添加点击事件 3.2效果图如下 3.3发现问题 3.3.1不循环 3.3.2循环 1.实现效果 2.基础代码演示 2.1js代码 <div class"out-box"><div class"tes…

优秀的3d建模是数据可视化的视觉核心1

增强视觉效果&#xff1a;3D建模通过创建三维立体图像&#xff0c;为观众提供了更为真实和直观的视觉体验。相比于传统的二维图表和图形&#xff0c;3D模型能够更准确地展示复杂数据之间的空间关系&#xff0c;使数据可视化大屏上的信息更加生动和易于理解。 提升信息传达效率&…

flink sink kafka的事务提交现象猜想

现象 查看flink源码时 sink kafka有事务提交机制&#xff0c;查看源码发现是使用两阶段提交策略&#xff0c;而事务提交是checkpoint完成后才执行&#xff0c;那么如果checkpoint设置间隔时间比较长时&#xff0c;事务未提交之前&#xff0c;后端应该消费不到数据&#xff0c…

Y3编辑器文档4:触发器1(对话、装备、特效、行为树、排行榜、不同步问题)

文章目录 一、触发器简介1.1 触发器界面1.2 ECA语句编辑及快捷键1.3 参数设置1.4 变量设置1.5 实体触发器1.6 函数库与触发器复用 二、触发器的多层结构2.1 子触发器&#xff08;在游戏内对新的事件进行注册&#xff09;2.2 触发器变量作用域2.3 复合条件2.4 循环2.5 计时器2.6…

【开源】A065—基于SpringBoot的库存管理系统的设计与实现

&#x1f64a;作者简介&#xff1a;在校研究生&#xff0c;拥有计算机专业的研究生开发团队&#xff0c;分享技术代码帮助学生学习&#xff0c;独立完成自己的网站项目。 代码可以查看项目链接获取⬇️&#xff0c;记得注明来意哦~&#x1f339; 赠送计算机毕业设计600个选题ex…

Ariba Procurement: Administration_Cloud Basics

# SAP Ariba Procurement: Administration_Cloud Basics 认识Ariba Cloud SAP Ariba Procurement 是一个云计算平台… The Ariba Cloud 平台需要简单理解的概念: Datacenter数据中心:SAP Ariba在世界各地有许多数据中心。这些数据中心构成了Ariba云的基本物理基础设施。 …

vulnhub靶场【shenron】--1

前言 靶机&#xff1a;shenron-1 攻击&#xff1a;kali 都采用虚拟机&#xff0c;网卡为桥接模式 主机发现 使用arp-scan -l或netdiscover -r 192.168.1.1/24扫描 信息收集 使用nmap扫描端口 网站信息探测 查看页面&#xff0c;发现是apache2的默认界面&#xff0c;查看…

等保2.0数据库测评之SQL server数据库测评

一、SQL server数据库介绍 SQL server美国Microsoft公司推出的一种关系型数据库系统。SQL Server是一个可扩展的、高性能的、为分布式客户机/服务器计算所设计的数据库管理系统。 本次安装环境为Windows10专业版操作系统&#xff0c;数据库版本为Microsoft SQL Server 2019 (…

无人机之报警器的工作原理!

一、电量监测技术 电量监测是无人机电量指示和报警功能的基础。通过实时监测无人机的电池电量&#xff0c;系统能够准确判断电池的剩余使用时间&#xff0c;并在电量不足时发出报警。电量监测技术通常包括以下几个方面&#xff1a; 电压检测&#xff1a;无人机电池内部通常配…

【pyspark学习从入门到精通23】机器学习库_6

目录 分割连续变量 标准化连续变量 分类 分割连续变量 我们经常处理高度非线性的连续特征&#xff0c;而且只用一个系数很难拟合到我们的模型中。 在这种情况下&#xff0c;可能很难只通过一个系数来解释这样一个特征与目标之间的关系。有时&#xff0c;将值划分到离散的桶中…

解密时序数据库的未来:TDengine Open Day技术沙龙精彩回顾

在数字化时代&#xff0c;开源已成为推动技术创新和知识共享的核心力量&#xff0c;尤其在数据领域&#xff0c;开源技术的涌现不仅促进了行业的快速发展&#xff0c;也让更多的开发者和技术爱好者得以参与其中。随着物联网、工业互联网等技术的广泛应用&#xff0c;时序数据库…

QT 使用共享内存 实现进程间通讯

QSharedMemory&#xff1a;如果两个进程运行在同一台机器上&#xff0c;且对性能要求非常高&#xff08;如实时数据共享、图像渲染等&#xff09;&#xff0c;建议使用共享内存。 优点&#xff1a; 高性能&#xff1a; 共享内存是进程间通信的最快方式之一&#xff0c;因为数…

OpenCV实验:图片加水印

第二篇&#xff1a;图片添加水印&#xff08;加 logo&#xff09; 1. 实验原理 水印原理&#xff1a; 图片添加水印是图像叠加的一种应用&#xff0c;分为透明水印和不透明水印。水印的实现通常依赖于像素值操作&#xff0c;将水印图片融合到目标图片中&#xff0c;常用的方法…

深入解析下oracle的number底层存储格式

oracle数据库中&#xff0c;number数据类型用来存储数值数据&#xff0c;它既可以存储负数数值&#xff0c;也可以存储正数数值。相对于其他类型数据&#xff0c;number格式的数据底层存储格式要复杂得多。今天我们就详细探究下oracle的number底层存储格式。 一、环境搭建 1.…

SparkSQL与Hive的整合

文章目录 SparkSQL与Hive的整合1.1. Spark On Hive1.1.1. Hive的准备工作1.1.2. Spark的准备工作1.1.3. Spark代码开发1.1.4. Spark On Hive案例 1.2. Hive On Spark1.3. SparkSQL命令行1.4. SparkSQL分布式查询引擎1.4.1. 开启ThriftServer服务1.4.2. beeline连接ThriftServer…

(持续更新)linux网络编程中需要注意的内核参数与网络机制

目录 零、基本说明 一、内核参数 二、相关机制 1、GRO &#xff08;1&#xff09;适用场景 &#xff08;2&#xff09;优缺点 &#xff08;3&#xff09;相关操作 2、Nagle 算法 &#xff08;1&#xff09;基本规则 &#xff08;2&#xff09;优缺点 &#xff08;3&…

DevExpress WPF中文教程:Grid - 如何移动和调整列大小?(一)

DevExpress WPF拥有120个控件和库&#xff0c;将帮助您交付满足甚至超出企业需求的高性能业务应用程序。通过DevExpress WPF能创建有着强大互动功能的XAML基础应用程序&#xff0c;这些应用程序专注于当代客户的需求和构建未来新一代支持触摸的解决方案。 无论是Office办公软件…

Matlab笔记---clear、clc、clear all应用

在MATLAB中&#xff0c;clear、clc 和 clear all 是三个常用的命令&#xff0c;它们各自有不同的作用&#xff1a; clc&#xff1a; clc 命令用于清除MATLAB命令窗口中的所有输出。它不会删除任何变量、函数或文件&#xff0c;只是清除屏幕上的显示内容&#xff0c;让你可以更…

Qt 一个简单的QChart 绘图

Qt 一个简单的QChart 绘图 先上程序运行结果图&#xff1a; “sample9_1QChart.h” 文件代码如下&#xff1a; #pragma once#include <QtWidgets/QMainWindow> #include "ui_sample9_1QChart.h"#include <QtCharts> //必须这么设置 QT_CHARTS_USE_NAME…