当前位置: 代码网 > 服务器>服务器>Linux > 详解AP3216C(三合一sensor: 光照、距离、照射强度)驱动开发

详解AP3216C(三合一sensor: 光照、距离、照射强度)驱动开发

2024年08月01日 Linux 我要评论
本文详细介绍AP3216C的特性,内部结构,操作时序和寄存器的参数意义,并使用linux platform tree 下i2c 驱动接口,实现了AP3216C的驱动程序。并且编写了一个测试范例,验证该驱动程序的性能。 其可以正确的读出sensor内部的数据。

目录

概述

1 认识ap3216c

1.1 ap3216c特性

1.2 ap3216c内部结构

1.3 ap3216c 硬件电路

1.4 ap3216c工作时序

1.4.1 i2c 写数据协议

1.4.2 i2c 读数据协议

1.5 重要的寄存器

1.5.1 系统配置寄存器

1.5.2 和中断相关寄存器

1.5.3 ir数据寄存器

1.5.4 als 数据寄存器

1.5.5 ps 数据寄存器

2 驱动开发

2.1 查看i2c总线下的设备

2.2 编写驱动代码 

 3 编写测试代码

3.1 测试代码实现

3.2 makefile

4 测试

4.1 编译代码

4.2 运行测试程序


概述

        本文详细介绍ap3216c的特性,内部结构,操作时序和寄存器的参数意义,并使用linux platform tree 下i2c 驱动接口,实现了ap3216c的驱动程序。并且编写了一个测试范例,验证该驱动程序的性能。 其可以正确的读出sensor内部的数据。

源代码下载地址: ap3216clinux环境下的驱动程序资源-csdn文库

1 认识ap3216c

1.1 ap3216c特性

ap3216c是敦南科技出品的一款集成sensor, 其中包括 :als(数字型环境光线感应 sensor),ps(测距sensor)ir(照射sensor)。这款sensor主要用在手机、平板电脑、电视、显示器、数码相机等产品上。

1)驱动方式: 采用标准的i2c接口,且工作在快速模式(400k hz)

2)输出模块可选: als, ps+ir, als+ps+ir, pd,als once, sw reset, ps+ir once and als+ps+ir once.

3) 高分辨率:

数字型环境光线感应 sensor ,采用 16-bit 有效数据输出,数据采集范围( 0~65535 )

测距sensor,采用 10-bit 有效数据输出, 数据采集范围( 0~1023 )

1.2 ap3216c内部结构

由下结构图可以看见: als和ps分别和adc模块连接,以采集外部数据 。ir本分隔在一个单独的模块。

1.3 ap3216c 硬件电路

ap3216c采用标准的i2c驱动模式,其和mcu之间通过3个线连接,sda和scl是i2c的驱动线,还提供一个中断引脚int

1.4 ap3216c工作时序

ap3216c采用标准的i2c驱动接口,其slave 设备地址为:0x1e

1.4.1 i2c 写数据协议

1) 写方式一: 写寄存器地址

s: start 信号

slave address : 7 bit

w: 写数据bit

a: ack信号

register address: 寄存器地址

p: stop信号

详细时序图:

2) 写方式二: 写寄存器地址 和数据

s: start 信号

slave address : 7 bit

w: 使能写数据bit

a: ack信号

register address: 寄存器地址

register command: 写寄存器数据

p: stop信号

详细时序图:

1.4.2 i2c 读数据协议

1) 读方式一: 读寄存器地址

s: start 信号

slave address : 7 bit

r: 使能读数据bit

a: ack信号

register command: 寄存器数据

n: nack信号

p: stop信号

详细时序图:

2) 读方式二: 读寄存器地址的数据

s: start 信号

slave address : 7 bit

r: 使能读数据bit

w: 使能写数据bit

a: ack信号

register command: 寄存器数据

n: nack信号

p: stop信号

详细时序图:

1.5 重要的寄存器

