瑞芯微Rockchip开发者社区
直播中

李军

8年用户 1300经验值
私信 关注
[问答]

基于RK3399Pro的BH1750驱动程序开发流程是怎样的呢

BH1750是什么?BH1750数字光照度传感器是如何工作的?基于RK3399Pro的BH1750驱动程序开发流程是怎样的呢?


回帖(1)

李岩

2022-2-14 15:19:38
1、BH1750基础知识

BH1750是数字光照度传感器,IIC总线接口,常用于手机的LCD的背光中,取值范围1-65535lx
1.1、模块工作原理图



  • PD,感光材料
  • AMP,运放电路转换为当前的电压值
  • ADC,AD转换为16位的数值
  • Logic+I2C接口,IIC接口,如果ADDR接高电平则从机地址为1011100+0/1,低电平则从机地址为0100011+0/1
  • OSC,内部逻辑的CLK
1.2、原理图


通过原理图,确定ADDR地址为0x46+1/0
1.3、常用的地址寄存器

[tr]InstructionOpecodeComments[/tr]
Power On0000_0001等待测量指令
Continuously H-Resolution Mode0001_0000测量的精确到1lx,转换时间120ms
Continuously H-Resolution Mode20001_0001测量的精确到0.5lx,转换时间120ms
Continuously L-Resolution Mode0001_0011测量的精确到4lx,转换时间16ms
1.4、获取光照度值

当ADDR=L的时候
写寄存器指令-工作模式H-resolution

等待一会儿,时间不要超过180ms
从模块读数据指令

1.5、程序开发流程图




