1、概述

本文档基于SylixOS-EVB-i.MX6Q验证平台,介绍SylixOS中RTC设备驱动实现过程,可作为在SylixOS集成开发环境下进行字符设备驱动开发的参考。

2、RTC设备驱动

2.1硬件原理

实时时钟(RTC)的主要功能是在系统掉电的情况下,利用备用电源使时钟继续运行,保证不会丢失时间信息。

i.MX6Q验证平台上使用的是外置实时时钟集成电路ISL1208。硬件接线如图 2.1所示。

图 2.1 RTC硬件接线

图中,X1和X2为内部反向放大器的输入和输出引脚,要求外置一个32.768kHz的晶体振荡器以提供振荡源;VBAT为备用电源提供端,当VDD电源失效时,VBAT端的电源立即工作,保证在外部供电中断的情况下,内部的时钟信号产生电路依旧正常工作;SDA和SCL为连接到I2C总线的两个引脚,用于传输串行数据信号和时钟信号,最高传输速率达到400kHz;nRQ/FOUT是一个多功能引脚,可以将其配置为中断输出或固定频率输出端;VDD和GND分别为电源端和地,ISL1208的工作电压为2.0~5.5V。

2.2驱动实现

2.2.1安装RTC设备驱动程序

参照上一章节字符设备驱动模型,调用API_RtcDrvInstall内核函数,注册RTC设备驱动程序,包括RTC设备的创建、删除、打开、关闭、读写及IO控制等驱动函数,注册的过称即是在内核维护的驱动程序表中,找到空闲位置,然后将驱动函数填入该空闲驱动程序表。注册RTC设备驱动流程如程序清单 2.1所示,函数返回驱动函数索引号_G_iRtcDrvNum——驱动函数在驱动程序表中的位置。

程序清单 2.1安装RTC设备驱动程序

LW_API  INT  API_RtcDrvInstall (VOID)
{if (_G_iRtcDrvNum > 0) {return  (ERROR_NONE);}_G_iRtcDrvNum = iosDrvInstall(__rtcOpen, (FUNCPTR)LW_NULL, __rtcOpen,__rtcClose,LW_NULL,LW_NULL,__rtcIoctl);DRIVER_LICENSE(_G_iRtcDrvNum,     "GPL->Ver 2.0");DRIVER_AUTHOR(_G_iRtcDrvNum,      "Han.hui");DRIVER_DESCRIPTION(_G_iRtcDrvNum, "hardware rtc.");return  ((_G_iRtcDrvNum > 0) ? (ERROR_NONE) : (PX_ERROR));
}

2.2.2创建设备

1. ISL1208 RTC驱动程序

ISL1208驱动程序主要包括RTC初始化、时间设置、时间获取。如程序清单 2.2所示。

程序清单 2.2 ISL1208 RTC驱动程序集

static  LW_RTC_FUNCS     _G_isl1208RtcFuncs = {isl1208RtcInit,isl1208RtcSetTime,isl1208RtcGetTime,LW_NULL
};

1)isl1208RtcInit——RTC初始化

由于ISL1208 RTC通过I2C总线进行数据传输,所以需要在RTC初始化函数中调用API_I2cDeviceCreate内核函数创建RTC设备,将其作为从设备挂接在I2C总线上(前提是已实现验证平台上的I2C驱动并创建I2C适配器),这样,RTC进行数据传输时即可根据适配器名查找到对应的I2C适配器,并调用I2C适配器的操作函数。具体实现如程序清单 2.3所示。

程序清单 2.3 RTC初始化

static VOID  isl1208RtcInit (VOID)
{__PISL1208_RTC_CONTROLER  pRtcControler = &_G_isl1208RtcControlers[0];if (!pRtcControler->RTCC_pI2cDevice) {pRtcControler->RTCC_pI2cDevice = API_I2cDeviceCreate(pRtcControler->RTCC_pcI2cBusName,"/dev/rtc",0x6F,      /* ISL 芯片的设备地址          */0);if (pRtcControler->RTCC_pI2cDevice) {isl1208RtcHwInit();}}
}

2)isl1208RtcSetTime——RTC时间设置

RTC的时间设置过程:

  1. 将待设置时间进行转码并填入数据buf;

  2. 封装I2C总线传输控制消息,消息中包含RTC从设备地址、消息长度、传输控制标志(读/写)、数据buf;

  3. 发送I2C控制消息,控制RTC设备写使能;

  4. 发送I2C控制消息,填充RTC对应时间设置寄存器;

  5. 发送I2C控制消息,控制RTC设备写失能。

