RT-Thread驱动——RTC PCF8563

13 篇文章 17 订阅

1 介绍

1.1 RTC选择

  RTC选择不外乎就两种,独立外挂和CPU集成,精度要求不高或者联网的情况下使用集成RTC即可,可节约成本。独立RTC的选择则比较多,从低端到高精度的,各大厂商都有可选择,常用的如DS1302、PCF8563、DS3231等。对于时间要求严格,并且没有连接网络无法同步网络时间,则需要选择独立RTC,对于RT-Thread来说,本人针对PCF8563和DS3231都进行测试过,并且在产品上已经使用。所以选择一款经典的RTC芯片,以PCF8563为例,阐述RTT下的RTC驱动实现,举一反三,根据此更换其他RTC芯片则是依葫芦画瓢。


1.2 PCF8563

  PCF8563是一款非常经典的实时时钟(RTC)芯片,是飞利浦(PHILIPS)司推出的一款工业级内含I2C 总线接口功能的具有极低功耗的多功能时钟/日历芯片。PCF8563的驱动源码和说明文档也是非常多,特别是可以参考Linux内核的PCF8563源码。


2 RT-Thread驱动

2.1 RTT驱动模型

  RTT驱动模型和Linux比较类似,严格分为几层,而且层次分明,层与层之间都有标准的访问接口,最上层封则装成统一的接口,即是open、read、write、close
这里写图片描述
RTT 驱动类型为“struct rt_device”结构体,其原型如下:

/**
 * Device structure
 */
struct rt_device
{
    struct rt_object          parent;                   /**< inherit from rt_object */
    enum rt_device_class_type type;                     /**< device type */
    rt_uint16_t               flag;                     /**< device flag */
    rt_uint16_t               open_flag;                /**< device open flag */
    rt_uint8_t                ref_count;                /**< reference count */
    rt_uint8_t                device_id;                /**< 0 - 255 */
    /* device call back */
    rt_err_t (*rx_indicate)(rt_device_t dev, rt_size_t size);
    rt_err_t (*tx_complete)(rt_device_t dev, void *buffer);
    /* common device interface */
    rt_err_t  (*init)   (rt_device_t dev);
    rt_err_t  (*open)   (rt_device_t dev, rt_uint16_t oflag);
    rt_err_t  (*close)  (rt_device_t dev);
    rt_size_t (*read)   (rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size);
    rt_size_t (*write)  (rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size);
    rt_err_t  (*control)(rt_device_t dev, rt_uint8_t cmd, void *args);
    void      *user_data;        /**< device private data */
};

  其中的函数指针部分就是需要我们在底层重点实现的,其他参数则为描述驱动类型或者调用驱动的方式设置。


2.2 RTT的RTC框架模型

  RTT兼容C库的时间获取函数—“time”,并重写了time函数,其实现源码如下。

#if defined (__IAR_SYSTEMS_ICC__) &&  (__VER__) >= 6020000
#pragma module_name = "?time"
time_t (__time32)(time_t *t) /* Only supports 32-bit timestamp */
#else
time_t time(time_t *t)
#endif
{
    static rt_device_t device = RT_NULL;
    time_t time_now = 0;
    /* optimization: find rtc device only first. */
    if (device == RT_NULL)
    {
        device = rt_device_find("rtc");
    }
    /* read timestamp from RTC device. */
    if (device != RT_NULL)
    {
        if (rt_device_open(device, 0) == RT_EOK)
        {
            rt_device_control(device, RT_DEVICE_CTRL_RTC_GET_TIME, &time_now);
            rt_device_close(device);
        }
    }
    /* if t is not NULL, write timestamp to *t */
    if (t != RT_NULL)
    {
        *t = time_now;
    }
    return time_now;
}

  设置日期和时间的函数分别为“set_date”“set_time”,这个几个函数需要我们关注的地方是RTC驱动注册名称为“rtc”,及“control”函数。了解这几个函数,主要是熟悉访问RTC驱动的方式,以下面实现PCF8563驱动过程。


2.3 RTT驱动调用过程

这里写图片描述

3 RTT PCF8563驱动

  在使用RTT驱动框架控制一个外设时,原则上最基本的需要实现的函数实体分别有“init”、“open”、“close”、“read”、“write”以及“control”函数,这样应用层就可也驱动框架接口(API)访问底层外设。

  而通过上文分析RTT下的RTC设备模型可看出,访问RTC设备是循序地按照“open->read/write->close”的来处理,对于行时间的获取和设置,都是通“control”函数接口进行。因此我们在这里需要关键实现的即是“control”函数接口对应的实体函数,该函数的功能包括从PCF8563读出时间和向PCF8563写入设定的时间。而对于“open”、“close”函数,则暂保留为空,如果后期RTT框架有改动,则增加openclose的内容。


3.1 PCF8563设备接口实现——control函数实现

static rt_err_t rt_pcf8563_control(rt_device_t dev, int cmd, void *args)
{
	rt_err_t	ret = RT_EOK;
    time_t 		*time;
    struct tm 	time_temp;	
    rt_uint8_t 	buff[7];
	
    RT_ASSERT(dev != RT_NULL);
    rt_memset(&time_temp, 0, sizeof(struct tm));

    switch (cmd)
    {
        case RT_DEVICE_CTRL_RTC_GET_TIME:
        time = (time_t *)args;
        ret = pcf8563_read_reg(REG_PCF8563_SEC,buff,7);

		if(ret == RT_EOK)
		{
	        time_temp.tm_year  = bcd_to_hex(buff[6]&SHIELD_PCF8563_YEAR) + 2000 - 1900;
	        time_temp.tm_mon   = bcd_to_hex(buff[5]&SHIELD_PCF8563_MON) - 1;
	        time_temp.tm_mday  = bcd_to_hex(buff[3]&SHIELD_PCF8563_DAY);
	        time_temp.tm_hour  = bcd_to_hex(buff[2]&SHIELD_PCF8563_HOUR);
	        time_temp.tm_min   = bcd_to_hex(buff[1]&SHIELD_PCF8563_MIN);
	        time_temp.tm_sec   = bcd_to_hex(buff[0]&SHIELD_PCF8563_SEC);

	        *time = mktime(&time_temp);
		}
        break;

        case RT_DEVICE_CTRL_RTC_SET_TIME:
        {
            struct tm *time_new;
					
            time = (time_t *)args;
            time_new = localtime(time);
            buff[6] = hex_to_bcd(time_new->tm_year + 1900 - 2000);
            buff[5] = hex_to_bcd(time_new->tm_mon + 1);
            buff[3] = hex_to_bcd(time_new->tm_mday);
            buff[4] = hex_to_bcd(time_new->tm_wday+1);
            buff[2] = hex_to_bcd(time_new->tm_hour);
            buff[1] = hex_to_bcd(time_new->tm_min);
            buff[0] = hex_to_bcd(time_new->tm_sec);
            ret = pcf8563_write_reg(REG_PCF8563_SEC,buff,7);

        }
        break;
        default:
        break;
		}
    return RT_EOK;
}
  • “RT_DEVICE_CTRL_RTC_GET_TIME”“RT_DEVICE_CTRL_RTC_SET_TIME”分别是RTT定义的获取时间命令字和设置时间命令字。

  • RTT的RTC模型与Linux系统类似,将具体年月日换算成时间戳。

  • 关于年和月的处理:struct tm为标准C库定义的结构体,结构体中的“tm_year”(年份)是从1900年开始的,“tm_mon”(月份)范围是0—11,0表示1月;而PCF8563的年份值范围是0—99,月份值范围是1—12,因此要做相关处理。

  • “pcf8563_read_reg”“pcf8563_write_reg”是PCF8563读写寄存器函数,通过此两函数从寄存器获取时间或者设置(写入)时间。

  • 从PCF8563中获取的时间值为BCD码,故需编写“bcd_to_hex”转换函数将BCD码转换为十进制数;同理在设置时间前,需要将十进制数转换为BCD码,即“hex_to_bcd”函数,然后再写寄存器。两者函数源码如下。

