栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

i2c外置RTC开发流程记录

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

i2c外置RTC开发流程记录

前置条件

T40 + sd2010 外置rtc

首先要确认硬件是否正常链接,设备地址是多少,可以借助i2c-tools

 注意:要使用i2c-tools  内核需要打开 CONFIG_I2C_CHARDEV (用户空间支持使用i2c总线),/dev/下有i2c-*说明配置已打开

i2c-tools

这个是专门用来调试i2c的

编译移植:

下载地址:
Index of /pub/software/utils/i2c-tools/

这里用的是i2c-tools-3.1.1

解压之后进入目录修改Makefile(加上静态编译 和 安装路径)

make CC=mips-linux-uclibc-gnu-gcc; make install

编译成功后生成的 _install/sbin/下就是生成的工具

使用方法:

i2cdetect:用于扫描 i2c 总线上的设备,并显示地址 i2cset:向i2c设备某个寄存器写入值 i2cget:读取i2c设备某个寄存器的值 i2cdump:读取某个i2c设备所有寄存器的值 i2ctransfer:一次性读写多个字节

 可以看到从机的地址为0x32(i2c总线号问硬件工程师即可)

如果扫描不到,可能是管教复用没打开 gpio 复用i2c

不同厂商的复用方法可能不一样,具体要咨询一下厂商。

T40的复用方法

 查原理图确认RTC SDA/SCK 对应的gpio为 PB20  PB21,总线是3.

内核目录  arch/mips/boot/dts/ingenic

这里不知道是怎么个规则, 0、1、2轮流试一下。

读写rtc

查询规格书可知寄存器列表

 方法1 用户空间直接操作 i2c设备:

前面已知总线号3,地址0x32

#include 
#include 
#include 
#include 
#include 
#include 

#include 
#include 
#include 
#include 

typedef struct _RJ_TIME_
{
    unsigned char       sec;        ///< 秒
    unsigned char       min;        ///< 分
    unsigned char       hour;       ///< 时

    unsigned char       wday;       ///< 星期几
    unsigned char       mday;       ///< 某日
    unsigned char       mon;        ///< 某月

    unsigned short      year;       ///< 某年

    int         msec;       ///< 毫秒
}_RJ_TIME_;

static char nChipAddress = (char)0x32;

int readEx(int m_nFd, unsigned char p_Address, char p_RegNo, char* p_Value, int p_valueLen)
{
	if (ioctl(m_nFd, I2C_SLAVE_FORCE, p_Address))
	{
		printf("readEx wrong slave address!n");
		return -1;
	}

	if (write(m_nFd, &p_RegNo, 1) < 0)
	{
		printf("write i2c error! n");
		return -1;
	}


	if (read(m_nFd, p_Value, p_valueLen) < 0)
	{
		printf("read i2c error! n");
		return -1;
	}

	return 0;
}

int rtc_get_time(_RJ_TIME_ *time)
{
	int ret;
	unsigned char nValue[7]={0};
	
	int m_nFd = open("/dev/i2c-3", O_RDWR);
	if (m_nFd <= 0)
	{
		printf("error open i2c Device failed!n");
		return -1;
	}
	
	ret = readEx(m_nFd, nChipAddress, 0, (char*)nValue,sizeof(nValue));
	if (0 != ret)
	{
		close(m_nFd);
		return ret;
	}
		
	//printf("%x,%x,%x,%x,%x,%x,%xn",nValue[0],nValue[1],nValue[2],nValue[3],nValue[4],nValue[5],nValue[6]);
	
	time->sec	=	(nValue[0]>>4) * 10 + (nValue[0]&0x0f) ;
	time->min	=	(nValue[1]>>4) * 10 + (nValue[1]&0x0f) ;
	nValue[2] &= 0x7f;
	time->hour	=	(nValue[2]>>4) * 10 + (nValue[2]&0x0f) ;
	time->mday	=	(nValue[4]>>4) * 10 + (nValue[4]&0x0f) ;
	time->mon	=	(nValue[5]>>4) * 10 + (nValue[5]&0x0f);
	time->year	=	(nValue[6]>>4) * 10 + (nValue[6]&0x0f);
	time->wday	=	(nValue[3]>>4) * 10 + (nValue[3]&0x0f) ;	
	

	
	
	close(m_nFd);
	
	return 0;
}

