linux pcf8563开发文档,linux下的i2c与时钟芯片pcf8563通信

2012/7/19

linux下的i2c与时钟芯片pcf8563通信

by: 韩大卫 @吉林师范大学

1,本程序增加了对星期寄存器(wday)的写操作。

2, 本程序将i2c-test 改为rtdate 命令,并将rtdate作为最终命令发布。

3,在linux下,成功地在用户层操作了时钟芯片pcf8563的寄存器。

4,本程序考虑到了不同的系统中的rtc时钟芯片挂在不同的i2c bus的位置。、

比如:如果挂在 /dev/i2c-0 下,那么就只能打开/dev/i2c-0 进行操作,否则的话read/write 均会失败,

那么这样就需要我们手动的传入参数,这需在程序中加入相应的判断条件。同时为了最大程度上做到便捷,

如果不使用路径参数的话,那么程序中给出了默认路径/dev/i2c-1, 我们这样就可以直接

#rtdate -s 2012.7.19-19.36.00 修改硬件时间。

#rtdate -s 19.36.00 修改硬件时间

#rtdate -r 显示硬件时间

#rtdate -l 显示系统时间

需要手动加路径的话:

#rtdate-d /dev/i2c-10 -s 18:20:30

这样可以做到在不同的嵌入式系统中,不修改代码的情况下操作时钟芯片读写硬件时间,强化了软件的健壮性。

我们嵌入式系统中的cpu是Cavium Networks OCTEON CN5220,基于64bit的mips处理器。

********************************************* *******************************

转载请务必表明出处。 韩大卫@吉林师范大学@08信息。

********************************************** *******************************

main.c

**************** ******************************************

#include "i2c.h"

#define TIMEOUT3

#define RETRY3

static int fd;

static inline int is_leap_year(unsigned int year){

return (!(year % 4) && (year % 100)) || !(year % 400);

}

int rtc_month_days(unsigned int month, unsigned int year){

return rtc_days_in_month[month - 1] + (is_leap_year(year) && month == 1);

}

/*

*test year.mon.mday.wday.hour.min.sec

*/

int rtc_valid_tm(struct rtc_time *tm)

{

if(tm->tm_year < 1970

|| tm->tm_year >2069

|| ((unsigned)tm->tm_mon) > 12

|| tm->tm_mday < 0

|| tm->tm_mday > rtc_month_days(tm->tm_mon, tm->tm_year)

|| ((unsigned)tm->tm_hour) >= 24

|| ((unsigned)tm->tm_min) >= 60

|| ((unsigned)tm->tm_sec) >= 60)

return -EINVAL;

return 0;

}

/*

*test hour:min:sec

*/

int rtc_valid_half_tm(struct rtc_time *tm)

{

if((unsigned)tm->tm_hour >= 24 ||

(unsigned)tm->tm_min >= 60 ||

(unsigned)tm->tm_sec >= 60)

return -EINVAL;

return 0;

}

int i_open(unsigned char* dev, unsigned int timeout, unsigned int retry){

return i2c_open(dev,timeout,retry);

}

int read_data(u16 addr, u8 offset, u8 *val){

int ret;

ret = i2c_read_data(addr,offset,val);

if(ret < 0){

printf("%s error!\n",__FUNCTION__);

exit(-1);

}

return 0;

}

int write_data(u16 addr, u8 offset, u8 val){

int ret;

ret = i2c_write_data(addr,offset,val);

if(ret < 0){

printf("%s error!\n",__FUNCTION__);

exit(-1);

}

return 0;

}

int get_week_data(int y,int m,int d){

unsigned int w, c;

if (m <= 2){

m |= 4;

y--;

}

c =y/100;

c &=0x03;

y %=100;

w =((c | (c << 2)) + (y + (y >> 2)) + (13 * m + 8)/ 5 + d) % 7;

return w;

}

/*

*-s YYYY.MM.DD-hh.mm.ss

*/