RTC时间设置过程如程序清单 2.4所示,其中isl1208ReadReg和isl1208SetRegs即为封装I2C总线传输控制消息并调用总线传输控制函数进行消息传输的过程,这里不做过多描述。

程序清单 2.4 RTC时间设置

static INT  isl1208RtcSetTime (PLW_RTC_FUNCS  pRtcFuncs, time_t  *pTimeNow)
{__PISL1208_RTC_CONTROLER  pRtcControler = &_G_isl1208RtcControlers[0];struct tm                 tmNow;UINT8                     aucBuffer[ISL1208_RTC_SECTION_LEN] = { 0, };UINT8                     ucCtlDat[1], ucRegDat[1];gmtime_r(pTimeNow, &tmNow);                                         /*  转换成 tm 时间格式          *//** 将待设置时间进行转码并填入数据buf*/aucBuffer[ISL1208_REG_YR] = rtcBinToBcd(tmNow.tm_year % 100);aucBuffer[ISL1208_REG_MO] = rtcBinToBcd(tmNow.tm_mon + 1);aucBuffer[ISL1208_REG_DT] = rtcBinToBcd(tmNow.tm_mday);aucBuffer[ISL1208_REG_DW] = rtcBinToBcd(tmNow.tm_wday & 7);aucBuffer[ISL1208_REG_HR] = rtcBinToBcd(tmNow.tm_hour);aucBuffer[ISL1208_REG_MN] = rtcBinToBcd(tmNow.tm_min);aucBuffer[ISL1208_REG_SC] = rtcBinToBcd(tmNow.tm_sec);/** 读取 RTC 的状态值并设置 WRTC, 控制 RTC 写使能*/isl1208ReadReg(pRtcControler->RTCC_pI2cDevice, ISL1208_REG_SR, ucRegDat, 1);ucCtlDat[0] = ucRegDat[0] | ISL1208_REG_SR_WRTC;isl1208SetRegs(pRtcControler->RTCC_pI2cDevice, ISL1208_REG_SR, ucCtlDat, 1);/** 写入待设置时间*/isl1208SetRegs(pRtcControler->RTCC_pI2cDevice, 0, aucBuffer, ISL1208_RTC_SECTION_LEN);/** 设置 WRTC, 控制 RTC 写失能*/ucCtlDat[0] = ucRegDat[0] & ~ISL1208_REG_SR_WRTC;isl1208SetRegs(pRtcControler->RTCC_pI2cDevice, ISL1208_REG_SR, ucCtlDat, 1);return  (ERROR_NONE);
}

3)isl1208RtcGetTime——RTC时间获取

RTC时间获取就是调用isl1208ReadReg函数,读取RTC设备存放时间信息的寄存器,然后将获取的时间进行转码,获得当前年、月、日、时、分、秒等信息,填入相应结构体。具体实现过程如程序清单 2.5所示。

程序清单 2.5 RTC时间获取

static INT  isl1208RtcGetTime (PLW_RTC_FUNCS  pRtcFuncs, time_t  *pTimeNow)
{__PISL1208_RTC_CONTROLER  pRtcControler = &_G_isl1208RtcControlers[0];struct tm                 tmNow;UINT8                     ucValue;UINT8                     aucBuffer[ISL1208_RTC_SECTION_LEN] = { 0, };/** 读取RTC设备存放时间信息的寄存器*/isl1208ReadReg(pRtcControler->RTCC_pI2cDevice, 0, aucBuffer, ISL1208_RTC_SECTION_LEN);/** 对获取的时间信息进行转码并填入相应的结构体*/tmNow.tm_sec  = rtcBcdToBin(aucBuffer[ISL1208_REG_SC]);tmNow.tm_min  = rtcBcdToBin(aucBuffer[ISL1208_REG_MN]);ucValue = aucBuffer[ISL1208_REG_HR];if (ucValue & ISL1208_REG_HR_MIL) {                                 /*  24h 格式                    */tmNow.tm_hour = rtcBcdToBin(ucValue & 0x3F);} else {                                                            /*  12h 格式                    */if (ucValue & ISL1208_REG_HR_PM) {                              /*  PM 标志设置                 */tmNow.tm_hour = 12 + rtcBcdToBin(ucValue & 0x1F);} else {tmNow.tm_hour = rtcBcdToBin(ucValue & 0x1F);}}tmNow.tm_wday  = rtcBcdToBin(aucBuffer[ISL1208_REG_DW]);tmNow.tm_mday  = rtcBcdToBin(aucBuffer[ISL1208_REG_DT]);tmNow.tm_mon   = rtcBcdToBin(aucBuffer[ISL1208_REG_MO]) - 1;tmNow.tm_year  = rtcBcdToBin(aucBuffer[ISL1208_REG_YR]) + 100;tmNow.tm_yday  = 0;tmNow.tm_isdst = 0;if (pTimeNow) {*pTimeNow = timegm(&tmNow);}return  (ERROR_NONE);
}

