Linux i2c设备驱动——BMP180

1. BMP180

  BMP180是博世(BOSCH)公司的一款气压传感器,内置EEPROM存储大气压和温度校准系数,以数据接口i2c对外连接处理器。


1.1 编程关键信息

【1】i2c从地址
  0x77(7bit有效地址,不包括读写位,Linux i2c总线驱动内部作读写位处理)
在这里插入图片描述
【2】校准系数
  处理器通过i2c读取BMP180的温度值和压力值是原始AD值,未经过校准补偿。每个BM180器件在出厂时都根据不同特性提供独有的校准系数,存储于内置EEPROM中,校准系数共176位(22字节)。处理器获得准确的气压值和温度值,首先应读取内置校准系数,将原始AD值和校准系数进行换算。BM180数据手册提供计算方式。

在这里插入图片描述
【3】寄存器

  • 校准系数寄存器
  • 原始AD值寄存器
  • 芯片唯一ID
  • 芯片复位

2. Linux BMP180驱动

  以下步骤为主要过程,有所省略,只标识出关键节点和注意事项,完整源码见文章末尾。


2.1 平台

编译系统:Ubuntu16.04
ARM硬件:firefly RK3399
ARM系统:firefly Ubuntu16.04(SDK)
Linux内核:Linux 4.4.179
连接i2c:i2c4

  首先需根据firefly官网提供的Ubuntu16 固件编译教程下载Linux SDK并同步源码。


2.2 修改设备树

  根据SDK编译脚本可知,RK3399板子使用的设备树位于“kernel/arch/arm64/boot/dts/rockchip/rk3399-firefly.dts”,经过层层挖掘,i2c总线相关设备树节点位于“rk3399-firefly.dts—>rk3399-firefly-port.dtsi —> rk3399-firefly-core.dtsi”,编辑“rk3399-firefly-core.dtsi”,在“i2c4”节点上依葫芦画瓢,添加bmp180节点,bmp180 i2c从地址为0x77。

  bmp180: bmp180@77{
                compatible = "bosch,bmp180";
                reg = <0x77>;
                status = "okay";
        };

  本次驱动测试是将bmp180驱动编译成模块(.ko),没有编译到内核中,因此到这一步就可以开始开始编译内核了,如果是首次编译,需要漫长的等待。编译完成,在kernel目录下生成“boot.img”,boot.img包括了内核(kernel.img)和设备树文件(resource.img)。通过官方烧录工具,选择更新boot分区。

在这里插入图片描述

2.3 bmp180_open接口

  用户在open“bmp180”驱动时,将芯片校准系数读出,用于后面read操作计算实际温度值和气压值

	bmp180_read_regs(pfile->private_data, BMS_CAL_AC1, bmbuf, 22);
	bmp180_clac_parm.ac1 = (bmbuf[0]<<8)|bmbuf[1];
	bmp180_clac_parm.ac2 = (bmbuf[2]<<8)|bmbuf[3];
	bmp180_clac_parm.ac3 = (bmbuf[4]<<8)|bmbuf[5];
	bmp180_clac_parm.ac4 = (bmbuf[6]<<8)|bmbuf[7];
	bmp180_clac_parm.ac5 = (bmbuf[8]<<8)|bmbuf[9];
	bmp180_clac_parm.ac6 = (bmbuf[10]<<8)|bmbuf[11];
	bmp180_clac_parm.b1 = (bmbuf[12]<<8)|bmbuf[13];
	bmp180_clac_parm.b2 = (bmbuf[14]<<8)|bmbuf[15];
	bmp180_clac_parm.mb = (bmbuf[16]<<8)|bmbuf[17];
	bmp180_clac_parm.mc = (bmbuf[18]<<8)|bmbuf[19];
	bmp180_clac_parm.md = (bmbuf[20]<<8)|bmbuf[21];

2.4 bmp180_read接口

  read函数负责读取原始AD值,并通过校验系数计算出实际值,返回给用户层。温度值为short型,单位0.1℃;气压值为long型(64位系统为8字节),单位Pa;温度值存储于低字节,气压值存储于高字节;小端模式。