/* bcd to hex */
static unsigned char bcd_to_hex(unsigned char data)
{
    unsigned char temp;

    temp = ((data>>4)*10 + (data&0x0f));
    return temp;
}

/* hex_to_bcd */
static unsigned char hex_to_bcd(unsigned char data)
{
    unsigned char temp;

    temp = (((data/10)<<4) + (data%10));
    return temp;
}

3.2 PCF8563底层驱动

  PCF8563底层驱动即是通过i2c总线读写其寄存器,而i2c总线RTT已经统一好框架,通过RTT的标准框架调用i2c总线进行访问PCF8563。这里i2c总线框架与底层分离,i2c总线底层的实现则与具体cpu型号相关。

第一步,定义一个注册设备用的PCF8563结构体

struct pcf8563_device
{
    struct rt_device rtc_parent;
    struct rt_i2c_bus_device *i2c_device;
};
  • rtc_parent 是标准RTT驱动设备框架参数。
  • i2c_device 是i2c总线指针,通过该指针调用i2c总线,使用前必须初始化。

第二步,编写PCF8563读写函数

/* pcf8563 read register */
rt_uint8_t pcf8563_read_reg(rt_uint8_t reg,rt_uint8_t *data,rt_uint8_t data_size)
{
	struct rt_i2c_msg msg[2];
		
    msg[0].addr  = PCF8563_ARRD;
    msg[0].flags = RT_I2C_WR;
    msg[0].len   = 1;
    msg[0].buf   = &reg;
    msg[1].addr  = PCF8563_ARRD;
    msg[1].flags = RT_I2C_RD;
    msg[1].len   = data_size;
    msg[1].buf   = data;
    if(rt_i2c_transfer(pcf8563_dev.i2c_device, msg, 2) != 2)
	    return RT_ERROR; 
    return RT_EOK;
}
/* pcf8563 write register */
rt_err_t pcf8563_write_reg(rt_uint8_t reg, rt_uint8_t *data,rt_uint8_t data_size)
{
    struct rt_i2c_msg msg[2];

    msg[0].addr   	= PCF8563_ARRD;
    msg[0].flags	= RT_I2C_WR;
    msg[0].len   	= 1;
    msg[0].buf   	= &reg;
    msg[1].addr  	= PCF8563_ARRD;
    msg[1].flags	= RT_I2C_WR | RT_I2C_NO_START;
    msg[1].len   	= data_size;
    msg[1].buf   	= data;
	
    if (rt_i2c_transfer(pcf8563_dev.i2c_device, msg, 2) == 2)
	{
		return RT_EOK;
	}
 	else
    {
	  	rt_kprintf("i2c bus write failed!\r\n");
        return -RT_ERROR;
    }
}
  • 使用到RTT的i2c接口函数为“rt_i2c_transfer”,入口参数分别为:i2c设备指针、信息帧、帧数。
  • “struct rt_i2c_msg”是RTT定义的i2c信息帧,原型如下。
struct rt_i2c_msg
{
    rt_uint16_t addr;
    rt_uint16_t flags;
    rt_uint16_t len;
    rt_uint8_t  *buf;
};

  • addr,i2c器件地址,不包括读写位,如PCF8563的地址为0x51。
  • flags,标识位,有几种类型,包括读、写、10bit i2c地址选择、应答、非应答。
#define RT_I2C_WR                0x0000
#define RT_I2C_RD               (1u << 0)
#define RT_I2C_ADDR_10BIT       (1u << 2)  /* this is a ten bit chip address */
#define RT_I2C_NO_START         (1u << 4)
#define RT_I2C_IGNORE_NACK      (1u << 5)
#define RT_I2C_NO_READ_ACK      (1u << 6)  /* when I2C reading, we do not ACK */
  • len,数据长度。
  • buf,数据缓存指针(发送或者接收)。
  • 对于读函数,需要两帧信息,第一帧发送读寄存器地址数据,第二帧开始接收返回数据;对于写函数,同样需要两帧,第一帧发送写寄存器地址数据,第二帧发送待写入的数据。

3.3 初始化

  初始化包括两部分,一是指定i2c总线,PCF8563读写函数通过调用i2c总线进行访问;而是RTC设备初始化,上层应用从而可通过标准接口访问PCF8563。

/* pcf8563 device int  */
int rt_hw_pcf8563_init(void)
{		
    struct rt_i2c_bus_device *i2c_device;
    uint8_t data;
	
    i2c_device = rt_i2c_bus_device_find("i2c1");
    if (i2c_device == RT_NULL)
    {
	#ifdef RT_USE_FINSH_DEBUG
        rt_kprintf("i2c bus device %s not found!\r\n", "i2c1");
	#endif
        return 1;
    }				 	
    pcf8563_dev.i2c_device = i2c_device;
    /* register rtc device */
    pcf8563_dev.rtc_parent.type   		= RT_Device_Class_RTC;
    pcf8563_dev.rtc_parent.init    		= RT_NULL;
    pcf8563_dev.rtc_parent.open    		= rt_pcf8563_open;
    pcf8563_dev.rtc_parent.close   		= RT_NULL;
    pcf8563_dev.rtc_parent.read   		= rt_pcf8563_read;
    pcf8563_dev.rtc_parent.write  	 	= RT_NULL;
    pcf8563_dev.rtc_parent.control 		= rt_pcf8563_control;
    pcf8563_dev.rtc_parent.user_data 	= RT_NULL;			/* no private */
    rt_device_register(&pcf8563_dev.rtc_parent, "rtc", RT_DEVICE_FLAG_RDWR);
		
    /* init pcf8563 */
    data = 0x7f;	/* close clock out */
    if (pcf8563_write_reg(REG_PCF8563_CLKOUT, &data, 1) != RT_EOK)
	{
		return -RT_ERROR;
	}

    return RT_EOK;
}
INIT_DEVICE_EXPORT(rt_hw_pcf8563_init);
  • 初始化最开始定义的“pcf8563_dev”,其中“rt_pcf8563_open”、“rt_pcf8563_read”只是空函数,没有实现内容;然后注册为“rtc”设备,RTT默认调用RTC的名称为“rtc”,采用统一命名,更换RTC芯片时保证该命名一致。
  • 调用RTT宏“INIT_DEVICE_EXPORT”完成初始化。

4 完整源码

#ifndef _DRV_PCF8563_H_
#define _DRV_PCF8563_H_

#include <rthw.h>
#include <rtthread.h>
#include <rtdevice.h>

/* slave address */	
#define 	PCF8563_ARRD			0x51

