0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

基于AP3216C芯片的三合一整合型光感測器設(shè)計

電子設(shè)計 ? 來源:面板板社區(qū) ? 作者:嵌入式大雜燴 ? 2021-03-26 16:07 ? 次閱讀

1、前言

開發(fā)板上有AP3216三合一整合型光感測器,看了看出廠SDK包中并未添加相關(guān)驅(qū)動。本次我們就一起來學(xué)習(xí)一下。

2、AP3216簡介

AP3216C 芯片集成了光強傳感器( ALS: Ambient Light Sensor),接近傳感器( PS: Proximity Sensor),還有一個紅外 LED( IR LED)。

這個芯片設(shè)計的用途是給手機之類的使用,比如:返回當(dāng)前環(huán)境光強以便調(diào)整屏幕亮度;用戶接聽電話時,將手機放置在耳邊后,自動關(guān)閉屏幕避免用戶誤觸碰 。

該芯片通過 I2C 接口與主控制器相連, 如:

pIYBAGBdlbOAIL6PAADkkj4qYmo904.png

3、IIC驅(qū)動簡介

Linux下IIC有兩種驅(qū)動方式:一種是按照字符設(shè)備驅(qū)動方式來驅(qū)動IIC;另一種是走Linux下IIC的框架。按照字符設(shè)備驅(qū)動的方式可以查閱這一篇文章:Linux IIC 字符設(shè)備 驅(qū)動例子。

這里我們淺淺地(真的很淺~~)了解學(xué)習(xí)一下第二種方式,因為找到的AP3216的驅(qū)動就是基于IIC驅(qū)動框架的,哈哈。

IIC驅(qū)動框架圖如

IIC驅(qū)動框架可大體分為兩大部分:

① I2C 總線驅(qū)動:SOC 的 I2C 控制器驅(qū)動,也叫做 I2C 適配器驅(qū)動。

② I2C 設(shè)備驅(qū)動:針對具體的 I2C 設(shè)備而編寫的驅(qū)動。

其中,訪問抽象層與I2C核心層數(shù)據(jù)I2C 總線驅(qū)動部分;driver驅(qū)動層屬于I2C設(shè)備驅(qū)動部分。

上面框圖對應(yīng)的代碼調(diào)用層次圖如:

下面的AP3216驅(qū)動可以對照這張圖來看看。

4、AP3216實驗

我們使用設(shè)備樹來描述AP3216設(shè)備信息,首先我們沒有在設(shè)備樹中添加AP3216相關(guān)節(jié)點時,我們系統(tǒng)的I2C設(shè)備如:

添加I2C pinctrl,板子上AP3216接的是I2C1:

配置寄存器的值都設(shè)為0x4001b8b0,這一段是什么意思我們在什么是Pinctrl子系統(tǒng)及GPIO子系統(tǒng)?這篇筆記中也有寫到,就是幾個寄存器及其配置。

接下來在i2c1節(jié)點下添加ap3216節(jié)點:

編譯設(shè)備樹,傳到開發(fā)板上,重啟。此時我們系統(tǒng)的I2C設(shè)備有:

可見,新增的AP3216 I2C設(shè)備名就是我們設(shè)備樹里設(shè)置的。

下面編寫AP3216驅(qū)動(以下代碼來源于網(wǎng)絡(luò)):

ap3216.c:

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include"ap3216creg.h"
/***************************************************************
文件名:ap3216c.c
描述:AP3216C驅(qū)動程序
***************************************************************/
#defineAP3216C_CNT1
#defineAP3216C_NAME"ap3216c"

structap3216c_dev{
dev_tdevid;/*設(shè)備號*/
structcdevcdev;/*cdev*/
structclass*class;/*類*/
structdevice*device;/*設(shè)備*/
structdevice_node*nd;/*設(shè)備節(jié)點*/
intmajor;/*主設(shè)備號*/
void*private_data;/*私有數(shù)據(jù)*/
unsignedshortir,als,ps;/*三個光傳感器數(shù)據(jù)*/
};

