This is a temperature and atmospheric pressure chip. The datasheet is available at: https://www.adafruit.com/datasheets/BST-BMP280-DS001-11.pdf Change-Id: I3406eb6c2c4da564757b8315323d0681d648b541 Signed-off-by: Vlad Dogaru <vlad.dogaru@intel.com>
237 lines
6.1 KiB
C
237 lines
6.1 KiB
C
/* sensor_bmp280.c - Driver for Bosch BMP280 temperature and pressure sensor */
|
|
|
|
/*
|
|
* Copyright (c) 2016 Intel Corporation
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
#include <nanokernel.h>
|
|
#include <i2c.h>
|
|
#include <sensor.h>
|
|
#include <init.h>
|
|
#include <gpio.h>
|
|
#include <misc/byteorder.h>
|
|
#include "sensor_bmp280.h"
|
|
|
|
#ifndef CONFIG_SENSOR_DEBUG
|
|
#define DBG(...) { ; }
|
|
#else
|
|
#include <misc/printk.h>
|
|
#define DBG printk
|
|
#endif /* CONFIG_SENSOR_DEBUG */
|
|
|
|
static int bmp280_burst_read(struct bmp280_data *data, uint8_t addr,
|
|
uint8_t *vals, uint8_t len)
|
|
{
|
|
struct i2c_msg msgs[2] = {
|
|
{
|
|
.buf = &addr,
|
|
.len = 1,
|
|
.flags = I2C_MSG_WRITE | I2C_MSG_RESTART,
|
|
},
|
|
{
|
|
.buf = vals,
|
|
.len = len,
|
|
.flags = I2C_MSG_READ | I2C_MSG_STOP,
|
|
},
|
|
};
|
|
|
|
return i2c_transfer(data->i2c_master, msgs, 2, data->i2c_slave_addr);
|
|
}
|
|
|
|
static int bmp280_reg_read(struct bmp280_data *data, uint8_t reg, uint8_t *val)
|
|
{
|
|
return bmp280_burst_read(data, reg, val, 1);
|
|
}
|
|
|
|
static int bmp280_reg_write(struct bmp280_data *data, uint8_t reg, uint8_t val)
|
|
{
|
|
uint8_t buf[2] = {reg, val};
|
|
|
|
return i2c_write(data->i2c_master, buf, 2, data->i2c_slave_addr);
|
|
}
|
|
|
|
/*
|
|
* Compensation code taken from BMP280 datasheet, Section 3.11.3
|
|
* "Compensation formula".
|
|
*/
|
|
static void bmp280_compensate_temp(struct bmp280_data *data, int32_t adc_temp)
|
|
{
|
|
int32_t var1, var2;
|
|
|
|
var1 = (((adc_temp >> 3) - ((int32_t)data->dig_t1 << 1)) *
|
|
((int32_t)data->dig_t2)) >> 11;
|
|
var2 = (((((adc_temp >> 4) - ((int32_t)data->dig_t1)) *
|
|
((adc_temp >> 4) - ((int32_t)data->dig_t1))) >> 12) *
|
|
((int32_t)data->dig_t3)) >> 14;
|
|
|
|
data->t_fine = var1 + var2;
|
|
data->comp_temp = (data->t_fine * 5 + 128) >> 8;
|
|
}
|
|
|
|
static void bmp280_compensate_press(struct bmp280_data *data, int32_t adc_press)
|
|
{
|
|
int64_t var1, var2, p;
|
|
|
|
var1 = ((int64_t)data->t_fine) - 128000;
|
|
var2 = var1 * var1 * (int64_t)data->dig_p6;
|
|
var2 = var2 + ((var1 * (int64_t)data->dig_p5) << 17);
|
|
var2 = var2 + (((int64_t)data->dig_p4) << 35);
|
|
var1 = ((var1 * var1 * (int64_t)data->dig_p3) >> 8) +
|
|
((var1 * (int64_t)data->dig_p2) << 12);
|
|
var1 = (((((int64_t)1) << 47) + var1)) * ((int64_t)data->dig_p1) >> 33;
|
|
|
|
/* Avoid exception caused by division by zero. */
|
|
if (var1 == 0) {
|
|
data->comp_press = 0;
|
|
return;
|
|
}
|
|
|
|
p = 1048576 - adc_press;
|
|
p = (((p << 31) - var2) * 3125) / var1;
|
|
var1 = (((int64_t)data->dig_p9) * (p >> 13) * (p >> 13)) >> 25;
|
|
var2 = (((int64_t)data->dig_p8) * p) >> 19;
|
|
p = ((p + var1 + var2) >> 8) + (((int64_t)data->dig_p7) << 4);
|
|
|
|
data->comp_press = (uint32_t)p;
|
|
}
|
|
|
|
static int bmp280_sample_fetch(struct device *dev)
|
|
{
|
|
struct bmp280_data *data = dev->driver_data;
|
|
uint8_t buf[6];
|
|
int32_t adc_press, adc_temp;
|
|
int ret;
|
|
|
|
ret = bmp280_burst_read(data, BMP280_REG_PRESS_MSB, buf, sizeof(buf));
|
|
if (ret) {
|
|
return ret;
|
|
}
|
|
|
|
adc_press = (buf[0] << 12) | (buf[1] << 4) | (buf[2] >> 4);
|
|
adc_temp = (buf[3] << 12) | (buf[4] << 4) | (buf[5] >> 4);
|
|
|
|
bmp280_compensate_temp(data, adc_temp);
|
|
bmp280_compensate_press(data, adc_press);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int bmp280_channel_get(struct device *dev,
|
|
enum sensor_channel chan,
|
|
struct sensor_value *val)
|
|
{
|
|
struct bmp280_data *data = dev->driver_data;
|
|
|
|
switch (chan) {
|
|
case SENSOR_CHAN_TEMP:
|
|
/*
|
|
* data->comp_temp has a resolution of 0.01 degC. So
|
|
* 5123 equals 51.23 degC.
|
|
*/
|
|
val->type = SENSOR_TYPE_INT_PLUS_MICRO;
|
|
val->val1 = data->comp_temp / 100;
|
|
val->val2 = data->comp_temp % 100 * 10000;
|
|
break;
|
|
case SENSOR_CHAN_PRESS:
|
|
/*
|
|
* data->comp_press has 24 integer bits and 8
|
|
* fractional. Output value of 24674867 represents
|
|
* 24674867/256 = 96386.2 Pa = 963.862 hPa
|
|
*/
|
|
val->type = SENSOR_TYPE_INT_PLUS_MICRO;
|
|
val->val1 = data->comp_press >> 8;
|
|
val->val2 = ((data->comp_press & 0xff) * 1000000) >> 8;
|
|
break;
|
|
default:
|
|
return -EINVAL;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static struct sensor_driver_api bmp280_api_funcs = {
|
|
.sample_fetch = bmp280_sample_fetch,
|
|
.channel_get = bmp280_channel_get,
|
|
};
|
|
|
|
static void bmp280_read_compensation(struct bmp280_data *data)
|
|
{
|
|
uint16_t buf[12];
|
|
|
|
bmp280_burst_read(data, BMP280_REG_COMP_START,
|
|
(uint8_t *)buf, sizeof(buf));
|
|
|
|
data->dig_t1 = sys_le16_to_cpu(buf[0]);
|
|
data->dig_t2 = sys_le16_to_cpu(buf[1]);
|
|
data->dig_t3 = sys_le16_to_cpu(buf[2]);
|
|
|
|
data->dig_p1 = sys_le16_to_cpu(buf[3]);
|
|
data->dig_p2 = sys_le16_to_cpu(buf[4]);
|
|
data->dig_p3 = sys_le16_to_cpu(buf[5]);
|
|
data->dig_p4 = sys_le16_to_cpu(buf[6]);
|
|
data->dig_p5 = sys_le16_to_cpu(buf[7]);
|
|
data->dig_p6 = sys_le16_to_cpu(buf[8]);
|
|
data->dig_p7 = sys_le16_to_cpu(buf[9]);
|
|
data->dig_p8 = sys_le16_to_cpu(buf[10]);
|
|
data->dig_p9 = sys_le16_to_cpu(buf[11]);
|
|
}
|
|
|
|
static int bmp280_chip_init(struct device *dev)
|
|
{
|
|
struct bmp280_data *data = (struct bmp280_data *) dev->driver_data;
|
|
uint8_t buf;
|
|
|
|
bmp280_reg_read(data, BMP280_REG_ID, &buf);
|
|
if (buf != BMP280_CHIP_ID) {
|
|
DBG("bmp280: bad chip id %x\n", buf);
|
|
return -ENOTSUP;
|
|
}
|
|
|
|
bmp280_read_compensation(data);
|
|
bmp280_reg_write(data, BMP280_REG_CTRL_MEAS, BMP280_CTRL_MEAS_VAL);
|
|
bmp280_reg_write(data, BMP280_REG_CONFIG, BMP280_CONFIG_VAL);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int bmp280_init(struct device *dev)
|
|
{
|
|
struct bmp280_data *data = dev->driver_data;
|
|
int ret;
|
|
|
|
dev->driver_api = &bmp280_api_funcs;
|
|
|
|
data->i2c_master = device_get_binding(CONFIG_BMP280_I2C_MASTER_DEV_NAME);
|
|
if (!data->i2c_master) {
|
|
DBG("bmp280: i2c master not found: %s\n",
|
|
CONFIG_BMP280_I2C_MASTER_DEV_NAME);
|
|
return -EINVAL;
|
|
}
|
|
|
|
data->i2c_slave_addr = CONFIG_BMP280_I2C_ADDR;
|
|
|
|
ret = bmp280_chip_init(dev);
|
|
if (ret) {
|
|
return ret;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static struct bmp280_data bmp280_data;
|
|
|
|
DEVICE_INIT(bmp280, CONFIG_BMP280_DEV_NAME, bmp280_init, &bmp280_data,
|
|
NULL, SECONDARY, CONFIG_BMP280_INIT_PRIORITY);
|