/* register */
#define		REG_PCF8563_STATE1		0x00
#define		REG_PCF8563_STATE2		0x01
#define		REG_PCF8563_SEC			0x02
#define		REG_PCF8563_MIN			0x03
#define		REG_PCF8563_HOUR		0x04
#define		REG_PCF8563_DAY			0x05
#define		REG_PCF8563_WEEK		0x06
#define		REG_PCF8563_MON			0x07
#define		REG_PCF8563_YEAR		0x08
#define		REG_PCF8563_CLKOUT		0x0d

/* offset */
#define 	SHIELD_PCF8563_STATE1   (unsigned char)0xa8
#define 	SHIELD_PCF8563_STATE2   (unsigned char)0x1f
#define 	SHIELD_PCF8563_SEC      (unsigned char)0x7f
#define 	SHIELD_PCF8563_MIN      (unsigned char)0x7f
#define 	SHIELD_PCF8563_HOUR     (unsigned char)0x3f
#define 	SHIELD_PCF8563_DAY      (unsigned char)0x3f
#define 	SHIELD_PCF8563_WEEK     (unsigned char)0x07
#define 	SHIELD_PCF8563_MON      (unsigned char)0x1f
#define 	SHIELD_PCF8563_YEAR     (unsigned char)0xff

extern int rt_hw_pcf8563_init(void);

#endif 
/*
 * File      : drv_pcf8563.c
 * This file is part of RT-Thread RTOS
 * COPYRIGHT (C) 2006 - 2018, RT-Thread Development Team
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License along
 *  with this program; if not, write to the Free Software Foundation, Inc.,
 *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Change Logs:
 * Date           Author       Notes
 * 2018-04-20     Acuity       the first version
 */
 
#include <board.h>
#include <rtdevice.h>
#include <time.h>
#include "drv_pcf8563.h"

#define RT_USING_PCF8563

#ifdef RT_USING_PCF8563		

struct pcf8563_device
{
    struct rt_device rtc_parent;
    struct rt_i2c_bus_device *i2c_device;
};
static struct pcf8563_device pcf8563_dev;

/* bcd to hex */
static unsigned char bcd_to_hex(unsigned char data)
{
    unsigned char temp;

    temp = ((data>>4)*10 + (data&0x0f));
    return temp;
}

/* hex_to_bcd */
static unsigned char hex_to_bcd(unsigned char data)
{
    unsigned char temp;

    temp = (((data/10)<<4) + (data%10));
    return temp;
}

/* pcf8563 read register */
rt_err_t pcf8563_read_reg(rt_uint8_t reg,rt_uint8_t *data,rt_uint8_t data_size)
{
    struct rt_i2c_msg msg[2];
		
    msg[0].addr  = PCF8563_ARRD;
    msg[0].flags = RT_I2C_WR;
    msg[0].len   = 1;
    msg[0].buf   = &reg;
    msg[1].addr  = PCF8563_ARRD;
    msg[1].flags = RT_I2C_RD;
    msg[1].len   = data_size;
    msg[1].buf   = data;

    if (rt_i2c_transfer(pcf8563_dev.i2c_device, msg, 2) == 2)
    {
		return RT_EOK;
	}
 	else
    {
	  	rt_kprintf("i2c bus write failed!\r\n");
        return -RT_ERROR;
    }
}

/* pcf8563 write register */
rt_err_t pcf8563_write_reg(rt_uint8_t reg, rt_uint8_t *data,rt_uint8_t data_size)
{
    struct rt_i2c_msg msg[2];

    msg[0].addr   	= PCF8563_ARRD;
    msg[0].flags	= RT_I2C_WR;
    msg[0].len   	= 1;
    msg[0].buf   	= &reg;
    msg[1].addr  	= PCF8563_ARRD;
    msg[1].flags	= RT_I2C_WR | RT_I2C_NO_START;
    msg[1].len   	= data_size;
    msg[1].buf   	= data;
	
    if (rt_i2c_transfer(pcf8563_dev.i2c_device, msg, 2) == 2)
	{
		return RT_EOK;
	}
 	else
    {
	  	rt_kprintf("i2c bus write failed!\r\n");
        return -RT_ERROR;
    }
}

static rt_err_t rt_pcf8563_open(rt_device_t dev, rt_uint16_t flag)
{
    if (dev->rx_indicate != RT_NULL)
    {
        /* open interrupt */
    }

    return RT_EOK;
}

static rt_size_t rt_pcf8563_read(rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size)
{
    return RT_EOK;
}

static rt_err_t rt_pcf8563_control(rt_device_t dev, int cmd, void *args)
{
	rt_err_t	ret = RT_EOK;
    time_t 		*time;
    struct tm 	time_temp;	
    rt_uint8_t 	buff[7];
	
    RT_ASSERT(dev != RT_NULL);
    rt_memset(&time_temp, 0, sizeof(struct tm));

    switch (cmd)
    {
        case RT_DEVICE_CTRL_RTC_GET_TIME:
        time = (time_t *)args;
        ret = pcf8563_read_reg(REG_PCF8563_SEC,buff,7);

		if(ret == RT_EOK)
		{
	        time_temp.tm_year  = bcd_to_hex(buff[6]&SHIELD_PCF8563_YEAR) + 2000 - 1900;
	        time_temp.tm_mon   = bcd_to_hex(buff[5]&SHIELD_PCF8563_MON) - 1;
	        time_temp.tm_mday  = bcd_to_hex(buff[3]&SHIELD_PCF8563_DAY);
	        time_temp.tm_hour  = bcd_to_hex(buff[2]&SHIELD_PCF8563_HOUR);
	        time_temp.tm_min   = bcd_to_hex(buff[1]&SHIELD_PCF8563_MIN);
	        time_temp.tm_sec   = bcd_to_hex(buff[0]&SHIELD_PCF8563_SEC);

	        *time = mktime(&time_temp);
		}
        break;

        case RT_DEVICE_CTRL_RTC_SET_TIME:
        {
            struct tm *time_new;
					
            time = (time_t *)args;
            time_new = localtime(time);
            buff[6] = hex_to_bcd(time_new->tm_year + 1900 - 2000);
            buff[5] = hex_to_bcd(time_new->tm_mon + 1);
            buff[3] = hex_to_bcd(time_new->tm_mday);
            buff[4] = hex_to_bcd(time_new->tm_wday+1);
            buff[2] = hex_to_bcd(time_new->tm_hour);
            buff[1] = hex_to_bcd(time_new->tm_min);
            buff[0] = hex_to_bcd(time_new->tm_sec);
            ret = pcf8563_write_reg(REG_PCF8563_SEC,buff,7);

        }
        break;
        default:
        break;
		}
    return RT_EOK;
}
		