int rtc_write(int m_nFd, unsigned char p_Address, char p_RegNo, char p_Value)
{
	if (ioctl(m_nFd, I2C_SLAVE_FORCE, p_Address))
	{
		printf("write wrong slave address(0x%x)!n",p_Address);
		return -1;
	}

	char mbuf[2];
	mbuf[0] = p_RegNo;
	mbuf[1] = p_Value;
	if (write(m_nFd, mbuf, 2) < 0)
	{
		printf("write i2c errorn");
		return -1;
	}
	return 0;
}

int writeEx(int m_nFd, unsigned char p_Address, char p_RegNo, char* p_Value, int p_valueLen)
{
	if (ioctl(m_nFd, I2C_SLAVE_FORCE, p_Address))
	{
		printf("writeEx wrong slave address!n");
		return -1;
	}

	unsigned char* mbuf = (unsigned char*)calloc(p_valueLen + 1, sizeof(unsigned char));
	if ( mbuf == NULL ) 
	{
		printf("Error: read buffer allocationn");
		return -1;
	}

	mbuf[0] = p_RegNo;
	for ( int i = 0; i < p_valueLen; i++ ) 
	{
		mbuf[i + 1] = (unsigned char)p_Value[i];
	}
	if (write(m_nFd, mbuf, p_valueLen + 1) < 0)
	{
		printf("write i2c error !n");
		free(mbuf);
		return -1;
	}
	free(mbuf);
	
	return 0;
}

int rtc_set_time(_RJ_TIME_ *p_tmTime)
{
	int ret;
	unsigned char nValue[7]={0};
	
	int m_nFd = open("/dev/i2c-3", O_RDWR);
	if (m_nFd <= 0)
	{
		printf("error open i2c Device failed!n");
		return -1;
	}
	
	unsigned char nSeconds = p_tmTime->sec;
	unsigned char nMinutes = p_tmTime->min;
	unsigned char nHours = p_tmTime->hour;
	unsigned char nDays = p_tmTime->mday;
	unsigned char nMonths = p_tmTime->mon;
	unsigned char nYears = p_tmTime->year;
	unsigned char nWeekDay = p_tmTime->wday;
	
	nValue[0] = ((nSeconds/10)<<4)|(nSeconds%10);
	nValue[1] = ((nMinutes/10)<<4)|(nMinutes%10);
	nValue[2] = ((nHours/10)<<4)|(nHours%10);
	nValue[2] |= 0x80;//24 小时制
	nValue[3] = ((nWeekDay/10)<<4)|(nWeekDay%10);
	nValue[4] = ((nDays/10)<<4)|(nDays%10);
	nValue[5] = ((nMonths/10)<<4)|(nMonths%10);
	nValue[6] = ((nYears/10)<<4)|(nYears%10);
	
	rtc_write(m_nFd, nChipAddress, 0x10,0x80);
	rtc_write(m_nFd, nChipAddress, 0x0f,0x84);
	
	printf("nYears[%d]%x, nMonths[%d]%x, nDays[%d]%x, nWeekDay[%d]%x, nHours[%d]%x, nMinutes[%d]%x, nSeconds[%d]%xn",
	nYears, nValue[6],
	nMonths, nValue[5],
	nDays, nValue[4],
	nWeekDay, nValue[3],
	nHours, nValue[2],
	nMinutes, nValue[1],
	nSeconds, nValue[0]);
	
	writeEx(m_nFd, nChipAddress, 0, (char*)nValue,sizeof(nValue));
	
	rtc_write(m_nFd, nChipAddress, 0x0f,0x0);
	rtc_write(m_nFd, nChipAddress, 0x10,0x0);
	
	close(m_nFd);
	
	return 0;
}

void case_get_rtc()
{
	_RJ_TIME_ rtc_time;

	rtc_get_time(&rtc_time);
	
	printf("%d-%02d-%02d %d:%d:%dn",rtc_time.year + 2000,rtc_time.mon,rtc_time.mday,
		rtc_time.hour,rtc_time.min,rtc_time.sec);
}