staticstructap3216c_devap3216cdev;

/*
*@description:從ap3216c讀取多個寄存器數(shù)據(jù)
*@param-dev:ap3216c設(shè)備
*@param-reg:要讀取的寄存器首地址
*@param-val:讀取到的數(shù)據(jù)
*@param-len:要讀取的數(shù)據(jù)長度
*@return:操作結(jié)果
*/
staticintap3216c_read_regs(structap3216c_dev*dev,u8reg,void*val,intlen)
{
intret;
structi2c_msgmsg[2];
structi2c_client*client=(structi2c_client*)dev->private_data;

/*msg[0]為發(fā)送要讀取的首地址*/
msg[0].addr=client->addr;/*ap3216c地址*/
msg[0].flags=0;/*標(biāo)記為發(fā)送數(shù)據(jù)*/
msg[0].buf=®/*讀取的首地址*/
msg[0].len=1;/*reg長度*/

/*msg[1]讀取數(shù)據(jù)*/
msg[1].addr=client->addr;/*ap3216c地址*/
msg[1].flags=I2C_M_RD;/*標(biāo)記為讀取數(shù)據(jù)*/
msg[1].buf=val;/*讀取數(shù)據(jù)緩沖區(qū)*/
msg[1].len=len;/*要讀取的數(shù)據(jù)長度*/

ret=i2c_transfer(client->adapter,msg,2);
if(ret==2){
ret=0;
}else{
printk("i2crdfailed=%dreg=%06xlen=%d\n",ret,reg,len);
ret=-EREMOTEIO;
}
returnret;
}

/*
*@description:向ap3216c多個寄存器寫入數(shù)據(jù)
*@param-dev:ap3216c設(shè)備
*@param-reg:要寫入的寄存器首地址
*@param-val:要寫入的數(shù)據(jù)緩沖區(qū)
*@param-len:要寫入的數(shù)據(jù)長度
*@return:操作結(jié)果
*/
statics32ap3216c_write_regs(structap3216c_dev*dev,u8reg,u8*buf,u8len)
{
u8b[256];
structi2c_msgmsg;
structi2c_client*client=(structi2c_client*)dev->private_data;

b[0]=reg;/*寄存器首地址*/
memcpy(&b[1],buf,len);/*將要寫入的數(shù)據(jù)拷貝到數(shù)組b里面*/

msg.addr=client->addr;/*ap3216c地址*/
msg.flags=0;/*標(biāo)記為寫數(shù)據(jù)*/

msg.buf=b;/*要寫入的數(shù)據(jù)緩沖區(qū)*/
msg.len=len+1;/*要寫入的數(shù)據(jù)長度*/

returni2c_transfer(client->adapter,&msg,1);
}

/*
*@description:讀取ap3216c指定寄存器值,讀取一個寄存器
*@param-dev:ap3216c設(shè)備
*@param-reg:要讀取的寄存器
*@return:讀取到的寄存器值
*/
staticunsignedcharap3216c_read_reg(structap3216c_dev*dev,u8reg)
{
u8data=0;

ap3216c_read_regs(dev,reg,&data,1);
returndata;

#if0
structi2c_client*client=(structi2c_client*)dev->private_data;
returni2c_smbus_read_byte_data(client,reg);
#endif
}

/*
*@description:向ap3216c指定寄存器寫入指定的值,寫一個寄存器
*@param-dev:ap3216c設(shè)備
*@param-reg:要寫的寄存器
*@param-data:要寫入的值
*@return:無
*/
staticvoidap3216c_write_reg(structap3216c_dev*dev,u8reg,u8data)
{
u8buf=0;
buf=data;
ap3216c_write_regs(dev,reg,&buf,1);
}

