• 详解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,编写如下代码

    1. /***************************************************************
    2. Copyright 2024-2029. All rights reserved.
    3. 文件名 : drv_ap3216c.c
    4. 作者 : tangmingfei2013@126.com
    5. 版本 : V1.0
    6. 描述 : ap3216c 驱动程序
    7. 其他 : 无
    8. 日志 : 初版V1.0 2024/02/01
    9. ***************************************************************/
    10. #include
    11. #include
    12. #include
    13. #include
    14. #include
    15. #include
    16. #include
    17. #include
    18. #include
    19. #include
    20. #include
    21. #include
    22. #include
    23. #include
    24. #include
    25. #include
    26. #include "drv_ap3216.h"
    27. #define DEV_FILE "/dev/i2c-0"
    28. static int fd = -1;
    29. static void msleep(unsigned int time)
    30. {
    31. struct timespec sleeper, temp;
    32. sleeper.tv_sec = (time_t)(time/1000);
    33. sleeper.tv_nsec = (long)(time%1000)*1000000;
    34. nanosleep(&sleeper, &temp);
    35. }
    36. static int ap3216c_write_reg( unsigned char reg, unsigned char cmd)
    37. {
    38. int ret = -1;
    39. unsigned char buf[2] = {0};
    40. buf[0] = reg;
    41. buf[1] = cmd;
    42. ret = write(fd, buf, 2);
    43. if( ret < 0 )
    44. {
    45. printf("write cmd to ap3216c register failure.\n");
    46. return -1;
    47. }
    48. return 0;
    49. }
    50. static int ap3216c_read_reg( unsigned char reg, unsigned char *val)
    51. {
    52. int ret = -1;
    53. unsigned char buf[1] = {0};
    54. buf[0] = reg; //send register address
    55. ret = write( fd, buf, 1);
    56. if( ret < 0 )
    57. {
    58. printf("write cmd to ap3216c register failure.\n");
    59. return -1;
    60. }
    61. ret = read(fd, buf, 1); //read data from the register
    62. if( ret < 0 )
    63. {
    64. printf("get the humidy failure.\n");
    65. return -1;
    66. }
    67. *val = buf[0];
    68. return 0;
    69. }
    70. void ap3216c_read_datas(ap3216c_data *pdata)
    71. {
    72. unsigned char i =0;
    73. unsigned char buf[6], val = 0;
    74. /* read all sensor‘ data */
    75. for( i = 0; i < 6; i++)
    76. {
    77. ap3216c_read_reg( AP3216C_IRDATALOW + i, &val);
    78. buf[i] = val;
    79. }
    80. /* IR */
    81. if(buf[0] & 0X80){ /* IR_OF位为1,则数据无效 */
    82. pdata->ir = 0;
    83. }
    84. else {
    85. pdata->ir = ((unsigned short)buf[1] << 2) | (buf[0] & 0X03);
    86. }
    87. /* ALS */
    88. pdata->als = ((unsigned short)buf[3] << 8) | buf[2];
    89. /* PS */
    90. if(buf[4] & 0x40){ /* IR_OF位为1,则数据无效 */
    91. pdata->ps = 0;
    92. }
    93. else{
    94. pdata->ps = ((unsigned short)(buf[5] & 0X3F) << 4) | (buf[4] & 0X0F);
    95. }
    96. }
    97. void ap3216c_release( void )
    98. {
    99. close( fd );
    100. }
    101. int ap3216c_init(void)
    102. {
    103. // init i2c
    104. fd = open(DEV_FILE, O_RDWR);
    105. if( fd < 0 )
    106. {
    107. close( fd );
    108. printf("%s %s i2c device open failure: %s\n", __FILE__, __FUNCTION__, strerror(errno));
    109. return -1;
    110. }
    111. ioctl(fd, I2C_TENBIT, 0);
    112. ioctl(fd, I2C_SLAVE, AP3216C_ADDR);
    113. // reset sensor
    114. ap3216c_write_reg( AP3216C_SYSTEMCONG, 0x04);
    115. msleep(2);
    116. // enable ALS、PS+IR
    117. ap3216c_write_reg( AP3216C_SYSTEMCONG, 0X03);
    118. msleep(2);
    119. return fd;
    120. }

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

    1. #ifndef __DRV__AP3216_H
    2. #define __DRV__AP3216_H
    3. #ifdef __cplusplus
    4. extern "C" {
    5. #endif
    6. #define AP3216C_ADDR 0X1E
    7. /* AP3316C寄存器 */
    8. #define AP3216C_SYSTEMCONG 0x00 /* 配置寄存器 */
    9. #define AP3216C_INTSTATUS 0X01 /* 中断状态寄存器 */
    10. #define AP3216C_INTCLEAR 0X02 /* 中断清除寄存器 */
    11. #define AP3216C_IRDATALOW 0x0A /* IR数据低字节 */
    12. #define AP3216C_IRDATAHIGH 0x0B /* IR数据高字节 */
    13. #define AP3216C_ALSDATALOW 0x0C /* ALS数据低字节 */
    14. #define AP3216C_ALSDATAHIGH 0X0D /* ALS数据高字节 */
    15. #define AP3216C_PSDATALOW 0X0E /* PS数据低字节 */
    16. #define AP3216C_PSDATAHIGH 0X0F /* PS数据高字节 */
    17. typedef struct _ap3216c_data{
    18. unsigned short ir;
    19. unsigned short als;
    20. unsigned short ps; /* */
    21. }ap3216c_data;
    22. void ap3216c_read_datas(ap3216c_data *pdata);
    23. int ap3216c_init(void);
    24. #ifdef __cplusplus
    25. }
    26. #endif
    27. #endif /* __DRV__AP3216_H */

     3 编写测试代码

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

    3.1 测试代码实现

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

    1. /***************************************************************
    2. Copyright 2024-2029. All rights reserved.
    3. 文件名 : test_ap3216.c
    4. 作者 : tangmingfei2013@126.com
    5. 版本 : V1.0
    6. 描述 : 验证dev_ap3216.c
    7. 其他 : 无
    8. 日志 : 初版V1.0 2024/02/1
    9. ***************************************************************/
    10. #include
    11. #include
    12. #include
    13. #include
    14. #include
    15. #include
    16. #include
    17. #include
    18. #include
    19. #include
    20. #include
    21. #include
    22. #include
    23. #include
    24. #include
    25. #include
    26. #include "drv_ap3216.h"
    27. int main(void)
    28. {
    29. ap3216c_data stru_data;
    30. int count_run = 100;
    31. int set;
    32. set = ap3216c_init();
    33. if( set < 0){
    34. printf("initial ap3216c failure.\n");
    35. return -1;
    36. }
    37. while( count_run > 0){
    38. ap3216c_read_datas( &stru_data );
    39. printf("ir = %d, als = %d, ps = %d \r\n",
    40. stru_data.ir, stru_data.als, stru_data.ps);
    41. count_run--;
    42. sleep(1);
    43. }
    44. ap3216c_release();
    45. return 0;
    46. }

    3.2 Makefile

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

    1. CFLAGS= -Wall -O2
    2. CC=/home/ctools/gcc-linaro-4.9.4-arm-linux-gnueabihf/bin/arm-linux-gnueabihf-gcc
    3. STRIP=/home/ctools/gcc-linaro-4.9.4-arm-linux-gnueabihf/bin/arm-linux-gnueabihf-strip
    4. test_ap3216: test_ap3216.o drv_ap3216.o
    5. $(CC) $(CFLAGS) -o test_ap3216 test_ap3216.o drv_ap3216.o
    6. $(STRIP) -s test_ap3216
    7. clean:
    8. rm -f test_ap3216 test_ap3216.o drv_ap3216.o

    4 测试

    4.1 编译代码

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

    4.2 运行测试程序

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

  • 相关阅读:
    计算机毕业设计Javam和vue的酒店管理系统2021(源码+系统+mysql数据库+lw文档)
    基于STM32单片机的智能家居环境监测与控制系统设计
    hooks 内部结构
    【Rust 日报】2022-11-25 Rust 真的要上天了!
    opensbi firmware源码分析(2)
    SOAR安全事件编排自动化响应-安全运营实战
    Linux 指令心法(十一)`tail` 显示文本文件的末尾部分
    ElasticSearch总结二
    群接龙大团长有哪些,群接龙大团长如何对接?
    基于ssm的视力保养连锁预约系统设计与实现-计算机毕业设计源码+LW文档
  • 原文地址:https://blog.csdn.net/mftang/article/details/136222319