基于RK3399Pro的BH1750驱动开发

1、BH1750基础知识

BH1750是数字光照度传感器,IIC总线接口,常用于手机的LCD的背光中,取值范围1-65535lx

1.1、模块工作原理图

Block Diagram

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

1.2、原理图

BH1750
通过原理图,确定ADDR地址为0x46+1/0

1.3、常用的地址寄存器

Instruction Opecode Comments
Power On 0000_0001 等待测量指令
Continuously H-Resolution Mode 0001_0000 测量的精确到1lx,转换时间120ms
Continuously H-Resolution Mode2 0001_0001 测量的精确到0.5lx,转换时间120ms
Continuously L-Resolution Mode 0001_0011 测量的精确到4lx,转换时间16ms

1.4、获取光照度值

ADDR=L的时候
写寄存器指令-工作模式H-resolution
写指令
等待一会儿,时间不要超过180ms

从模块读数据指令

读取数据

1.5、程序开发流程图

Created with Raphaël 2.3.0 开始 打开电源:Power ON 设置模式:H-Resolution Mode 数据读取 数据正确? 反馈给上层应用 结束 yes no

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 = &reg;

    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 = &reg;
	
	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) = %d\nsizeof(light() = %d\n",sizeof(data_buf),sizeof(value));
	

	ret = i2c_write_byte(bh1750_client,RDADDR,PWON);
	if(ret ==0 )
	{
    
    
		printk("PWON i2c_write_byte error\r\n");
	}
	
	ret = i2c_write_byte(bh1750_client,RDADDR,CH_RM);
	if(ret ==0 )
	{
    
    
		printk("CH_RM i2c_write_byte error\r\n");
	}
	msleep(250);
	
	ret = i2c_read_byte(bh1750_client,RDADDR,data_buf,2);
	if(ret != 1){
    
    
		printk("<0>""%s %d i2c read byte data err\n",__FUNCTION__,__LINE__);
		return -1;
	}
	
	value = (data_buf[0]<<8) | (data_buf[1]<<0);
	printk("<0>""value = %d\n",value);
	
	
	
	ret = copy_to_user(buf, &value, sizeof(value));
	if(ret < 0){
    
    
		printk("<0>""%s %d err copy light value to user\n",__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 = %x\n",client->addr);
	ret = misc_register(&gec3399_bh1750_misc);   //×¢2á×?·?éè±?
	if(ret < 0){
    
    
		printk("misc register error\n");
		goto err_register_error;		
	}
	
	bh1750_node = of_find_compatible_node(NULL, NULL,"bh1750");
	if(bh1750_node == NULL){
    
    
		printk("not node of compatible is bh1750\n");
		ret = -ENODEV;
		goto err_gpio_request;
	}
	
	
		
	printk("bh1750 dirve install succee\n");
	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 <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <poll.h>

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 error\n");
			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、实验现象

读取到光照度数据

猜你喜欢

转载自blog.csdn.net/ZOROE123/article/details/117442036