/*
*@description :讀取AP3216C的數(shù)據(jù),讀取原始數(shù)據(jù),包括ALS,PS和IR, 注意!
*:如果同時打開ALS,IR+PS的話兩次數(shù)據(jù)讀取的時間間隔要大于112.5ms
*@param-ir:ir數(shù)據(jù)
*@param-ps:ps數(shù)據(jù)
*@param-ps:als數(shù)據(jù)
*@return :無。
*/
voidap3216c_readdata(structap3216c_dev*dev)
{
unsignedchari=0;
unsignedcharbuf[6];

/*循環(huán)讀取所有傳感器數(shù)據(jù)*/
for(i=0;iir=0;
else/*讀取IR傳感器的數(shù)據(jù)*/
dev->ir=((unsignedshort)buf[1]<als=((unsignedshort)buf[3]<ps=0;
else/*讀取PS傳感器的數(shù)據(jù)*/
dev->ps=((unsignedshort)(buf[5]&0X3F)<private_data=&ap3216cdev;

/*初始化AP3216C*/
ap3216c_write_reg(&ap3216cdev,AP3216C_SYSTEMCONG,0x04);/*復(fù)位AP3216C*/
mdelay(50);/*AP3216C復(fù)位最少10ms*/
ap3216c_write_reg(&ap3216cdev,AP3216C_SYSTEMCONG,0X03);/*開啟ALS、PS+IR*/
return0;
}

/*
*@description:從設(shè)備讀取數(shù)據(jù)
*@param-filp:要打開的設(shè)備文件(文件描述符)
*@param-buf:返回給用戶空間的數(shù)據(jù)緩沖區(qū)
*@param-cnt:要讀取的數(shù)據(jù)長度
*@param-offt:相對于文件首地址的偏移
*@return:讀取的字節(jié)數(shù),如果為負(fù)值,表示讀取失敗
*/
staticssize_tap3216c_read(structfile*filp,char__user*buf,size_tcnt,loff_t*off)
{
shortdata[3];
longerr=0;

structap3216c_dev*dev=(structap3216c_dev*)filp->private_data;

ap3216c_readdata(dev);

data[0]=dev->ir;
data[1]=dev->als;
data[2]=dev->ps;
err=copy_to_user(buf,data,sizeof(data));
return0;
}

/*
*@description:關(guān)閉/釋放設(shè)備
*@param-filp:要關(guān)閉的設(shè)備文件(文件描述符)
*@return:0成功;其他失敗
*/
staticintap3216c_release(structinode*inode,structfile*filp)
{
return0;
}

/*AP3216C操作函數(shù)*/
staticconststructfile_operationsap3216c_ops={
.owner=THIS_MODULE,
.open=ap3216c_open,
.read=ap3216c_read,
.release=ap3216c_release,
};

/*
*@description:i2c驅(qū)動的probe函數(shù),當(dāng)驅(qū)動與
*設(shè)備匹配以后此函數(shù)就會執(zhí)行
*@param-client:i2c設(shè)備
*@param-id:i2c設(shè)備ID
*@return:0,成功;其他負(fù)值,失敗
*/
staticintap3216c_probe(structi2c_client*client,conststructi2c_device_id*id)
{
/*1、構(gòu)建設(shè)備號*/
if(ap3216cdev.major){
ap3216cdev.devid=MKDEV(ap3216cdev.major,0);
register_chrdev_region(ap3216cdev.devid,AP3216C_CNT,AP3216C_NAME);
}else{
alloc_chrdev_region(&ap3216cdev.devid,0,AP3216C_CNT,AP3216C_NAME);
ap3216cdev.major=MAJOR(ap3216cdev.devid);
}

/*2、注冊設(shè)備*/
cdev_init(&ap3216cdev.cdev,&ap3216c_ops);
cdev_add(&ap3216cdev.cdev,ap3216cdev.devid,AP3216C_CNT);

/*3、創(chuàng)建類*/
ap3216cdev.class=class_create(THIS_MODULE,AP3216C_NAME);
if(IS_ERR(ap3216cdev.class)){
returnPTR_ERR(ap3216cdev.class);
}

/*4、創(chuàng)建設(shè)備*/
ap3216cdev.device=device_create(ap3216cdev.class,NULL,ap3216cdev.devid,NULL,AP3216C_NAME);
if(IS_ERR(ap3216cdev.device)){
returnPTR_ERR(ap3216cdev.device);
}

ap3216cdev.private_data=client;

return0;
}

/*
*@description:i2c驅(qū)動的remove函數(shù),移除i2c驅(qū)動的時候此函數(shù)會執(zhí)行
*@param-client:i2c設(shè)備
*@return:0,成功;其他負(fù)值,失敗
*/
staticintap3216c_remove(structi2c_client*client)
{
/*刪除設(shè)備*/
cdev_del(&ap3216cdev.cdev);
unregister_chrdev_region(ap3216cdev.devid,AP3216C_CNT);

/*注銷掉類和設(shè)備*/
device_destroy(ap3216cdev.class,ap3216cdev.devid);
class_destroy(ap3216cdev.class);
return0;
}

/*傳統(tǒng)匹配方式ID列表*/
staticconststructi2c_device_idap3216c_id[]={
{"iot,ap3216c",0},
{}
};

/*設(shè)備樹匹配列表*/
staticconststructof_device_idap3216c_of_match[]={
{.compatible="iot,ap3216c"},
{/*Sentinel*/}
};

/*i2c驅(qū)動結(jié)構(gòu)體*/
staticstructi2c_driverap3216c_driver={
.probe=ap3216c_probe,
.remove=ap3216c_remove,
.driver={
.owner=THIS_MODULE,
.name="ap3216c",
.of_match_table=ap3216c_of_match,
},
.id_table=ap3216c_id,
};

/*
*@description:驅(qū)動入口函數(shù)
*@param:無
*@return:無
*/
staticint__initap3216c_init(void)
{
intret=0;

ret=i2c_add_driver(&ap3216c_driver);
returnret;
}

/*
*@description:驅(qū)動出口函數(shù)
*@param:無
*@return:無
*/
staticvoid__exitap3216c_exit(void)
{
i2c_del_driver(&ap3216c_driver);
}

/*module_i2c_driver(ap3216c_driver)*/

module_init(ap3216c_init);
module_exit(ap3216c_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("pjw");

驅(qū)動詳解可查閱注釋及配合上訴的I2C驅(qū)動框架的框圖及數(shù)據(jù)手冊理解。

ap3216creg.h:

#ifndefAP3216C_H
#defineAP3216C_H
/***************************************************************
文件名:ap3216creg.h
描述:AP3216C寄存器地址描述頭文件
***************************************************************/
#defineAP3216C_ADDR0X1E/*AP3216C器件地址*/
/*AP3316C寄存器*/
#defineAP3216C_SYSTEMCONG0x00/*配置寄存器*/
#defineAP3216C_INTSTATUS0X01/*中斷狀態(tài)寄存器*/
#defineAP3216C_INTCLEAR0X02/*中斷清除寄存器*/
#defineAP3216C_IRDATALOW0x0A/*IR數(shù)據(jù)低字節(jié)*/
#defineAP3216C_IRDATAHIGH0x0B/*IR數(shù)據(jù)高字節(jié)*/
#defineAP3216C_ALSDATALOW0x0C/*ALS數(shù)據(jù)低字節(jié)*/
#defineAP3216C_ALSDATAHIGH0X0D/*ALS數(shù)據(jù)高字節(jié)*/
#defineAP3216C_PSDATALOW0X0E/*PS數(shù)據(jù)低字節(jié)*/
#defineAP3216C_PSDATAHIGH0X0F/*PS數(shù)據(jù)高字節(jié)*/
#endif

ap3216應(yīng)用:

ap3216cApp.c:

#include"stdio.h"
#include"unistd.h"
#include"sys/types.h"
#include"sys/stat.h"
#include"sys/ioctl.h"
#include"fcntl.h"
#include"stdlib.h"
#include"string.h"
#include
#include
#include
#include
#include
/***************************************************************
文件名:ap3216cApp.c
描述: ap3216c設(shè)備測試APP。
使用方法:./ap3216cApp /dev/ap3216c
***************************************************************/

/*
*@description:main主程序
*@param-argc:argv數(shù)組元素個數(shù)
*@param-argv:具體參數(shù)
*@return:0成功;其他失敗
*/
intmain(intargc,char*argv[])
{
intfd;
char*filename;
unsignedshortdatabuf[3];
unsignedshortir,als,ps;
intret=0;

if(argc!=2){
printf("ErrorUsage!\r\n");
return-1;
}

filename=argv[1];
fd=open(filename,O_RDWR);
if(fd

編寫Makefile,從之前的文章=======拷貝過來修改:

KERN_DIR=/home/book/100ask_imx6ull-sdk/Linux-4.9.88

all:
make-C$(KERN_DIR)M=`pwd`modules
$(CROSS_COMPILE)gcc-oap3216cAppap3216cApp.c

clean:
make-C$(KERN_DIR)M=`pwd`modulesclean
rm-rfmodules.order
rm-fap3216cApp

#參考內(nèi)核源碼drivers/char/ipmi/Makefile
#要想把a.c,b.c編譯成ab.ko,可以這樣指定:
#ab-y:=a.ob.o
#obj-m+=ab.o

obj-m+=ap3216.o

編譯得到ap3216.ko及ap3216cApp,傳到板子上運行:

以上就是本次的實驗分享,如果文章對你有幫助,歡迎轉(zhuǎn)發(fā),謝謝!

參考資料

1、https://blog.csdn.net/weixin_34032792/article/details/85582751?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-2.control&dist_request_id=1328690.367.16165120737124801&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-2.control

2、https://blog.csdn.net/p1279030826/article/details/106459333

3、《嵌入式Linux應(yīng)用開發(fā)完全手冊》

編輯:hfy

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
  • 接近傳感器
    +關(guān)注

    關(guān)注

    5

    文章

    188

    瀏覽量

    24398
  • I2C
    I2C
    +關(guān)注

    關(guān)注

    28

    文章

    1477

    瀏覽量

    123104
  • I2C總線
    +關(guān)注

    關(guān)注

    8

    文章

    386

    瀏覽量

    60792
  • 光感測器
    +關(guān)注

    關(guān)注

    0

    文章

    5

    瀏覽量

    7126
收藏 人收藏

    評論

    相關(guān)推薦

    移動電源方案究竟硬件三合一還是軟件三合一?

    弄清楚。實際上移動電源三合一,分為硬件移動電源三合一和軟件移動電源三合一兩種技術(shù)路線。硬件三合一芯片主要存在的問題是:1.發(fā)熱嚴(yán)重,因為主
    發(fā)表于 09-15 22:57

    同步整流 移動電源三合一問題

    事件,真相如何?要解答這個問題,其根本是要把三合一移動電源解決方案不穩(wěn)定的原因弄清楚。 實際上移動電源三合一,分為硬件移動電源三合一和軟件移動電源三合一兩種技術(shù)路線。 硬件
    發(fā)表于 09-18 14:32

    移動電源硬件三合一方案和軟件三合一方案對比

    事件,真相如何?要解答這個問題,其根本是要把三合一移動電源解決方案不穩(wěn)定的原因弄清楚。實際上移動電源三合一,分為硬件移動電源三合一和軟件移動電源三合一兩種技術(shù)路線。硬件
    發(fā)表于 10-21 10:40

    新人提問:移動電源方案軟件三合一好還是硬件三合一好?

    新人提問:移動電源方案軟件三合一好還是硬件三合一好?剛開始做移動電源這行,時間不長,對于這個移動電源方案軟件三合一還是硬件三合一兩者的把握
    發(fā)表于 10-23 14:05

    雞、狗、貓三合一聲光玩具電路圖

    雞、狗、貓三合一聲光玩具電路圖
    發(fā)表于 05-21 13:31 ?889次閱讀
    雞、狗、貓<b class='flag-5'>三合一聲光</b>玩具電路圖

    Vishay推出首款三合一環(huán)境傳感 VCNL4000

    Vishay推出首款三合一環(huán)境傳感 VCNL4000 帶有I2C總線界面的短距離接近/環(huán)境傳感
    發(fā)表于 09-30 12:05 ?983次閱讀
    Vishay推出首款<b class='flag-5'>三合一</b>環(huán)境<b class='flag-5'>光</b>傳感<b class='flag-5'>器</b> VCNL4000

    三合一(溫濕)傳感設(shè)計

    本設(shè)計采用SHT11溫濕度傳感芯片款集成了ADC的環(huán)境傳感MAX9635,實現(xiàn)溫、濕度及光照
    發(fā)表于 07-16 10:38 ?4325次閱讀
    <b class='flag-5'>三合一</b>(溫濕<b class='flag-5'>光</b>)傳感<b class='flag-5'>器</b>設(shè)計

    環(huán)境溫濕度及光照三合一傳感器設(shè)計

    設(shè)計了基于I 2 C總線接口的全校準(zhǔn)數(shù)字式相對濕度、溫度傳感和環(huán)境三合一傳感器。其具有數(shù)字式輸出、免調(diào)試、免標(biāo)定、免外圍電路,提供I 2 C
    發(fā)表于 12-07 14:25 ?99次下載
    環(huán)境溫濕度及光照<b class='flag-5'>三合一傳感器</b>設(shè)計

    移動電源三合一方案解析_移動電源三合一方案的優(yōu)點介紹

    本文主要介紹移動電源三合一方案解析_移動電源三合一方案的優(yōu)點介紹。移動電源三合一方案,是指主控芯片移動電源MCU無需外掛DC-DC芯片和充電
    發(fā)表于 12-29 15:00 ?9877次閱讀
    移動電源<b class='flag-5'>三合一</b>方案解析_移動電源<b class='flag-5'>三合一</b>方案的優(yōu)點介紹

    移動電源三合一方案都有哪些_移動電源三合一方案哪種最穩(wěn)定

    、ZS6288/A三合一同步升壓移動電源專用芯片,ZS6599三合一移動電源專用芯片這幾種方案都是可以的,穩(wěn)定性有保障。
    發(fā)表于 12-29 15:22 ?1.7w次閱讀
    移動電源<b class='flag-5'>三合一</b>方案都有哪些_移動電源<b class='flag-5'>三合一</b>方案哪種最穩(wěn)定

    MPort 100IE三合一隔離Modbus網(wǎng)關(guān)

    電子發(fā)燒友網(wǎng)站提供《MPort 100IE三合一隔離Modbus網(wǎng)關(guān).pdf》資料免費下載
    發(fā)表于 10-17 09:23 ?0次下載
    MPort 100IE<b class='flag-5'>三合一</b>隔離<b class='flag-5'>型</b>Modbus網(wǎng)關(guān)

    三合一智能音箱演示

    三合一智能音箱演示
    發(fā)表于 03-15 19:54 ?0次下載
    <b class='flag-5'>三合一</b>智能音箱演示

    AP3216C三合一環(huán)境傳感器使用指南

    博主最近在調(diào)試 AP3216C 三合一環(huán)境傳感,由敦南科技推出的款傳感,支持環(huán)境光強度(ALS)、接近距離(PS)和紅外線強度(IR)
    的頭像 發(fā)表于 04-17 18:01 ?9225次閱讀
    <b class='flag-5'>AP3216C</b><b class='flag-5'>三合一</b>環(huán)境傳感器使用指南

    三合一智能音箱演示

    三合一智能音箱演示
    發(fā)表于 07-06 19:03 ?0次下載
    <b class='flag-5'>三合一</b>智能音箱演示

    WH4530A三合一 接近傳感芯片

    由工采網(wǎng)代理的臺灣旺泓-WH4530A是款集成了環(huán)境傳感(PS)接近傳感(ALS)和紅外LED燈三合一
    的頭像 發(fā)表于 02-26 10:58 ?466次閱讀
    WH4530A<b class='flag-5'>三合一</b><b class='flag-5'>光</b>距<b class='flag-5'>感</b> 接近傳感<b class='flag-5'>芯片</b>