2、代码编写
2.1修改内核的dts源文件
设备树路径:
arch/arm64/boot/dts/rockchip/rk3399pro-toybrick-prop-linux.dts
添加设备节点
&i2c6 {
        status = "okay";
        i2c-scl-rising-time-ns = <300>;
        i2c-scl-falling-time-ns = <15>;
        clock-frequency=<400000>;
        ina219x47c6: ina219@47 {
                     status = "okay";
                     compatible = "ina219";
                     reg = <0x47>;
        };
        bh1750:bh1750@46{
                status = "okay";
                compatible = "bh1750";
                reg = <0x46>
        };
};
2.2、编写驱动文件
2.2.1、I2C读写接口
static int i2c_read_byte(struct i2c_client * client, uint8_t reg, uint8_t * buf, int len)
{
struct i2c_msg msgs[2];
    msgs[0].addr = client->addr;
    msgs[0].flags = 0;
    msgs[0].len = 1;
    msgs[0].buf = ®
    msgs[1].addr = client->addr;
    msgs[1].flags = I2C_M_RD;
    msgs[1].len = len;
    msgs[1].buf = buf;
    if(i2c_transfer(client->adapter, msgs, 2) != 2)
     return 0;
    return 1;
}
static int i2c_write_byte(struct i2c_client * client, uint8_t reg, uint8_t buf)
{
struct i2c_msg msgs[2];
msgs[0].addr = client->addr;
msgs[0].flags = 0;
msgs[0].len = 1;
msgs[0].buf = ®
msgs[1].addr = client->addr;
msgs[1].flags = 0;
msgs[1].len = 1;
msgs[1].buf = &buf;
    if(i2c_transfer(client->adapter, msgs, 2) != 2)
     return 0;
    return 1;
}
2.2.2、BH1750光照度读写函数
static ssize_t gec3399_light_read(struct file *filp, char __user *buf, size_t len, loff_t *off)
{
  int ret;
  char data_buf[4];
short value;
memset(data_buf, 0, sizeof(data_buf));
memset(&value, 0, sizeof(value));
//printk("<0>""sizeof(data_buf) = %dnsizeof(light() = %dn",sizeof(data_buf),sizeof(value));
ret = i2c_write_byte(bh1750_client,RDADDR,PWON);
if(ret ==0 )
{
printk("PWON i2c_write_byte errorrn");
}
ret = i2c_write_byte(bh1750_client,RDADDR,CH_RM);
if(ret ==0 )
{
printk("CH_RM i2c_write_byte errorrn");
}
msleep(250);
ret = i2c_read_byte(bh1750_client,RDADDR,data_buf,2);
if(ret != 1){
printk("<0>""%s %d i2c read byte data errn",__FUNCTION__,__LINE__);
return -1;
}
value = (data_buf[0]<<8) | (data_buf[1]<<0);
printk("<0>""value = %dn",value);
ret = copy_to_user(buf, &value, sizeof(value));
if(ret < 0){
printk("<0>""%s %d err copy light value to usern",__FUNCTION__,__LINE__);
return -EFAULT;
}
return ret;
}
2.2.3、BH1750的初始化入口函数
static const struct i2c_device_id i2c_id[] = {
{ "bh1750", 0 },
{ }, /* Terminating entry */
};
static struct of_device_id i2c_match[] = {
{.compatible = "bh1750" },
{ },
};
MODULE_DEVICE_TABLE(i2c, i2c_id);
static struct i2c_driver i2c_driver = {
.driver = {
.name = "bh1750",
.owner = THIS_MODULE,
.of_match_table = of_match_ptr(i2c_match),
},
.probe = i2c_probe,
.remove = i2c_remove,
.id_table = i2c_id,
};
module_i2c_driver(i2c_driver);
2.2.4、文件探索
static int i2c_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
int ret;
struct device_node *bh1750_node = NULL;
bh1750_client = client;
printk("The match successful!n");
printk("client->addr = %xn",client->addr);
ret = misc_register(&gec3399_bh1750_misc);   //×¢2á×?·?éè±?
if(ret < 0){
printk("misc register errorn");
goto err_register_error;
}
bh1750_node = of_find_compatible_node(NULL, NULL,"bh1750");
if(bh1750_node == NULL){
printk("not node of compatible is bh1750n");
ret = -ENODEV;
goto err_gpio_request;
}
printk("bh1750 dirve install succeen");
return 0;
err_gpio_request:
misc_deregister(&gec3399_bh1750_misc);
err_register_error:
return 0;
}
2.2.5、杂项设备
static struct miscdevice gec3399_bh1750_misc = {
.minor = MISC_DYNAMIC_MINOR,
.name = "light_drv",
.fops = &gec3399_light_fops,
};
2.2.6、文件操作集
通过文件操作集初始化BH1750的入口函数
static const struct file_operations gec3399_light_fops = {
.owner = THIS_MODULE,
.read = gec3399_light_read,
};
2.3、测试程序
#include
#include
#include
#include
#include
#include
#include
#include
int fd_light = 0;
short light_value;  
int main(void)
{
int ret;
//打开光照度设备节点1
fd_light = open("/dev/light_drv", O_RDWR);
if(fd_light < 0)
{
perror("open light_drv driver");
return -1;
}
while(1)
{
//读取光照度值
ret = read(fd_light,&light_value,2);
if(ret<0)
{
perror("read errorn");
return -1;
}
printf("light_value = %d n",light_value);
sleep(1);
}
close(fd_light);
return 0;
}
2.4、Makefile文件
obj-m += bh1750_drv.o
KERNELDIR:=/file/RK3399Pro/rk3399pro_git_repo/kernel
PWD:=$(shell pwd)
default:
$(MAKE)  -C $(KERNELDIR) M=$(PWD) modules
test:
aarch64-linux-gnu-gcc bh1750_test.c -o bh1750_test
clean:
rm -rf *.o *.order .*.cmd *.ko *.mod.c *.symvers *.tmp_versions
3、测试步骤
3.1、编译源码
在ubuntu中输入:
make
得到驱动目标文件bh1750_drv.ko
输入:
make test
得到测试目标文件:bh1750_test
3.2、加载驱动
在开发板命令终端输入:
insmod bh1750_drv.ko
3.3、执行测试程序
在开发板命令终端输入:
chmod 777 bh1750_test
./bh1750_test
4、实验现象
读取到光照度数据。
举报

更多回帖

发帖
×
20
完善资料,
赚取积分