2. 创建RTC设备

调用API_RtcDevCreate创建RTC设备,设备结构体prtcdev中保存的操作函数集就是函数入参——ISL1208 RTC驱动程序_G_isl1208RtcFuncs。然后再调用API_IosDevAddEx内核函数,向系统中添加一个设备,该函数中主要就是填充设备结构体中的另一个成员——设备头,设备头中保存着设备名称、设备驱动索引号、设备类型、打开次数等。最后,将该设备头添加入设备头管理链表进行管理。RTC设备的创建过程如程序清单 2.6所示。

程序清单 2.6 RTC设备创建

LW_API  INT  API_RtcDevCreate (PLW_RTC_FUNCS    prtcfuncs)
{PLW_RTC_DEV     prtcdev;if (prtcfuncs == LW_NULL) {_ErrorHandle(EINVAL);return  (PX_ERROR);}if (_G_iRtcDrvNum <= 0) {_DebugHandle(__ERRORMESSAGE_LEVEL, "no driver.\r\n");_ErrorHandle(ERROR_IO_NO_DRIVER);return  (PX_ERROR);}/** 为设备结构体分配空间*/prtcdev = (PLW_RTC_DEV)__SHEAP_ALLOC(sizeof(LW_RTC_DEV));if (prtcdev == LW_NULL) {_DebugHandle(__ERRORMESSAGE_LEVEL, "system low memory.\r\n");_ErrorHandle(ERROR_SYSTEM_LOW_MEMORY);return  (PX_ERROR);}lib_bzero(prtcdev, sizeof(LW_RTC_DEV));/** 保存RTC设备驱动程序*/prtcdev->RTCDEV_prtcfuncs = prtcfuncs;/** 向系统中添加一个设备,将设备头链入链表进行管理*/if (iosDevAddEx(&prtcdev->RTCDEV_devhdr, __LW_RTC_DEV_NAME, _G_iRtcDrvNum, DT_CHR) != ERROR_NONE) {__SHEAP_FREE((PVOID)prtcdev);return  (PX_ERROR);}/** 初始化硬件*/if (prtcfuncs->RTC_pfuncInit) {prtcfuncs->RTC_pfuncInit();}return  (ERROR_NONE);
}

3、RTC时间同步

RTC设备创建完成并安装完设备驱动程序后,即可调用API_RtcToSys内核函数进行时间同步。该函数调用API_RtcGet函数,打开已安装的RTC设备,通过ioctl命令控制,获取当前RTC时间,最终调用lib_clock_settime,将获取的时间设置为系统时间。具体实现过程如程序清单 3.1所示。

程序清单 3.1系统时间同步

LW_API  INT  API_RtcToSys (VOID)
{struct timespec   tv;/** 获取当前RTC时间*/if (API_RtcGet(&tv.tv_sec) < 0) {return  (PX_ERROR);}tv.tv_nsec = 0;/** 将获取的时间设置为系统时间*/return  (lib_clock_settime(CLOCK_REALTIME, &tv));
}

转载于:https://blog.51cto.com/11178899/1944944