void case_set_rtc()
{
	time_t timep;
	struct tm *p;
	
	time(&timep);
	p=gmtime(&timep);
	
	printf("%d",p->tm_year + 1900);
	printf("-%02d",1+p->tm_mon);
	printf("-%02d ",p->tm_mday);
	printf("%02d-",p->tm_hour);
	printf("%02d-",p->tm_min); 	
	printf("%02d ",p->tm_sec); 
	printf("星期 %dn",p->tm_wday); 
	
	_RJ_TIME_ rtc_time;
	
	rtc_time.year = p->tm_year -100; // + 1900 -2000
	if (p->tm_year +1900 < 2000)
		rtc_time.year = 0x0;
	rtc_time.mon = p->tm_mon + 1;
	rtc_time.mday = p->tm_mday;
	rtc_time.hour = p->tm_hour;
	rtc_time.min = p->tm_min;
	rtc_time.sec = p->tm_sec;
	rtc_time.wday = p->tm_wday;
	
	rtc_set_time(&rtc_time);

}

int main(int argc, char *argv[])
{
	
	int result;
	
	opterr = 0;//使getopt不行stderr输出错误信息
	
	while( (result = getopt(argc, argv, "rwh")) != -1 )
	{
		switch(result)
		{
			case 'r':
			//printf("[rtc] Get hw time.n");
			case_get_rtc();
			break;
			case 'w':
			printf("[rtc] Set hw time.n");
			case_set_rtc();
			break;
			case 'h':
			printf("[Usage: hwclock [-r|--show][-w|--systohc]n");
			printf("t-r	Show hardware clock timen");
			printf("t-w	Set hardware clock from system timen");
			case '?':
			printf("[rtc] Unknow cmd.n");
			break;
			default:
			printf("[rtc] error.n");
			break;
		}
	}
	
	return 0;
}

方法2 加载rtc驱动 后台通过hwclock 读写时间:

内核 drivers/rtc目录下有很多厂商已经实现好的驱动, 找一下有没有对应的型号,如果刚好没有,那么我们就自己写驱动。

如果对驱动完全一窍不通,先看下这位博主的系列文章

(一)初识Linux驱动_hanp_linux的博客-CSDN博客 (bing.com) 

驱动编译的时候如果有报错 undefine 大概率是内核对应的配置没有打开,此时虽然能生成ko,但是加载的时候是加载不上去的。

我自己遇到了rtc_device_register undefine 。原因是CONFIG_RTC_CLASS没有打开

这篇文章写得已经很详细了

 (2条消息) Linux驱动开发: Linux下RTC实时时钟驱动_DS小龙哥的博客-CSDN博客_rtc驱动

补充自己写得针对sd2010的rtc驱动

rtc相关操作接口遇到问题可以先尝试搜一下 rtc 厂商的官网,看有没有一些错误解释 或者demo

device端

rtc_device.c

#include "linux/module.h"
#include "linux/init.h"
#include 

 
//释放平台总线
static void pdev_release(struct device *dev)
{
	printk("rtc_pdev:the rtc_pdev is close!!!n");
}
 

struct platform_device  rtc_pdev= 
{
	.name = "sd2010rtc",  
	.id = -1,         
	.dev =            
	{
		.release = pdev_release,
	},
};
 
 

static int __init plat_dev_init(void)
{
	printk("rtc device initn");
	platform_device_register(&rtc_pdev);
	return 0;
}
 

static void __exit plat_dev_exit(void)
{
	platform_device_unregister(&rtc_pdev);
}
 
module_init(plat_dev_init);
module_exit(plat_dev_exit);
MODULE_LICENSE("GPL");

Makefile

CROSS_COMPILE ?= mips-linux-gnu-

ISVP_ENV_KERNEL_DIR = $(PWD)/../../../../kernel-4.4.94

KDIR := ${ISVP_ENV_KERNEL_DIR}
MODULE_NAME := rtc_device_sd2010

all: modules

.PHONY: modules clean

$(MODULE_NAME)-objs := rtc_device.o
obj-m := $(MODULE_NAME).o

modules:
	@$(MAKE) -C $(KDIR) M=$(shell pwd) $@
clean:
	@rm -rf *.o *~ .depend .*.cmd  *.mod.c .tmp_versions *.ko *.symvers modules.order
drver端 (设置接口未完成)
#include              
#include 
#include                  
#include 
#include 
#include 
#include           
#include                 
#include                
#include               
#include 
#include               
#include          
#include                
#include     
#include 
#include 