/* pcf8563 device int  */
int rt_hw_pcf8563_init(void)
{		
    struct rt_i2c_bus_device *i2c_device;
    uint8_t data;
	
    i2c_device = rt_i2c_bus_device_find("i2c1");
    if (i2c_device == RT_NULL)
    {
	#ifdef RT_USE_FINSH_DEBUG
        rt_kprintf("i2c bus device %s not found!\r\n", "i2c1");
	#endif
        return 1;
    }				 	
    pcf8563_dev.i2c_device = i2c_device;
    /* register rtc device */
    pcf8563_dev.rtc_parent.type   		= RT_Device_Class_RTC;
    pcf8563_dev.rtc_parent.init    		= RT_NULL;
    pcf8563_dev.rtc_parent.open    		= rt_pcf8563_open;
    pcf8563_dev.rtc_parent.close   		= RT_NULL;
    pcf8563_dev.rtc_parent.read   		= rt_pcf8563_read;
    pcf8563_dev.rtc_parent.write  	 	= RT_NULL;
    pcf8563_dev.rtc_parent.control 		= rt_pcf8563_control;
    pcf8563_dev.rtc_parent.user_data 	= RT_NULL;			/* no private */
    rt_device_register(&pcf8563_dev.rtc_parent, "rtc", RT_DEVICE_FLAG_RDWR);
		
    /* init pcf8563 */
    data = 0x7f;	/* close clock out */
    if (pcf8563_write_reg(REG_PCF8563_CLKOUT, &data, 1) != RT_EOK)
	{
		return -RT_ERROR;
	}

    return RT_EOK;
}
INIT_DEVICE_EXPORT(rt_hw_pcf8563_init);
#endif

  • 8
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 11
    评论