int time_year_begin(char* ptr,struct rtc_time* tm){

if( !(*(ptr+4) == '.' || *(ptr+4) == ':' )){

printf("TIME Format error !\n");

exit(-1);

}

u8 offset;

u16 addr = 0x51;

int i= 0;

int set_hour_flags=0;

unsigned char buf[8]={0};

int data[10]={0};

/* get year */

data[i++] = atoi(ptr);

while( *ptr ){

if( *ptr == '.' || *ptr == ':'){

ptr++;

/* get mon and mday */

data[i++] = atoi(ptr);

}

ptr++;

if( *ptr == '-'){

set_hour_flags = 1;

ptr++;

/* get hour */

data[i++] = atoi(ptr);

while( *ptr ){

if( *ptr == '.' || *ptr == ':' ){

ptr++;

/* get min and sec */

data[i++] = atoi(ptr);

}

else ptr++;

}

break;

}

}

tm->tm_year = data[0];

tm->tm_mon = data[1];

tm->tm_mday = data[2];

tm->tm_hour = data[3];

tm->tm_min = data[4];

tm->tm_sec = data[5];

tm->tm_wday=get_week_data(tm->tm_year,tm->tm_mon,tm->tm_mday);

if(rtc_valid_tm(tm) < 0){

printf("date/time is not valid.set time error!\n");

exit(-1);

}

buf[PCF8563_REG_SC]=bin2bcd(tm->tm_sec);

buf[PCF8563_REG_MN]=bin2bcd(tm->tm_min);

buf[PCF8563_REG_HR] =bin2bcd(tm->tm_hour);

buf[PCF8563_REG_DM]=bin2bcd(tm->tm_mday);

buf[PCF8563_REG_DW]=tm->tm_wday & 0x07;

buf[PCF8563_REG_MO]=bin2bcd(tm->tm_mon);

buf[PCF8563_REG_YR]=bin2bcd(tm->tm_year % 100);

if ( tm->tm_year/2000 )

buf[PCF8563_REG_MO] |= 0x00;

else

buf[PCF8563_REG_MO] |= PCF8563_MO_C;

/* write year-wday or year-sec*/

for(offset = set_hour_flags? PCF8563_REG_SC : PCF8563_REG_DM; offset <= PCF8563_REG_YR ; offset++ ){

write_data(addr,offset,buf[offset]);

}

rtc_time_list();

return 0;

}

/*

*-s hh.mm.ss

*/

int time_hour_begin(char *ptr,struct rtc_time* tm){

if( !(*(ptr+2) == '.' || *(ptr+1) == '.' || *(ptr+2) == ':' || *(ptr+1) == ':') ){

printf("TIME Format error !\n");

exit(-1);

}

u8 offset;

u16 addr =0x51;

int i =0;

unsigned char buf[4]={0};

int data[10]={0};

/* get hour */

data[i++] = atoi(ptr);

while( *ptr ){

if( *ptr == '.' || *ptr == ':'){

ptr++;

/* get min and sec */

data[i++] = atoi(ptr);

}

else

ptr++;

}

tm->tm_hour = data[0];

tm->tm_min = data[1];

tm->tm_sec = data[2];

if(rtc_valid_half_tm(tm) < 0){

printf("date/time is not valid.set time error!\n");

exit(-1);

}

buf[PCF8563_REG_SC]=bin2bcd(tm->tm_sec);

buf[PCF8563_REG_MN]=bin2bcd(tm->tm_min);

buf[PCF8563_REG_HR] =bin2bcd(tm->tm_hour);

for(offset = PCF8563_REG_SC; offset <= PCF8563_REG_HR ; offset++ ){

write_data(addr,offset,buf[offset]);

}

rtc_time_list();

return 0;

}

int rtc_time_list(void){

u16 addr=0x51;

u8 offset=0x00;

u8 buf[13]={0};

int data[10]={0};

struct rtc_time *tm = (struct rtc_time*)malloc(sizeof(struct rtc_time));

read_data(addr, offset, buf);

tm->tm_sec=buf[PCF8563_REG_SC] & 0x7F;

tm->tm_min=buf[PCF8563_REG_MN] & 0x7F;

tm->tm_hour=buf[PCF8563_REG_HR] & 0x3F;// rtc hr 0-23

tm->tm_mday=buf[PCF8563_REG_DM] & 0x3F;

tm->tm_wday=buf[PCF8563_REG_DW] & 0x07;

tm->tm_mon=buf[PCF8563_REG_MO] & 0x1F;// rtc mn 1-12 -1 :tm_mon:[0-11]

tm->tm_year=buf[PCF8563_REG_YR];

if(buf[PCF8563_REG_MO] & PCF8563_MO_C)

tm->tm_year+=0x1900;//MO:8bit = 1:1900

else

tm->tm_year+=0x2000;//MO:8bit = 0:2000

printf("%4x:%02x:%02x ",

tm->tm_year, tm->tm_mon, tm->tm_mday);

switch(tm->tm_wday){

case 1 :

printf("Mon ");break;

case 2 :

printf("Tus ");break;

case 3 :

printf("Wed ");break;

case 4 :

printf("Thu ");break;

case 5 :

printf("Fir ");break;

case 6 :

printf("Sat ");break;

case 7 :

printf("Sun ");break;

}

printf("%02x:%02x:%02x\n",

tm->tm_hour, tm->tm_min, tm->tm_sec);

return 0;

}