#define sd2010_sec_add			0x00		//秒数据地址
#define sd2010_min_add			0x01		//分数据地址
#define sd2010_hr_add			0x02		//时数据地址
#define sd2010_day_add			0x03		//星期数据地址
#define sd2010_date_add			0x04		//日数据地址
#define sd2010_month_add		0x05		//月数据地址
#define sd2010_year_add			0x06		//年数据地址

#define REG_CTRL_1      0x0F
#define REG_CTRL_2      0x10
#define REG_CTRL_3      0x11

#define RTC_I2C_NUM     3
#define RTC_ADDR        0x32

#define I2C_WRITE 0
#define I2C_READ  1

static struct i2c_board_info sd2010_info = {
    I2C_BOARD_INFO("sd2010", RTC_ADDR),
};

static struct i2c_client *sd2010_client;


static int sd2010_rtc_gettime(struct device *dev, struct rtc_time *rtc_tm)
{
	printk("从RTC底层获取时间成功!n");

	//struct i2c_client *client = to_i2c_client(dev);

    unsigned char addr = sd2010_sec_add;
    unsigned char nValue[7] = {0};

    struct i2c_msg msgs[1] = {
		[0] = {
                .addr  = sd2010_client->addr,
                .flags = I2C_READ,
                .len = 7,
                .buf = nValue,
        },   
    };


	
    if ((i2c_transfer(sd2010_client->adapter, &msgs[0], 1)) != 1) {
        dev_err(&sd2010_client->dev, "%s: read errorn", __func__);
        return -EIO;
    }

	printk("%x,%x,%x,%x,%x,%x,%xn",nValue[0],nValue[1],nValue[2],nValue[3],nValue[4],nValue[5],nValue[6]);
	
	rtc_tm->tm_year=2018-1900;   //年 
	rtc_tm->tm_mon=8-1;         //月 
	rtc_tm->tm_mday=18;         //日 
	rtc_tm->tm_hour=18;		   //时 
	rtc_tm->tm_min=18;		//分 
	rtc_tm->tm_sec=18;//秒
	
	
	rtc_tm->tm_sec	=	(nValue[0]>>4) * 10 + (nValue[0]&0x0f) ;
	rtc_tm->tm_min	=	(nValue[1]>>4) * 10 + (nValue[1]&0x0f) ;
	nValue[2] &= 0x7f;
	rtc_tm->tm_hour	=	(nValue[2]>>4) * 10 + (nValue[2]&0x0f) ;
	rtc_tm->tm_mday	=	(nValue[4]>>4) * 10 + (nValue[4]&0x0f) ;
	rtc_tm->tm_mon	=	(nValue[5]>>4) * 10 + (nValue[5]&0x0f);
	rtc_tm->tm_year	=	(nValue[6]>>4) * 10 + (nValue[6]&0x0f) + 100;
	
	return 0;
}
 
static int sd2010_rtc_settime(struct device *dev, struct rtc_time *tm)
{
	printk("RTC收到的时间为:%d-%d-%d %d-%d-%dn",1900 + tm->tm_year, tm->tm_mon, tm->tm_mday,
		 tm->tm_hour, tm->tm_min, tm->tm_sec);

	//struct i2c_client *client = to_i2c_client(dev);
  
	//printk("-------------1n");
	
	unsigned char bufdata[8] = {0};



	unsigned char nSeconds = 10;
	unsigned char nMinutes = 10;
	unsigned char nHours = 10;
	unsigned char nDays = 10;
	unsigned char nMonths = 10;
	unsigned char nYears = 10;
	
	bufdata[0] = sd2010_sec_add;
	bufdata[1] = ((nSeconds/10)<<4)|(nSeconds%10);
	bufdata[2] = ((nMinutes/10)<<4)|(nMinutes%10);
	bufdata[3] = ((nHours/10)<<4)|(nHours%10);
	bufdata[5] |= 0x80;//24 小时制
	//nValue[4] = ((nWeekDay/10)<<4)|(nWeekDay%10);
	bufdata[5] = ((nDays/10)<<4)|(nDays%10);
	bufdata[6] = ((nMonths/10)<<4)|(nMonths%10);
	bufdata[7] = ((nYears/10)<<4)|(nYears%10);
	

	
	//printk("-------------2n");
	
	unsigned char bufoff1[2] = {0};
	unsigned char bufoff2[2] = {0};
	
	bufoff1[0] = REG_CTRL_1;
	bufoff1[1] = 0x0;
	bufoff2[0] = REG_CTRL_2;
	bufoff2[1] = 0x0;
	
	
	
	printk("-------------3n");
	
	return 0;	
}
 