SylixOS中RTC设备驱动相关推荐

  1. RT-Thread GD32F4xx RTC设备驱动

    目录 1.RTC 2.软件模拟RTC 2.1 配置软件模拟RTC 2.2 soft_rtc.c 3.GD32F4xx RTC驱动 3.1 创建RTC设备 3.2 实现RTC设备的操作方法 3.3 注册 ...

  2. 全志平台boot框架中增加设备驱动过程分析

    全志平台boot框架中增加设备驱动过程分析 在boot启动阶段,大家都知道他的主要目的就是引导uboot,uboot在引导内核,从而让整个系统运作起来.全志的boot阶段,对应平板这一块,它会驱动LC ...

  3. python framebuffer_Linux中LCD设备驱动

    1.framebuffer 帧缓冲 帧缓冲(framebuffer)是Linux 系统为显示设备提供的一个接口,它将显示缓冲区抽象,屏蔽图像硬件的底层差异,允许上层应用程序在图形模式下直接对显示缓冲区 ...

  4. 驱动开发中platform设备驱动架构详解

    1.什么是platform总线 从Linux2.6开始Linux加入了一套驱动管理和注册机制-platform总线驱动模型.platform总线是一条虚拟总线(只有一条),这类总线没有对应的硬件结构. ...

  5. 一文彻底搞清Linux中块设备驱动的深层次原理和编写方法

    [摘要]本文主要讲述了在Linux环境下的块设备驱动的常见数据结构和内核接口,并以一个实际例子讲述了块设备驱动的编写方法. 1.前提知识 一个块驱动提供对块存储设备(比如 SD 卡.EMMC.NAND ...

  6. linux下的rtc设备驱动,linux下测试RTC驱动相关的命令date和hwclock常见用法讲解

    之前对Linux下面时间相关的内容,一无所知,第一次见到hwclock,不知为何物,也没找到解释清楚的帖子.故此整理一下,简单介绍Linux下验证rtc驱动是否工作正常,相关的的命令:date和hwc ...

  7. 【sylixos】i2c设备驱动创建和使用

    前提是需要已实现过i2c总线驱动 步骤 步骤分为几步: 创建设备 API_I2cAdapterCreate 传输消息 API_I2cDeviceTransfer 发送消息 API_I2cDeviceM ...

  8. linux中FT4232H设备驱动添加,USB转4串口芯片FT4232HL,FT4232HQ

    本帖最后由 eehome 于 2013-1-5 10:09 编辑 联系人:黄鑫城 电话:15817431194   0755-82078692 QQ:759728988    mail:Nick@cy ...

  9. SylixOS中APIC HPET定时器字符驱动实现

    1.简介 1.1 APIC介绍 "APIC"是Advanced Programmable Interrupt Controller的缩写,即高级可编程中断控制器.引入APIC机制是 ...

  10. Linux设备驱动的分层设计思想

    1.1 设备驱动核心层和例化 在面向对象的程序设计中,可以为某一类相似的事物定义一个基类,而具体的事物可以继承这个基类中的函数.如果对于继承的这个事物而言,其某函数的实 现与基类一致,那它就可以直接继 ...

最新文章

  1. OSPF的RID和DR/BDR的选举
  2. zblog文件大小超出,上传成功但插入不了
  3. missforest_missforest最佳丢失数据插补算法
  4. 新功能:阿里云负载均衡SLB支持HTTP访问强制跳转HTTPS
  5. java线程池 synchronized_java多线程学习(二) 之 synchronized
  6. BZOJ.1013.[JSOI2008]球形空间产生器(高斯消元)
  7. img 居中_解决img标签下方出现的小空隙
  8. java入门申请,《java入门如此简单》——基础知识1
  9. mysql5.5.48安装教程_Linux虚拟机下MySQL-server-5.5.48-1安装教程
  10. Button的单击变色+button上面图片下边文字+圆角
  11. Hadoop集群搭建(六):hadoop配置namenode服务
  12. 为什么手机网速太慢_为什么手机连上WiFi网速很慢
  13. Ubuntu无法解析域名
  14. Java中的魔法值介绍及解决办法
  15. 数据可视化之旅:常用图表对比
  16. 基于java的五子棋游戏的设计_基于Java的五子棋游戏的设计
  17. 4k笔记本刺眼睛_2020戴尔笔记本怎么选?哪个系列好?附5款高销量戴尔笔记本电脑型号推荐!【超高性价比】...
  18. echarts的基本使用及其插件下载
  19. harrynull过关之路(11-20)
  20. SATA硬盘和IDE硬盘区别及优劣比较

热门文章

  1. Atitit.数据采集器 dataspider
  2. atitit. orm mapping cfg 映射配置(3)-------hbnt one2maney cfg
  3. paip.提升效率---filter map reduce 的java 函数式编程实现
  4. paip.提升性能---并行多核编程哈的数据结构list,set,map
  5. paip.语义分析--分词--常见的单音节字词 2_deDuli 单字词 774个
  6. paip..提升安全性----增加自毁功能
  7. 解读畅捷通微服务治理能力提升之路
  8. 【粉丝福利】Logo评选投票,礼品赠送!
  9. 【优化算法】气味代理优化算法(SAO)【含Matlab源码 1131期】
  10. 【路径规划】基于matlab无线充电车辆路径和速度预测【含Matlab源码 1473期】