int sys_time_list(){

struct tm* ptr;

time_t lt;

lt = time(NULL);

ptr = localtime(&lt);

printf("%4d:",ptr->tm_year + 1900);

printf("%02d:",ptr->tm_mon + 1);

printf("%02d ",ptr->tm_mday);

switch(ptr->tm_wday){

case 1 :

printf("Mon ");break;

case 2 :

printf("Tus ");break;

case 3 :

printf("Wed ");break;

case 4 :

printf("Thu ");break;

case 5 :

printf("Fir ");break;

case 6 :

printf("Sat ");break;

case 7 :

printf("Sun ");break;

}

printf("%02d:",ptr->tm_hour);

printf("%02d:",ptr->tm_min);

printf("%02d\n",ptr->tm_sec);

return 0;

}

int i2c_rtc_data(char* ptr){

struct rtc_time* tm=(struct rtc_time*)malloc(sizeof(struct rtc_time));

int c =atoi(ptr);

if( c /1000 )

time_year_begin(ptr,tm);

else

time_hour_begin(ptr,tm);

return 0;

}

int help_info(void){

printf("\nUsage: rtdate [-d PATH] [OPTIONS]\n");

printf("\nOr: rtdate [-d PATH] -s TIME \n");

printf("\nDisplay rtc-time or sys-time, or set time.\n");

printf("\nOptions:\n");

printf("\n\t-r\t\tshow rtc-time\n");

printf("\n\t-l\t\tshow sys-time\n");

printf("\n\t-s TIME\ttset rtc-time\n");

printf("\n\t-h or --help\tshow help information\n");

printf("\nRecognized formats for TIME:\n");

printf("\n\tYYYY.MM.DD-hh.mm[.ss]\n");

printf("\n\tYYYY.MM.DD\n");

printf("\n\thh.mm[.ss]\n");

printf("\n\thh:mm[:ss]\n");

printf("\n\t'.' can be replaced by ':'\n");

printf("\nFor example\n\trtdate -s YYYY.MM.DD \n");

printf("\n\trtdate -s hh.mm:ss \n");

printf("\n\trtdate -d /dev/i2c-1 -s YYYY:MM:DD-hh.mm:ss \n\n");

return 0;

}

void path(char* argv){

fd = i_open(argv,TIMEOUT,RETRY);

if( fd < 0 ){

printf("i2c_open error!\n");

exit(-1);

}

}

int main(int argc,char* argv[]){

int sw = argc;

if( argc >= 3){

if(!strcmp(argv[1],"-d")){

path(argv[2]);

sw -= 2;

}else{

path("/dev/i2c-1");

}

}else{

path("/dev/i2c-1");

}

switch(sw){

case 1: {

if( rtc_time_list() ){

printf("rtctime_show error!\n");

exit(-1);

}

break;

}

case 2: {

if(!strcmp(argv[argc-1],"-l")){

if( sys_time_list() ){

printf("systime_show error!\n");

exit(-1);

}

}else if(!strcmp(argv[argc-1],"-r")){

if( rtc_time_list() ){

printf("rtctime_show error!\n");

exit(-1);

}

}else if(!strcmp(argv[argc-1],"-h") || !strcmp(argv[argc-1],"--help" ) ) {

help_info();

}else{

printf("useless operation %s ...\n Please try -h or --help for more information\n",argv[argc-1]);

exit(-1);

}

break;

}

case 3: {

if(!strcmp(argv[argc-2], "-s")){

i2c_rtc_data(argv[argc-1]);

}

break;

}

default:

printf("command error!\nPlease input -h or--help for more information"),exit(-1);

}

close(fd);

return 0;

}

************************** *********************************************

i2c.c :

******************* *****************************************

#include "i2c.h"

static int fd;

int

i2c_read_data(u16 addr, u8 offset, u8 *val)