static int sd2010_rtc_getalarm(struct device *dev, struct rtc_wkalrm *alrm)
{
	alrm->enabled=0;  //默认闹钟处于关闭状态
    alrm->time.tm_year=2018-1900;  //年 
	alrm->time.tm_mon=8-1;    //月 
	alrm->time.tm_mday=18;  //日 
	alrm->time.tm_hour=18;	//时 
	alrm->time.tm_min=18;	//分 
	alrm->time.tm_sec=18;	//秒
	printk("从RTC底层获取闹钟时间成功!n");

	return 0;	
}
 
static int sd2010_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm)
{
	printk("RTC闹钟设置成功n");
	return 0;	
}
	
static int sd2010_rtc_proc(struct device *dev, struct seq_file *seq)
{
	printk("proc调用成功n");
	return 0;	
}
 
static int sd2010_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
{
	printk("alarm_irq_enable调用成功n");
	return 0;	
}
 
static int sd2010_rtc_ioctl(struct device *dev, unsigned int cmd,unsigned long arg)
{
	printk("ioctl调用成功n");
	return 0;
}
 
 

static const struct rtc_class_ops sd2010_rtcops = {
	.read_time	= sd2010_rtc_gettime,
	.set_time	= sd2010_rtc_settime,
	.read_alarm	= sd2010_rtc_getalarm,
	.set_alarm	= sd2010_rtc_setalarm,
	.proc		= sd2010_rtc_proc,
	.alarm_irq_enable = sd2010_rtc_alarm_irq_enable,
	.ioctl		= sd2010_rtc_ioctl,
};
 
struct rtc_device *rtc;


static int drv_probe(struct platform_device *pdev)
{	

	struct i2c_adapter *i2c_adap;

	i2c_adap = i2c_get_adapter(RTC_I2C_NUM);
	sd2010_client = i2c_new_device(i2c_adap, &sd2010_info);
    i2c_put_adapter(i2c_adap);
   	
	unsigned char buf[2];
    struct i2c_msg msg = {
        RTC_ADDR, I2C_WRITE, 2, buf,
    };

	buf[0] = REG_CTRL_1;
	buf[1] = 0;

#if 0
    if ((i2c_transfer(sd2010_client->adapter, &msg, 1)) != 1) {
        dev_err(&sd2010_client->dev, "%s: write errorn", __func__);
		printk("i2c_transfer faild!!!n");
        return -EIO;
    }
	
#endif

	rtc = rtc_device_register("sd2010rtc",&pdev->dev, &sd2010_rtcops,THIS_MODULE);
	if(rtc==NULL)
		printk("RTC驱动注册失败n");
	else
  		printk("RTC驱动注册成功n");

	return 0;
}
 
static int drv_remove(struct platform_device *dev)
{
	rtc_device_unregister(rtc);
	printk("RTC驱动卸载成功n");
	return 0;
}
 
 

struct platform_driver  drv= 
{
	.probe = drv_probe,    
	.remove = drv_remove,  
	.driver = 
	{
		.name = "sd2010rtc",    
	},
};
 

static int __init plat_drv_init(void)
{
	printk("rtc_drver init !!!n");
	platform_driver_register(&drv);	
	return 0;
}
 

static void __exit plat_drv_exit(void)
{
	platform_driver_unregister(&drv);
}
 
module_init(plat_drv_init);  
module_exit(plat_drv_exit);  
MODULE_AUTHOR("SHJ");
MODULE_LICENSE("GPL");

Makefile

CROSS_COMPILE ?= mips-linux-gnu-

ISVP_ENV_KERNEL_DIR = $(PWD)/../../../../kernel-4.4.94

KDIR := ${ISVP_ENV_KERNEL_DIR}
MODULE_NAME := rtc_drver_sd2010

all: modules

.PHONY: modules clean

$(MODULE_NAME)-objs := rtc_drver.o
obj-m := $(MODULE_NAME).o

modules:
	@$(MAKE) -C $(KDIR) M=$(shell pwd) $@
clean:
	@rm -rf *.o *~ .depend .*.cmd  *.mod.c .tmp_versions *.ko *.symvers modules.order

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/925628.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号