ap3216c内部有许多寄存器,其地址空间(0x00 ~ 0x2d ),由于篇幅所限,这里不对每个寄存器做一一介绍。如需了解,可参看文档:ap3216c rev0.86. pdf。 本文主要介绍系统寄存器部分,地址空间(0x00 ~ 0x0f。各个寄存器的功能,看下表:

1.5.1 系统配置寄存器

该寄存器地址位0x00, 低位3个bit(bit-0 bit-1,bit-2)用于配置系统工作模式

具体模式如下表:

1.5.2 和中断相关寄存器

中断状态寄存器: address = 0x01

bit-0: als-int 用来表示中断是否发生, b0=1 表示als中断被触发, b0 =0 示als中断未被被触发

bit-1: ps-int 用来表示中断是否发生, b0=1 表示ps中断被触发, b0 =0 示ps中断未被被触发

中断清除寄存器: address = 0x02

当配置clr_mnr = 0时, 在读取寄存器(0x0c, 0x0d, 0x0e, 0x0f)的值后,芯片会自动清除中断;

当配置clr_mnr = 1时,需要软件强制把寄存器0x01的对应位置位为1,清除中断;

1.5.3 ir数据寄存器

对应地址: 0x0a 和0x0b

0x0a地址中,bit0和bit1 为数据位,表示低字节位, ir_of为数据溢出标记,当ir_of=1, 表明ir值过高,其会影响ps的数据的有效性

0x0b地址中,为ir 数据高字节位

1.5.4 als 数据寄存器

对应地址: 0x0c 和0x0d

1.5.5 ps 数据寄存器

对应地址: 0x0e 和0x0f

ir_of = 1,表示读取的数据有效。ir_of = 0,表示读取的数据无效。

2 驱动开发

2.1 查看i2c总线下的设备

i2c总线上可以挂载多个device,其要求在同一条总线上,每个设备的地址必须唯一性。如果两个设备的地址一样,会出现时序混乱。 下面通过命令来探测一下i2c总线下的设备情况。

查看i2c-0下设备情况

使用命令

 i2cdetect -a 0

执行该命令后,列出设备地址信息: 该总线下有两个设备,其地址分别为:0x1a和0x1e

2.2 编写驱动代码 

创建drv_ap3216c.c,编写如下代码

/***************************************************************
copyright  2024-2029. all rights reserved.
文件名     : drv_ap3216c.c
作者       : tangmingfei2013@126.com
版本       : v1.0
描述       : ap3216c 驱动程序
其他       : 无
日志       : 初版v1.0 2024/02/01

***************************************************************/
#include <sys/types.h>
#include <sys/stat.h>
#include <linux/types.h>
#include <linux/i2c-dev.h>
#include <linux/i2c.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <stdlib.h>
#include <linux/fs.h>
#include <errno.h>
#include <assert.h>
#include <string.h>
#include <time.h>
#include "drv_ap3216.h"

#define dev_file               "/dev/i2c-0"


static int fd = -1;

static void msleep(unsigned int time)
{
    struct timespec sleeper, temp;

    sleeper.tv_sec = (time_t)(time/1000);
    sleeper.tv_nsec = (long)(time%1000)*1000000;
    nanosleep(&sleeper, &temp);
}

static int ap3216c_write_reg( unsigned char reg, unsigned char cmd)
{
    int              ret = -1;
    unsigned char    buf[2] = {0};

    buf[0] = reg;
    buf[1] = cmd;
    
    ret = write(fd, buf, 2);
    if( ret < 0 )
    {
        printf("write cmd to ap3216c register failure.\n");
        return -1;
    }
    
    return 0;
}

static int ap3216c_read_reg( unsigned char reg, unsigned char *val)
{
    int           ret = -1;
    unsigned char buf[1] = {0};

    buf[0] = reg;           //send register address 
    ret = write( fd, buf, 1);
    if( ret < 0 )
    {
        printf("write cmd to ap3216c register failure.\n");
        return -1;
    }
    
    ret = read(fd, buf, 1);  //read data from the register 
    if( ret < 0 )
    {
        printf("get the humidy failure.\n");
        return -1;
    }
    *val = buf[0];
    
    return 0;
}

void ap3216c_read_datas(ap3216c_data *pdata)
{
    unsigned char i =0;
    unsigned char buf[6], val = 0;
    
    /* read all sensor‘ data */
    for( i = 0; i < 6; i++)    
    {
        ap3216c_read_reg( ap3216c_irdatalow + i, &val); 
        buf[i] = val;
    }

     /* ir   */
    if(buf[0] & 0x80){  /* ir_of位为1,则数据无效 */
        pdata->ir = 0;
    }        
    else {        
        pdata->ir = ((unsigned short)buf[1] << 2) | (buf[0] & 0x03); 
    }        
    
    /* als  */  
    pdata->als = ((unsigned short)buf[3] << 8) | buf[2]; 
    
    /* ps */
    if(buf[4] & 0x40){    /* ir_of位为1,则数据无效 */
        pdata->ps = 0; 
    }        
    else{                
        pdata->ps = ((unsigned short)(buf[5] & 0x3f) << 4) | (buf[4] & 0x0f); 
    }
}

void ap3216c_release( void )
{
    close( fd );
}

int ap3216c_init(void)
{
    // init i2c 
    fd = open(dev_file, o_rdwr);
    if( fd < 0 )
    {
        close( fd );
        printf("%s %s i2c device open failure: %s\n", __file__, __function__, strerror(errno));
        return -1;
    }

    ioctl(fd, i2c_tenbit, 0);
    ioctl(fd, i2c_slave, ap3216c_addr);
    
    // reset sensor 
    ap3216c_write_reg( ap3216c_systemcong, 0x04);
    msleep(2);
    
    // enable als、ps+ir
    ap3216c_write_reg( ap3216c_systemcong, 0x03);
    msleep(2);
    
    return fd;
}

在drv_ap3216c.h中,编写如下代码:

#ifndef __drv__ap3216_h
#define __drv__ap3216_h

#ifdef __cplusplus
extern "c" {
#endif

#define ap3216c_addr          0x1e

/* ap3316c寄存器 */
#define ap3216c_systemcong    0x00    /* 配置寄存器       */
#define ap3216c_intstatus     0x01    /* 中断状态寄存器   */
#define ap3216c_intclear      0x02    /* 中断清除寄存器   */
#define ap3216c_irdatalow     0x0a    /* ir数据低字节     */
#define ap3216c_irdatahigh    0x0b    /* ir数据高字节     */
#define ap3216c_alsdatalow    0x0c    /* als数据低字节    */
#define ap3216c_alsdatahigh   0x0d    /* als数据高字节    */
#define ap3216c_psdatalow     0x0e    /* ps数据低字节     */
#define ap3216c_psdatahigh    0x0f    /* ps数据高字节     */

typedef struct _ap3216c_data{
   unsigned short ir; 
   unsigned short als; 
   unsigned short ps;      /* */ 
}ap3216c_data;

void ap3216c_read_datas(ap3216c_data *pdata);
int ap3216c_init(void);


#ifdef __cplusplus
}
#endif

#endif /* __drv__ap3216_h */

 3 编写测试代码

测试主要实现,调用驱动程序接口,读取als,ps,ir数据,并打印出来

3.1 测试代码实现

创建一个test_ap3216.c,编写如下代码:

/***************************************************************
copyright  2024-2029. all rights reserved.
文件名     : test_ap3216.c
作者       : tangmingfei2013@126.com
版本       : v1.0
描述       : 验证dev_ap3216.c 
其他       : 无
日志       : 初版v1.0 2024/02/1

***************************************************************/
#include <sys/types.h>
#include <sys/stat.h>
#include <linux/types.h>
#include <linux/i2c-dev.h>
#include <linux/i2c.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <stdlib.h>
#include <linux/fs.h>
#include <sys/ioctl.h>
#include <errno.h>
#include <assert.h>
#include <string.h>
#include <time.h>
#include "drv_ap3216.h"

int main(void)
{
    ap3216c_data stru_data;
    int count_run = 100;
    int set;

    set = ap3216c_init();
    if( set < 0){
        printf("initial ap3216c failure.\n");
        return -1;
    }

    while( count_run > 0){
        ap3216c_read_datas( &stru_data );
        
        printf("ir = %d, als = %d, ps = %d \r\n", 
               stru_data.ir, stru_data.als, stru_data.ps);
        count_run--;
        sleep(1);
    }

    ap3216c_release();

    return 0;
}

3.2 makefile

在测试程序的目录下,创建一个makefile文件,编写如下代码

cflags= -wall -o2
cc=/home/ctools/gcc-linaro-4.9.4-arm-linux-gnueabihf/bin/arm-linux-gnueabihf-gcc
strip=/home/ctools/gcc-linaro-4.9.4-arm-linux-gnueabihf/bin/arm-linux-gnueabihf-strip

test_ap3216: test_ap3216.o drv_ap3216.o
	$(cc) $(cflags) -o test_ap3216 test_ap3216.o drv_ap3216.o
	$(strip) -s test_ap3216

clean:
	rm -f test_ap3216 test_ap3216.o drv_ap3216.o

4 测试

4.1 编译代码

使用make命令编译代码,然后将生成的可执行文件copy到nfs的共享目录下,方便在板卡中运行程序。

4.2 运行测试程序

 运行测试程序,可以看见在终端上打印出来sensor的数据

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2025  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com