pcf8563_i2c1_r8_ruoge_ov2640通过给RTC驱动增加设备节点读取秒钟成功+直接读取I2C1获取秒钟值20160626_2201.7z http://blog.csdn.net/21cnbao/article/details/7919055 在Android源码树中添加userspace I2C读写工具(i2c-util) 本文使用的开发板是:杭州若格科技有限公司的全志R8。CPU:CPUARM Cortex-A8 更多芯片资料请参见全志官网: http://www.allwinnertech.com/clq/r/R8.html 通过/dev/i2c-n节点,用户可以在userspace直接访问板上的i2c外设寄存器,主要是透过I2C_RDWR这个IO控制命令将i2c_msg数组传递给kernel去执行。 开发板的/dev/i2c-1总线下挂有一片I2C的RTCpcf8563。 root@android:/dev # cd /sys/class/i2c-adapter/ root@android:/sys/class/i2c-adapter # ll lrwxrwxrwx root root 1970-01-02 08:31 i2c-0 -> ../../devices/platform/sun5i-i2c.0/i2c-0 lrwxrwxrwx root root 1970-01-02 08:31 i2c-1 -> ../../devices/platform/sun5i-i2c.1/i2c-1 lrwxrwxrwx root root 1970-01-02 08:31 i2c-2 -> ../../devices/platform/sun5i-i2c.2/i2c-2 root@android:/sys/class/i2c-adapter # cd i2c-1 root@android:/sys/class/i2c-adapter/i2c-1 # ll drwxr-xr-x root root 1970-01-02 08:31 1-0051 --w------- root root 4096 1970-01-02 08:31 delete_device lrwxrwxrwx root root 1970-01-02 08:31 device -> ../../sun5i-i2c.1 drwxr-xr-x root root 1970-01-01 08:00 i2c-dev -r--r--r-- root root 4096 1970-01-02 08:31 name --w------- root root 4096 1970-01-02 08:31 new_device drwxr-xr-x root root 1970-01-01 08:00 power lrwxrwxrwx root root 1970-01-02 08:31 subsystem -> ../../../../bus/i2c -rw-r--r-- root root 4096 1970-01-01 08:00 uevent root@android:/sys/class/i2c-adapter/i2c-1 # root@android:/sys/class/i2c-adapter/i2c-1 # cd 1-0051/ root@android:/sys/class/i2c-adapter/i2c-1/1-0051 # ll lrwxrwxrwx root root 1970-01-02 10:18 driver -> ../../../../../bus/i2c/drivers/pcf8563 -r--r--r-- root root 4096 1970-01-02 10:18 modalias -r--r--r-- root root 4096 1970-01-02 10:18 name drwxr-xr-x root root 1970-01-02 10:18 power drwxr-xr-x root root 1970-01-02 10:18 rtc lrwxrwxrwx root root 1970-01-02 10:18 subsystem -> ../../../../../bus/i2c -rw-r--r-- root root 4096 1970-01-02 10:18 uevent root@android:/sys/class/i2c-adapter/i2c-1/1-0051 # cat name pcf8563 root@android:/sys/class/i2c-adapter/i2c-1/1-0051 # 注释:1-0051 1 表示 i2c-1这条I2C1总线上挂载的设备,如果是I2C2总线上挂载的设备,路径就是2-00XX了。 0051 一般的I2C设备的从机地址都是一个字节的,因为前两位为0x00(16进制的),后两位为pcf8563移位自后的I2C从机地址0x51(也是16进制的) 压缩包中的PCF8563-CN.pdf,datasheet告诉我们:I2C总线从地址:读,0A3H;写,0A2H。右移一位之后正好是0x51。 下面的代码可以完成这个功能: #include #include #include #include #include #include #include #include #include #include #include /* This is the structure as used in the I2C_RDWR ioctl call */ struct i2c_rdwr_ioctl_data { struct i2c_msg __user *msgs; /* pointers to i2c_msgs */ __u32 nmsgs; /* number of i2c_msgs */ }; int i2c_read_reg(char *dev, unsigned char *buf, unsigned slave_address, unsigned reg_address, int len) { struct i2c_rdwr_ioctl_data work_queue; unsigned char w_val = reg_address; int ret; int fd = open(dev, O_RDWR); if (!fd) { printf("Error on opening the device file\n"); return 0; } work_queue.nmsgs = 2; work_queue.msgs = (struct i2c_msg*)malloc(work_queue.nmsgs *sizeof(struct i2c_msg)); if (!work_queue.msgs) { printf("Memory alloc error\n"); close(fd); return 0; } ioctl(fd, I2C_TIMEOUT, 2); ioctl(fd, I2C_RETRIES, 1); (work_queue.msgs[0]).len = 1; (work_queue.msgs[0]).addr = slave_address; (work_queue.msgs[0]).buf = &w_val; (work_queue.msgs[1]).len = len; (work_queue.msgs[1]).flags = I2C_M_RD; (work_queue.msgs[1]).addr = slave_address; (work_queue.msgs[1]).buf = buf; ret = ioctl(fd, I2C_RDWR, (unsigned long) &work_queue); if (ret < 0) { printf("Error during I2C_RDWR ioctl with error code: %d\n", ret); close(fd); free(work_queue.msgs); return 0; } else { printf("read salve:x reg:x\n", slave_address, reg_address); close(fd); free(work_queue.msgs); return len; } } int i2c_write_reg(char *dev, unsigned char *buf, unsigned slave_address, unsigned reg_address, int len) { struct i2c_rdwr_ioctl_data work_queue; unsigned char w_val = reg_address; unsigned char w_buf[len+1]; int ret; w_buf[0] = reg_address; int fd = open(dev, O_RDWR); if (!fd) { printf("Error on opening the device file\n"); return 0; } work_queue.nmsgs = 1; work_queue.msgs = (struct i2c_msg*)malloc(work_queue.nmsgs *sizeof(struct i2c_msg)); if (!work_queue.msgs) { printf("Memory alloc error\n"); close(fd); return 0; } ioctl(fd, I2C_TIMEOUT, 2); ioctl(fd, I2C_RETRIES, 1); (work_queue.msgs[0]).len = 1 + len; (work_queue.msgs[0]).addr = slave_address; (work_queue.msgs[0]).buf = w_buf; memcpy(w_buf + 1, buf, len); ret = ioctl(fd, I2C_RDWR, (unsigned long) &work_queue); if (ret < 0) { printf("Error during I2C_RDWR ioctl with error code: %d\n", ret); close(fd); free(work_queue.msgs); return 0; } else { printf("write salve:x reg:x\n", slave_address, reg_address); close(fd); free(work_queue.msgs); return len; } } int main(int argc, char **argv) { unsigned int fd; unsigned int slave_address, reg_address; unsigned r_w; unsigned w_val; unsigned char rw_val; if (argc < 5) { printf("Usage:\n%s /dev/i2c-x start_addr reg_addr rw[0|1] [write_val]\n", argv[0]); return 0; } fd = open(argv[1], O_RDWR); if (!fd) { printf("Error on opening the device file %s\n", argv[1]); return 0; } sscanf(argv[2], "%x", &slave_address); sscanf(argv[3], "%x", &reg_address); sscanf(argv[4], "%d", &r_w); if (r_w == 0) { i2c_read_reg(argv[1], &rw_val, slave_address, reg_address, 1); printf("Read %s-%x reg %x, read value:%x\n", argv[1], slave_address, reg_address, rw_val); } else { if (argc < 6) { printf("Usage:\n%s /dev/i2c-x start_addr reg_addr r|w[0|1] [write_val]\n", argv[0]); return 0; } sscanf(argv[5], "%d", &w_val); if ((w_val & ~0xff) != 0) printf("Error on written value %s\n", argv[5]); rw_val = (unsigned char)w_val; i2c_write_reg(argv[1], &rw_val, slave_address, reg_address, 1); } return 0; } 在android/external/新建i2c-util目录,上述源代码存入android/external/i2c-util/i2c-util.c, R:\wyb\pcf8563_i2c1_r8_ruoge_ov2640\android\i2c-util\i2c-util.c 编写对应的Android.mk: LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE_TAGS := optional LOCAL_MODULE = i2c-util # LOCAL_SRC_FILES := $(call all-subdir-c-files) LOCAL_SRC_FILES := i2c-util.c include $(BUILD_EXECUTABLE) 编译Android后,上述工具会位于/system/bin目录。在电路板上使用它: R:\wyb\pcf8563_i2c1_r8_ruoge_ov2640\android\out\target\product\nuclear-evb\system\bin\i2c-util 如果android已经编译了,只需要执行: rootroot@rootroot-E400:~/wyb/pcf8563_i2c1_r8_ruoge_ov2640/android$ source build/envsetup.sh rootroot@rootroot-E400:~/wyb/pcf8563_i2c1_r8_ruoge_ov2640/android$ lunch 选择:18. nuclear_evb-eng (注意:不同的ubuntu电脑,序号可能不同,但是只需要选择nuclear_evb-eng编译选项前面的序号既可!!!!) rootroot@rootroot-E400:~/wyb/pcf8563_i2c1_r8_ruoge_ov2640/android$ rootroot@rootroot-E400:~/wyb/pcf8563_i2c1_r8_ruoge_ov2640/android$ cd i2c-util/ rootroot@rootroot-E400:~/wyb/pcf8563_i2c1_r8_ruoge_ov2640/android/i2c-util$ rootroot@rootroot-E400:~/wyb/pcf8563_i2c1_r8_ruoge_ov2640/android/i2c-util$ rootroot@rootroot-E400:~/wyb/pcf8563_i2c1_r8_ruoge_ov2640/android/i2c-util$ mm 详细的编译步骤: Connecting to 192.168.1.103:22... Connection established. To escape to local shell, press 'Ctrl+Alt+]'. Welcome to Ubuntu 14.04 LTS (GNU/Linux 3.13.0-24-generic x86_64) * Documentation: https://help.ubuntu.com/ Last login: Sun Jun 26 19:23:30 2016 from 192.168.1.101 rootroot@rootroot-E400:~$ cd wyb/pcf8563_i2c1_r8_ruoge_ov2640/ rootroot@rootroot-E400:~/wyb/pcf8563_i2c1_r8_ruoge_ov2640$ rootroot@rootroot-E400:~/wyb/pcf8563_i2c1_r8_ruoge_ov2640$ rootroot@rootroot-E400:~/wyb/pcf8563_i2c1_r8_ruoge_ov2640$ ll total 8606460 drwxr-xr-x 4 rootroot rootroot 4096 Jun 26 20:46 ./ drwxr-xr-x 19 rootroot rootroot 4096 Jun 25 06:50 ../ drwxrwxr-x 29 rootroot rootroot 4096 Jun 26 19:51 android/ drwxrwxr-x 8 rootroot rootroot 4096 Jun 26 16:35 lichee/ rootroot@rootroot-E400:~/wyb/pcf8563_i2c1_r8_ruoge_ov2640$ cd android/ rootroot@rootroot-E400:~/wyb/pcf8563_i2c1_r8_ruoge_ov2640/android$ rootroot@rootroot-E400:~/wyb/pcf8563_i2c1_r8_ruoge_ov2640/android$ rootroot@rootroot-E400:~/wyb/pcf8563_i2c1_r8_ruoge_ov2640/android$ source build/envsetup.sh including device/asus/grouper/vendorsetup.sh including device/asus/tilapia/vendorsetup.sh including device/generic/armv7-a-neon/vendorsetup.sh including device/generic/armv7-a/vendorsetup.sh including device/generic/mips/vendorsetup.sh including device/generic/x86/vendorsetup.sh including device/samsung/maguro/vendorsetup.sh including device/samsung/manta/vendorsetup.sh including device/samsung/toroplus/vendorsetup.sh including device/samsung/toro/vendorsetup.sh including device/softwinner/common/vendorsetup.sh including device/softwinner/crane-evb/vendorsetup.sh including device/softwinner/nuclear-256m/vendorsetup.sh including device/softwinner/nuclear-evb/vendorsetup.sh including device/softwinner/nuclear-r8m-evb/vendorsetup.sh including device/ti/panda/vendorsetup.sh including sdk/bash_completion/adb.bash rootroot@rootroot-E400:~/wyb/pcf8563_i2c1_r8_ruoge_ov2640/android$ rootroot@rootroot-E400:~/wyb/pcf8563_i2c1_r8_ruoge_ov2640/android$ rootroot@rootroot-E400:~/wyb/pcf8563_i2c1_r8_ruoge_ov2640/android$ lunch You're building on Linux Lunch menu... pick a combo: 1. full-eng 2. full_x86-eng 3. vbox_x86-eng 4. full_mips-eng 5. full_grouper-userdebug 6. full_tilapia-userdebug 7. mini_armv7a_neon-userdebug 8. mini_armv7a-userdebug 9. mini_mips-userdebug 10. mini_x86-userdebug 11. full_maguro-userdebug 12. full_manta-userdebug 13. full_toroplus-userdebug 14. full_toro-userdebug 15. crane_evb-eng 16. nuclear_256m-user 17. nuclear_256m-eng 18. nuclear_evb-eng 19. nuclear_r8m_evb-eng 20. full_panda-userdebug Which would you like? [full-eng] 18 ============================================ PLATFORM_VERSION_CODENAME=REL PLATFORM_VERSION=4.2.2 TARGET_PRODUCT=nuclear_evb TARGET_BUILD_VARIANT=eng TARGET_BUILD_TYPE=release TARGET_BUILD_APPS= TARGET_ARCH=arm TARGET_ARCH_VARIANT=armv7-a-neon HOST_ARCH=x86 HOST_OS=linux HOST_OS_EXTRA=Linux-3.13.0-24-generic-x86_64-with-Ubuntu-14.04-trusty HOST_BUILD_TYPE=release BUILD_ID=JDQ39 OUT_DIR=out ============================================ rootroot@rootroot-E400:~/wyb/pcf8563_i2c1_r8_ruoge_ov2640/android$ rootroot@rootroot-E400:~/wyb/pcf8563_i2c1_r8_ruoge_ov2640/android$ rootroot@rootroot-E400:~/wyb/pcf8563_i2c1_r8_ruoge_ov2640/android$ ll total 156 drwxrwxr-x 29 rootroot rootroot 4096 Jun 26 19:51 ./ drwxr-xr-x 4 rootroot rootroot 4096 Jun 26 20:46 ../ drwxrwxr-x 3 rootroot rootroot 4096 Jun 13 11:38 abi/ drwxrwxr-x 10 rootroot rootroot 4096 Jun 13 11:38 bionic/ drwxrwxr-x 5 rootroot rootroot 4096 Jun 13 11:38 bootable/ drwxrwxr-x 7 rootroot rootroot 4096 Jun 13 11:38 build/ drwxrwxr-x 11 rootroot rootroot 4096 Jun 13 11:38 cts/ drwxrwxr-x 18 rootroot rootroot 4096 Jun 13 11:38 dalvik/ drwxrwxr-x 18 rootroot rootroot 4096 Jun 13 11:38 development/ drwxrwxr-x 10 rootroot rootroot 4096 Jun 13 11:38 device/ drwxrwxr-x 3 rootroot rootroot 4096 Jun 13 11:38 docs/ drwxrwxr-x 159 rootroot rootroot 4096 Jun 13 11:39 external/ drwxrwxr-x 14 rootroot rootroot 4096 Jun 13 11:40 frameworks/ drwxrwxr-x 10 rootroot rootroot 4096 Jun 13 11:40 gdk/ drwxrwxr-x 10 rootroot rootroot 4096 Jun 13 11:40 hardware/ drwxr-xr-x 2 rootroot rootroot 4096 Jun 26 19:37 i2cscan/ drwxr-xr-x 2 rootroot rootroot 4096 Jun 26 19:52 i2c-util/ drwxrwxr-x 11 rootroot rootroot 4096 Jun 13 11:40 libcore/ drwxrwxr-x 4 rootroot rootroot 4096 Jun 13 11:40 libnativehelper/ -r--r--r-- 1 rootroot rootroot 87 Jun 13 11:38 Makefile drwxrwxr-x 8 rootroot rootroot 4096 Jun 13 11:40 ndk/ drwxrwxr-x 4 rootroot rootroot 4096 Jun 26 16:43 out/ drwxrwxr-x 8 rootroot rootroot 4096 Jun 13 11:40 packages/ drwxrwxr-x 5 rootroot rootroot 4096 Jun 13 11:40 pdk/ drwxrwxr-x 10 rootroot rootroot 4096 Jun 13 11:41 prebuilts/ drwxr-xr-x 2 rootroot rootroot 4096 Jun 25 13:01 read_pcf8563/ drwxrwxr-x 6 rootroot rootroot 4096 Jun 13 11:38 .repo/ drwxrwxr-x 51 rootroot rootroot 4096 Jun 13 11:41 sdk/ drwxrwxr-x 9 rootroot rootroot 4096 Jun 13 11:41 system/ drwxrwxr-x 4 rootroot rootroot 4096 Jun 13 11:41 tools/ rootroot@rootroot-E400:~/wyb/pcf8563_i2c1_r8_ruoge_ov2640/android$ rootroot@rootroot-E400:~/wyb/pcf8563_i2c1_r8_ruoge_ov2640/android$ rootroot@rootroot-E400:~/wyb/pcf8563_i2c1_r8_ruoge_ov2640/android$ cd i2c-util/ rootroot@rootroot-E400:~/wyb/pcf8563_i2c1_r8_ruoge_ov2640/android/i2c-util$ rootroot@rootroot-E400:~/wyb/pcf8563_i2c1_r8_ruoge_ov2640/android/i2c-util$ rootroot@rootroot-E400:~/wyb/pcf8563_i2c1_r8_ruoge_ov2640/android/i2c-util$ mm ============================================ PLATFORM_VERSION_CODENAME=REL PLATFORM_VERSION=4.2.2 TARGET_PRODUCT=nuclear_evb TARGET_BUILD_VARIANT=eng TARGET_BUILD_TYPE=release TARGET_BUILD_APPS= TARGET_ARCH=arm TARGET_ARCH_VARIANT=armv7-a-neon HOST_ARCH=x86 HOST_OS=linux HOST_OS_EXTRA=Linux-3.13.0-24-generic-x86_64-with-Ubuntu-14.04-trusty HOST_BUILD_TYPE=release BUILD_ID=JDQ39 OUT_DIR=out ============================================ PRODUCT_COPY_FILES frameworks/base/data/sounds/effects/ogg/Effect_Tick.ogg:system/media/audio/ui/Effect_Tick.ogg ignored. PRODUCT_COPY_FILES frameworks/base/data/sounds/effects/ogg/KeypressStandard.ogg:system/media/audio/ui/KeypressStandard.ogg ignored. PRODUCT_COPY_FILES frameworks/base/data/sounds/effects/ogg/KeypressSpacebar.ogg:system/media/audio/ui/KeypressSpacebar.ogg ignored. PRODUCT_COPY_FILES frameworks/base/data/sounds/effects/ogg/KeypressDelete.ogg:system/media/audio/ui/KeypressDelete.ogg ignored. PRODUCT_COPY_FILES frameworks/base/data/sounds/effects/ogg/KeypressReturn.ogg:system/media/audio/ui/KeypressReturn.ogg ignored. PRODUCT_COPY_FILES frameworks/base/data/sounds/effects/ogg/VideoRecord.ogg:system/media/audio/ui/VideoRecord.ogg ignored. PRODUCT_COPY_FILES frameworks/base/data/sounds/effects/ogg/camera_click.ogg:system/media/audio/ui/camera_click.ogg ignored. PRODUCT_COPY_FILES frameworks/base/data/sounds/effects/ogg/LowBattery.ogg:system/media/audio/ui/LowBattery.ogg ignored. PRODUCT_COPY_FILES frameworks/base/data/sounds/effects/ogg/Dock.ogg:system/media/audio/ui/Dock.ogg ignored. PRODUCT_COPY_FILES frameworks/base/data/sounds/effects/ogg/Undock.ogg:system/media/audio/ui/Undock.ogg ignored. PRODUCT_COPY_FILES frameworks/base/data/sounds/effects/ogg/Lock.ogg:system/media/audio/ui/Lock.ogg ignored. PRODUCT_COPY_FILES frameworks/base/data/sounds/effects/ogg/Unlock.ogg:system/media/audio/ui/Unlock.ogg ignored. PRODUCT_COPY_FILES frameworks/base/data/sounds/ringtones/ogg/Sceptrum.ogg:system/media/audio/ringtones/Sceptrum.ogg ignored. PRODUCT_COPY_FILES frameworks/base/data/sounds/effects/ogg/KeypressStandard_120.ogg:system/media/audio/ui/KeypressStandard.ogg ignored. PRODUCT_COPY_FILES frameworks/base/data/sounds/effects/ogg/KeypressSpacebar_120.ogg:system/media/audio/ui/KeypressSpacebar.ogg ignored. PRODUCT_COPY_FILES frameworks/base/data/sounds/effects/ogg/KeypressDelete_120.ogg:system/media/audio/ui/KeypressDelete.ogg ignored. PRODUCT_COPY_FILES frameworks/base/data/sounds/effects/ogg/KeypressReturn_120.ogg:system/media/audio/ui/KeypressReturn.ogg ignored. PRODUCT_COPY_FILES frameworks/base/data/sounds/notifications/ogg/Capella.ogg:system/media/audio/notifications/Capella.ogg ignored. PRODUCT_COPY_FILES frameworks/base/data/sounds/notifications/ogg/CetiAlpha.ogg:system/media/audio/notifications/CetiAlpha.ogg ignored. PRODUCT_COPY_FILES frameworks/base/data/sounds/notifications/ogg/Polaris.ogg:system/media/audio/notifications/Polaris.ogg ignored. PRODUCT_COPY_FILES frameworks/base/data/sounds/notifications/ogg/Pollux.ogg:system/media/audio/notifications/Pollux.ogg ignored. PRODUCT_COPY_FILES frameworks/base/data/sounds/notifications/ogg/Procyon.ogg:system/media/audio/notifications/Procyon.ogg ignored. PRODUCT_COPY_FILES frameworks/base/data/sounds/ringtones/ogg/Aquila.ogg:system/media/audio/ringtones/Aquila.ogg ignored. PRODUCT_COPY_FILES frameworks/base/data/sounds/ringtones/ogg/ArgoNavis.ogg:system/media/audio/ringtones/ArgoNavis.ogg ignored. PRODUCT_COPY_FILES frameworks/base/data/sounds/ringtones/ogg/Carina.ogg:system/media/audio/ringtones/Carina.ogg ignored. PRODUCT_COPY_FILES frameworks/base/data/sounds/ringtones/ogg/Centaurus.ogg:system/media/audio/ringtones/Centaurus.ogg ignored. PRODUCT_COPY_FILES frameworks/base/data/sounds/ringtones/ogg/Cygnus.ogg:system/media/audio/ringtones/Cygnus.ogg ignored. PRODUCT_COPY_FILES frameworks/base/data/sounds/ringtones/ogg/Draco.ogg:system/media/audio/ringtones/Draco.ogg ignored. PRODUCT_COPY_FILES frameworks/base/data/sounds/ringtones/ogg/Machina.ogg:system/media/audio/ringtones/Machina.ogg ignored. PRODUCT_COPY_FILES frameworks/base/data/sounds/ringtones/ogg/Orion.ogg:system/media/audio/ringtones/Orion.ogg ignored. PRODUCT_COPY_FILES frameworks/base/data/sounds/ringtones/ogg/Pegasus.ogg:system/media/audio/ringtones/Pegasus.ogg ignored. PRODUCT_COPY_FILES frameworks/base/data/sounds/ringtones/ogg/Pyxis.ogg:system/media/audio/ringtones/Pyxis.ogg ignored. PRODUCT_COPY_FILES frameworks/base/data/sounds/ringtones/ogg/Rigel.ogg:system/media/audio/ringtones/Rigel.ogg ignored. PRODUCT_COPY_FILES frameworks/base/data/sounds/ringtones/ogg/Scarabaeus.ogg:system/media/audio/ringtones/Scarabaeus.ogg ignored. PRODUCT_COPY_FILES frameworks/base/data/sounds/ringtones/ogg/Solarium.ogg:system/media/audio/ringtones/Solarium.ogg ignored. PRODUCT_COPY_FILES device/softwinner/nuclear-common/googleservice/gapps-jb-20121130-signed/system/tts/lang_pico/es-ES_zl0_sg.bin:system/tts/lang_pico/es-ES_zl0_sg.bin ignored. PRODUCT_COPY_FILES device/softwinner/nuclear-common/googleservice/gapps-jb-20121130-signed/system/tts/lang_pico/es-ES_ta.bin:system/tts/lang_pico/es-ES_ta.bin ignored. PRODUCT_COPY_FILES device/softwinner/nuclear-common/googleservice/gapps-jb-20121130-signed/system/tts/lang_pico/fr-FR_nk0_sg.bin:system/tts/lang_pico/fr-FR_nk0_sg.bin ignored. PRODUCT_COPY_FILES device/softwinner/nuclear-common/googleservice/gapps-jb-20121130-signed/system/tts/lang_pico/fr-FR_ta.bin:system/tts/lang_pico/fr-FR_ta.bin ignored. PRODUCT_COPY_FILES device/softwinner/nuclear-common/googleservice/gapps-jb-20121130-signed/system/tts/lang_pico/de-DE_gl0_sg.bin:system/tts/lang_pico/de-DE_gl0_sg.bin ignored. PRODUCT_COPY_FILES device/softwinner/nuclear-common/googleservice/gapps-jb-20121130-signed/system/tts/lang_pico/it-IT_cm0_sg.bin:system/tts/lang_pico/it-IT_cm0_sg.bin ignored. PRODUCT_COPY_FILES device/softwinner/nuclear-common/googleservice/gapps-jb-20121130-signed/system/tts/lang_pico/it-IT_ta.bin:system/tts/lang_pico/it-IT_ta.bin ignored. PRODUCT_COPY_FILES device/softwinner/nuclear-common/googleservice/gapps-jb-20121130-signed/system/tts/lang_pico/de-DE_ta.bin:system/tts/lang_pico/de-DE_ta.bin ignored. No private recovery resources for TARGET_DEVICE nuclear-evb make: Entering directory `/home/rootroot/wyb/pcf8563_i2c1_r8_ruoge_ov2640/android' target thumb C: i2c-util cd R:\wyb\pcf8563_i2c1_r8_ruoge_ov2640\android\out\target\product\nuclear-evb\system\bin C:\Users\Administrator.USER-20150913SZ>r: R:\wyb\pcf8563_i2c1_r8_ruoge_ov2640\android\out\target\product\nuclear-evb\system\bin>adb remount remount succeeded R:\wyb\pcf8563_i2c1_r8_ruoge_ov2640\android\out\target\product\nuclear-evb\system\bin> R:\wyb\pcf8563_i2c1_r8_ruoge_ov2640\android\out\target\product\nuclear-evb\system\bin>dir i2c* 驱动器 R 中的卷是 rootroot 卷的序列号是 1A1C-E71D R:\wyb\pcf8563_i2c1_r8_ruoge_ov2640\android\out\target\product\nuclear-evb\system\bin 的目录 2016/06/26 21:10 5,388 i2c-util 1 个文件 5,388 字节 0 个目录 268,337,782,784 可用字节 R:\wyb\pcf8563_i2c1_r8_ruoge_ov2640\android\out\target\product\nuclear-evb\system\bin> R:\wyb\pcf8563_i2c1_r8_ruoge_ov2640\android\out\target\product\nuclear-evb\system\bin>adb push i2c-util /data/ 29 KB/s (5388 bytes in 0.180s) R:\wyb\pcf8563_i2c1_r8_ruoge_ov2640\android\out\target\product\nuclear-evb\system\bin> 将R8的串口连接到windows电脑上。通过串口工具:比如Xshell5(有些人可能喜欢使用SecureCRT)读取R8的串口打印 (ubuntu下请使用minicom,使用方法请自行搜索了) 波特率选择:115200 N 8 1 等R8的android启动完成之后(LCD进android主界面),输入:su [ 37.990060] init: process 'ril-daemon', pid 950 exited [ 38.010049] init: process 'ril-daemon' killing any children in process group su root@android:/ # root@android:/ # root@android:/ # cd /data root@android:/data # root@android:/data # ll drwxrwxr-x system system 1970-01-11 08:58 anr drwxrwx--x system system 1970-01-02 08:01 app drwx------ root root 1980-10-01 11:03 app-asec drwxrwx--x system system 1970-01-02 08:01 app-lib drwxrwx--x system system 1980-10-01 11:03 app-private drwx------ system system 1980-10-01 11:04 backup drwxrwx--x system system 1970-01-02 08:00 dalvik-cache drwxrwx--x system system 2016-06-21 10:11 data drwxr-x--- root log 1980-10-01 11:03 dontpanic drwxrwx--- drm drm 1980-10-01 11:04 drm -rw-rw-rw- root root 5388 2016-06-26 21:10 i2c-util drwxr-x--x root root 1980-10-01 11:03 local drwxrwx--- root root 1970-01-01 08:00 lost+found drwxrwx--- media_rw media_rw 1980-10-01 11:03 media drwxrwx--t system misc 1980-10-01 11:03 misc -rw------- system system 154 1970-01-02 08:02 pointercal drwx------ root root 1970-01-02 08:00 property -rwxrwxrwx root root 5392 2016-06-25 13:01 read_pcf8563 drwxrwx--x system system 1980-10-01 11:03 resource-cache drwxr-x--- root shell 1980-10-01 11:03 ssh drwxrwxr-x system system 1970-01-02 08:00 system drwx------ system system 1970-01-02 08:03 tombstones drwx--x--x system system 1980-10-01 11:03 user root@android:/data # (让i2c-util具有可执行权限:) root@android:/data # chmod 777 i2c-util root@android:/data # root@android:/data # ll i2c* -rwxrwxrwx root root 5388 2016-06-26 21:10 i2c-util root@android:/data # root@android:/data # root@android:/data # (可选执行) root@android:/data # sync root@android:/data # 注意:串口打印会打印很多log信息。上面的步骤中的状态信息已经被过滤了。 如果你的串口打印过量的log信息,属于正常现象! 如果不想要这么多的状态信息,可以考虑使用adb shell。 不过windows命令行中的adb shell不能够按TAB键自动补充,ubuntu的可以。 也许我们可以把windows的命令行特别设计一下(给它修正一下),让它也可以通过按TAB键来自动补全!^_ 读取pcf8563的第2个寄存器(秒钟值): 表 5:BCD 格式寄存器概况 标明“-”的位无效 地址 寄存器名称 Bit7 Bit6 Bit5 Bit4 Bit3 Bit2 Bit1 Bit0 02h 秒 VL 00~59BCD 码格式数 root@android:/data # ./i2c-util /dev/i2c-1 0x51 0x02 0 read salve:51 reg:02 Read /dev/i2c-1-51 reg 2, read value:11 root@android:/data # ./i2c-util /dev/i2c-1 0x51 0x02 0 read salve:51 reg:02 Read /dev/i2c-1-51 reg 2, read value:12 root@android:/data # ./i2c-util /dev/i2c-1 0x51 0x02 0 read salve:51 reg:02 Read /dev/i2c-1-51 reg 2, read value:12 root@android:/data # ./i2c-util /dev/i2c-1 0x51 0x02 0 read salve:51 reg:02 Read /dev/i2c-1-51 reg 2, read value:13 root@android:/data # ./i2c-util /dev/i2c-1 0x51 0x02 0 read salve:51 reg:02 Read /dev/i2c-1-51 reg 2, read value:14 root@android:/data # ./i2c-util /dev/i2c-1 0x51 0x02 0 read salve:51 reg:02 Read /dev/i2c-1-51 reg 2, read value:14 root@android:/data # ./i2c-util /dev/i2c-1 0x51 0x02 0 read salve:51 reg:02 Read /dev/i2c-1-51 reg 2, read value:15 可以知道秒钟的值是变化的,基本上是一秒钟递增一次,I2C读取成功。 如果感兴趣的话,在执行读取命令的时候通过协议分析仪或者示波器来抓取I2C1的SCL/SDA的波形,来进行更加详尽的分析!^_ 方法二: 给出了一种复杂的解决办法(步骤从简,更多请参考开头的方法): R:\wyb\pcf8563_i2c1_r8_ruoge_ov2640\lichee\linux-3.4\drivers\rtc\rtc-sun5i.c 给这个驱动文件增加设备节点:/dev/a20_r8_pcf8563 增加设备节点的方法请参考: http://blog.csdn.net/mirkerson/article/details/8844997 android驱动学习---led实验 然后在这个驱动文件的pcf8563_probe函数处截获它的client指针(struct i2c_client *client) client2 = client; 用户可以通过在userspace直接访问设备节点:/dev/a20_r8_pcf8563(open) 然后调用ioctl:ioctl(fd, 0x00000001, 0x02); 来获取第2个寄存器:秒钟的值了。 #include #include #include #include #include #include #include #include #include #include #include int fd; int main(int argc, char **argv) { fd = open("/dev/a20_r8_pcf8563", O_RDWR); ioctl(fd, 0x00000001, 0x02); close(fd); return 0; } 执行过程(直接从内核打印秒钟值了,也可以看到秒钟值大概也是一秒钟递增一次!): root@android:/data # root@android:/data # ./read_pcf8563 [ 1397.060015] ****wyb drivers/rtc/rtc-sun5i.c:1169/r8_pcf8563_open()! open init.... [ 1397.071009] ****wyb drivers/rtc/rtc-sun5i.c:1130/r8_pcf8563_ioctl()! cmd=0x00000001 [ 1397.079076] ****wyb drivers/rtc/rtc-sun5i.c:1160/r8_pcf8563_ioctl()! cmd=0x00000001, value=0x00000046 [ 1397.088342] ****wyb drivers/rtc/rtc-sun5i.c:1177/r8_pcf8563_close()! close init root@android:/data # root@android:/data # ./read_pcf8563 [ 1398.409888] ****wyb drivers/rtc/rtc-sun5i.c:1169/r8_pcf8563_open()! open init.... [ 1398.411203] ****wyb drivers/rtc/rtc-sun5i.c:1130/r8_pcf8563_ioctl()! cmd=0x00000001 [ 1398.419273] ****wyb drivers/rtc/rtc-sun5i.c:1160/r8_pcf8563_ioctl()! cmd=0x00000001, value=0x00000047 [ 1398.428546] ****wyb drivers/rtc/rtc-sun5i.c:1177/r8_pcf8563_close()! close init root@android:/data # root@android:/data # root@android:/data # ./read_pcf8563 [ 1399.668173] ****wyb drivers/rtc/rtc-sun5i.c:1169/r8_pcf8563_open()! open init.... [ 1399.670939] ****wyb drivers/rtc/rtc-sun5i.c:1130/r8_pcf8563_ioctl()! cmd=0x00000001 [ 1399.679022] ****wyb drivers/rtc/rtc-sun5i.c:1160/r8_pcf8563_ioctl()! cmd=0x00000001, value=0x00000048 [ 1399.688299] ****wyb drivers/rtc/rtc-sun5i.c:1177/r8_pcf8563_close()! close init root@android:/data #
评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Acuity.

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值