if(copy_to_user(buf, (const uint8_t*)&temperature, sizeof(temperature)))
{
	ret = -1;
	printk("copy to user failed\n");
}
if (copy_to_user(buf+sizeof(temperature), (const uint8_t*)&pressure, sizeof(pressure)))
{
	ret = -1;
	printk("copy to user failed\n");
}

2.5 bmp180_ioctl

  ioctl提供用户层获取芯片唯一ID、复位芯片功能。

/* 命令字 */
#define BMP_RESET_CHIP	_IO('P', 0)
#define BMP_GET_CHIP_ID	_IOR('P', 1, char)

static long bmp180_ioctl(struct file *pfile, unsigned int cmd, unsigned long arg)
{
	int ret = 0;
	struct bmp180_dev *p;
	uint8_t chip_id = 0x00;
	
	p = pfile->private_data;
	switch(cmd)
	{
		case BMP_RESET_CHIP:
			bmp180_write_reg(p, BMP_REG_RESET, BMP_REG_RESET_VALUE);
		break;
		case BMP_GET_CHIP_ID:
			chip_id = bmp180_read_reg(p, BMP_REG_CHIP_ID);
			ret = copy_to_user((char __user*)arg, (char __user*)&chip_id, 1); 
		break;
		default:
		break;
	}

	return ret;
}

2.6 bmp180_probe

  probe探测函数,设备树和驱动匹配,执行字符驱动创建的流程。


2.7 i2c驱动注册和注销

  添加i2c驱动设备匹配属性,属性(compatible)名称字段与必须与设备树i2c节点属性名称保持一致,内核加载驱动时调用“probe”匹配设备树和驱动程序。然后,添加i2c设备驱动注册与注销函数。

/* 设备树匹配 */
static struct of_device_id of_bmp180_ids[] = {
   {.compatible = "bosch,bmp180"},
   { }   
 };
/* 传统的ID匹配 */
static const struct i2c_device_id bmp180_id[] = { 
     {"bmp180", BMP180_SLAVE_ADDR}, 
     {} 
}; 

/* bmp180 i2c设备驱动 */
static struct i2c_driver bmp180_driver = { 
	.driver   = { 
	.owner    = THIS_MODULE, 
	.name     = BMP180_DEV_NAME, 
	.of_match_table = of_bmp180_ids,
	}, 
	.id_table = bmp180_id, 
	.probe 	  = bmp180_probe, 
	.remove   = bmp180_remove, 
};

2.8 编译Makefile

  注意Makefile文件中内核路径,保证ARM板子上内核和编译的内核版本一致,否则后面加载驱动会失败。

ifeq ($(KERNELRELEASE),)
KERNELDIR = /opt/rk3399/linux-sdk/linux-sdk/kernel
PWD := $(shell pwd)

modules:
	$(MAKE) -C $(KERNELDIR) M=$(PWD) modules

clean:
	rm -rf *.o *.ko .mod.o *.mod.c *.symvers

else
	obj-m := bmp180.o
endif

3. 运行

3.1 加载驱动

  执行make编译驱动,生成bmp180.ko文件。可以通过U盘、NFS、串口等方式将驱动文件传输至板子上。然后执行“insmod bmp 180.ko”手动加载驱动。

  查看驱动加载是否加载成功。执行“ls /dev”查看系统设备驱动,或者执行“ls /sys/bus/i2c/drivers”查看i2c 设备驱动,发现bmp180驱动已经加载成功。
在这里插入图片描述
在这里插入图片描述


3.2 应用测试程序

  编写bmp180_app.c应用程序,2秒周期在终端输出一次温度值和气压值。
在这里插入图片描述

4. 源码

【1】https://github.com/Prry/linux-drivers/tree/master/bmp180

posted @ 2019-12-29 23:57  Acuity  阅读(550)  评论(0编辑  收藏  举报