{

int i,ret = 0;

struct i2c_rdwr_ioctl_data *data;

if((data =(struct i2c_rdwr_ioctl_data *)malloc(sizeof(struct i2c_rdwr_ioctl_data)))==NULL)

return -1;

data->nmsgs = 2;

if ((data->msgs = (struct i2c_msg *)malloc(data->nmsgs * sizeof(struct i2c_msg))) == NULL) {

ret = -1;

goto errexit3;

}

if ((data->msgs[0].buf = (unsigned char *)malloc(sizeof(unsigned char))) == NULL) {

ret = -1;

goto errexit2;

}

if ((data->msgs[1].buf = (unsigned char *)malloc(sizeof(unsigned char))) == NULL) {

ret = -1;

goto errexit1;

}

data->msgs[0].addr = addr;

data->msgs[0].flags = 0;

data->msgs[0].len = 1;

data->msgs[0].buf[0] = offset;

data->msgs[1].addr = addr;

data->msgs[1].flags = I2C_M_RD;

data->msgs[1].len = 13;//original data is 1

data->msgs[1].buf[0] = 0;

if ((ret = __i2c_send(fd, data)) < 0)

goto errexit0;

for(i = 0 ;i < data->msgs[1].len; i++)

val[i] = data->msgs[1].buf[i];

errexit0:

free(data->msgs[1].buf);

errexit1:

free(data->msgs[0].buf);

errexit2:

free(data->msgs);

errexit3:

free(data);

return ret;

}

int

i2c_write_data(u16 addr, u8 offset, u8 val)

{

int ret = 0;

struct i2c_rdwr_ioctl_data *data;

if ((data = (struct i2c_rdwr_ioctl_data *)malloc(sizeof(struct i2c_rdwr_ioctl_data))) == NULL)

return -1;

data->nmsgs = 1;

if ((data->msgs = (struct i2c_msg *)malloc(data->nmsgs * sizeof(struct i2c_msg))) == NULL) {

ret = -1;

goto errexit2;

}

if ((data->msgs[0].buf = (unsigned char *)malloc(2 * sizeof(unsigned char))) == NULL) {

ret = -1;

goto errexit1;

}

data->msgs[0].addr = addr;

data->msgs[0].flags = 0;

data->msgs[0].len = 2;

data->msgs[0].buf[0] = offset;

data->msgs[0].buf[1] = val;

if ((ret = __i2c_send(fd, data)) < 0)

goto errexit0;

errexit0:

free(data->msgs[0].buf);

errexit1:

free(data->msgs);

errexit2:

free(data);

return ret;

}

int

i2c_open(unsigned char* dev, unsigned int timeout, unsigned int retry)

{

if ((fd = open(dev, O_RDWR)) < 0)

return fd;

__i2c_set(fd, timeout, retry);

return fd;

}

static int

__i2c_send(int fd, struct i2c_rdwr_ioctl_data *data)

{

if (fd < 0)

return -1;

if (data == NULL)

return -1;

if (data->msgs == NULL || data->nmsgs == 0)

return -1;

return ioctl(fd, I2C_RDWR, (unsigned long)data) ;

}

static int

__i2c_set(int fd, unsigned int timeout, unsigned int retry)

{

if (fd == 0 )

return -1;

ioctl(fd, I2C_TIMEOUT, timeout ? timeout : I2C_DEFAULT_TIMEOUT);

ioctl(fd, I2C_RETRIES, retry ? retry : I2C_DEFAULT_RETRY);

return 0;

}

void

i2c_close(int fd)

{

if (fd < 0)

return;

close(fd);

}

unsigned bcd2bin(unsigned char val)

{

return (val & 0x0f) + (val >> 4) * 10;

}

unsigned char bin2bcd(unsigned val)

{

return ((val / 10) << 4) + val % 10;

}

********* *******************************************************

i2c.h :

******************* *******************************************

#ifndef I2C_H

#define I2C_H

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#define I2C_DEFAULT_TIMEOUT1

#define I2C_DEFAULT_RETRY3

#define PCF8563_REG_SC 0x02

#define PCF8563_REG_MN 0x03

#define PCF8563_REG_HR 0x04

#define PCF8563_REG_DM 0x05

#define PCF8563_REG_DW 0x06

#define PCF8563_REG_MO 0x07

#define PCF8563_REG_YR 0x08

#define PCF8563_MO_C 0x80

typedef unsigned char u8;

typedef unsigned short u16;

typedef unsigned int u32;

typedef unsigned long long u64;

typedef signed char s8;

typedef short s16;

typedef int s32;

typedef long long s64;

static const unsigned char rtc_days_in_month[] = {

31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31

};

unsigned bcd2bin(unsigned char val);

unsigned bcd2bin(unsigned char val);

static int

__i2c_send(int fd, struct i2c_rdwr_ioctl_data *data);

static int

__i2c_set(int fd, unsigned int timeout, unsigned int retry);

int

i2c_read_data(u16 addr, u8 offset, u8 *val);

int

i2c_write_data(u16 addr, u8 offset, u8 val);

int

i2c_open(unsigned char* dev, unsigned int timeout, unsigned int retry);

#endif

*************** *********************************************************

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值