esp-idf-lib/components/bmp180/bmp180.c

Mon, 17 Apr 2023 16:20:58 +0200

author
Michiel Broek <mbroek@mbse.eu>
date
Mon, 17 Apr 2023 16:20:58 +0200
changeset 32
84e54b14e7db
parent 1
1c9894662795
permissions
-rw-r--r--

Version 0.4.1 Measure internal chip temperature, range -10 to 80. Result available in mqtt json payload.

/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2015 Frank Bargstedt
 * Copyright (c) 2018 Ruslan V. Uss <unclerus@gmail.com>
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

/**
 * @file bmp180.c
 *
 * ESP-IDF driver for BMP180 digital pressure sensor
 *
 * Ported from esp-open-rtos
 *
 * Copyright (c) 2015 Frank Bargstedt\n
 * Copyright (c) 2018 Ruslan V. Uss <unclerus@gmail.com>
 *
 * MIT Licensed as described in the file LICENSE
 */
#include "bmp180.h"
#include <inttypes.h>
#include <esp_err.h>
#include <esp_log.h>
#include <ets_sys.h>
#include <esp_idf_lib_helpers.h>

#define I2C_FREQ_HZ 1000000 // Max 1MHz for esp-idf

static const char *TAG = "bmp180";

#define BMP180_RX_QUEUE_SIZE      10
#define BMP180_TASK_PRIORITY      9

#define BMP180_VERSION_REG        0xD0
#define BMP180_CONTROL_REG        0xF4
#define BMP180_RESET_REG          0xE0
#define BMP180_OUT_MSB_REG        0xF6
#define BMP180_OUT_LSB_REG        0xF7
#define BMP180_OUT_XLSB_REG       0xF8

#define BMP180_CALIBRATION_REG    0xAA

// Values for BMP180_CONTROL_REG
#define BMP180_MEASURE_TEMP       0x2E
#define BMP180_MEASURE_PRESS      0x34

// CHIP ID stored in BMP180_VERSION_REG
#define BMP180_CHIP_ID            0x55

// Reset value for BMP180_RESET_REG
#define BMP180_RESET_VALUE        0xB6

#define CHECK(x) do { esp_err_t __; if ((__ = x) != ESP_OK) return __; } while (0)
#define CHECK_ARG(VAL) do { if (!(VAL)) return ESP_ERR_INVALID_ARG; } while (0)

static esp_err_t bmp180_read_reg_16(i2c_dev_t *dev, uint8_t reg, int16_t *r)
{
    uint8_t d[] = { 0, 0 };

    CHECK(i2c_dev_read_reg(dev, reg, d, 2));
    *r = ((int16_t)d[0] << 8) | (d[1]);

    return ESP_OK;
}

static inline esp_err_t bmp180_start_measurement(i2c_dev_t *dev, uint8_t cmd)
{
    return i2c_dev_write_reg(dev, BMP180_CONTROL_REG, &cmd, 1);
}

static esp_err_t bmp180_get_uncompensated_temperature(i2c_dev_t *dev, int32_t *ut)
{
    // Write Start Code into reg 0xF4.
    CHECK(bmp180_start_measurement(dev, BMP180_MEASURE_TEMP));

    // Wait 5ms, datasheet states 4.5ms
    ets_delay_us(5000);

    int16_t v;
    CHECK(bmp180_read_reg_16(dev, BMP180_OUT_MSB_REG, &v));
    *ut = v;
    return ESP_OK;
}

static esp_err_t bmp180_get_uncompensated_pressure(i2c_dev_t *dev, bmp180_mode_t oss, uint32_t *up)
{
    uint16_t us;

    // Limit oss and set the measurement wait time. The datasheet
    // states 4.5, 7.5, 13.5, 25.5ms for oss 0 to 3.
    switch (oss)
    {
        case BMP180_MODE_ULTRA_LOW_POWER:                 us = 5000; break;
        case BMP180_MODE_STANDARD:                        us = 8000; break;
        case BMP180_MODE_HIGH_RESOLUTION:                 us = 14000; break;
        default: oss = BMP180_MODE_ULTRA_HIGH_RESOLUTION; us = 26000; break;
    }

    // Write Start Code into reg 0xF4
    CHECK(bmp180_start_measurement(dev, BMP180_MEASURE_PRESS | (oss << 6)));

    ets_delay_us(us);

    uint8_t d[] = { 0, 0, 0 };
    uint8_t reg = BMP180_OUT_MSB_REG;
    CHECK(i2c_dev_read_reg(dev, reg, d, 3));

    uint32_t r = ((uint32_t)d[0] << 16) | ((uint32_t)d[1] << 8) | d[2];
    r >>= 8 - oss;
    *up = r;

    return ESP_OK;
}

esp_err_t bmp180_init_desc(bmp180_dev_t *dev, i2c_port_t port, gpio_num_t sda_gpio, gpio_num_t scl_gpio)
{
    CHECK_ARG(dev);

    dev->i2c_dev.port = port;
    dev->i2c_dev.addr = BMP180_DEVICE_ADDRESS;
    dev->i2c_dev.cfg.sda_io_num = sda_gpio;
    dev->i2c_dev.cfg.scl_io_num = scl_gpio;
#if HELPER_TARGET_IS_ESP32
    dev->i2c_dev.cfg.master.clk_speed = I2C_FREQ_HZ;
#endif

    return i2c_dev_create_mutex(&dev->i2c_dev);
}

esp_err_t bmp180_free_desc(bmp180_dev_t *dev)
{
    CHECK_ARG(dev);

    return i2c_dev_delete_mutex(&dev->i2c_dev);
}

esp_err_t bmp180_init(bmp180_dev_t *dev)
{
    CHECK_ARG(dev);


    I2C_DEV_TAKE_MUTEX(&dev->i2c_dev);

    uint8_t id;
    I2C_DEV_CHECK(&dev->i2c_dev, i2c_dev_read_reg(&dev->i2c_dev, BMP180_VERSION_REG, &id, 1));
    if (id != BMP180_CHIP_ID)
    {
        I2C_DEV_GIVE_MUTEX(&dev->i2c_dev);
        ESP_LOGE(TAG, "Invalid device ID: 0x%02x", id);
        return ESP_ERR_NOT_FOUND;
    }

    I2C_DEV_CHECK(&dev->i2c_dev, bmp180_read_reg_16(&dev->i2c_dev, BMP180_CALIBRATION_REG + 0, &dev->AC1));
    I2C_DEV_CHECK(&dev->i2c_dev, bmp180_read_reg_16(&dev->i2c_dev, BMP180_CALIBRATION_REG + 2, &dev->AC2));
    I2C_DEV_CHECK(&dev->i2c_dev, bmp180_read_reg_16(&dev->i2c_dev, BMP180_CALIBRATION_REG + 4, &dev->AC3));
    I2C_DEV_CHECK(&dev->i2c_dev, bmp180_read_reg_16(&dev->i2c_dev, BMP180_CALIBRATION_REG + 6, (int16_t *)&dev->AC4));
    I2C_DEV_CHECK(&dev->i2c_dev, bmp180_read_reg_16(&dev->i2c_dev, BMP180_CALIBRATION_REG + 8, (int16_t *)&dev->AC5));
    I2C_DEV_CHECK(&dev->i2c_dev, bmp180_read_reg_16(&dev->i2c_dev, BMP180_CALIBRATION_REG + 10, (int16_t *)&dev->AC6));
    I2C_DEV_CHECK(&dev->i2c_dev, bmp180_read_reg_16(&dev->i2c_dev, BMP180_CALIBRATION_REG + 12, &dev->B1));
    I2C_DEV_CHECK(&dev->i2c_dev, bmp180_read_reg_16(&dev->i2c_dev, BMP180_CALIBRATION_REG + 14, &dev->B2));
    I2C_DEV_CHECK(&dev->i2c_dev, bmp180_read_reg_16(&dev->i2c_dev, BMP180_CALIBRATION_REG + 16, &dev->MB));
    I2C_DEV_CHECK(&dev->i2c_dev, bmp180_read_reg_16(&dev->i2c_dev, BMP180_CALIBRATION_REG + 18, &dev->MC));
    I2C_DEV_CHECK(&dev->i2c_dev, bmp180_read_reg_16(&dev->i2c_dev, BMP180_CALIBRATION_REG + 20, &dev->MD));

    I2C_DEV_GIVE_MUTEX(&dev->i2c_dev);

    ESP_LOGD(TAG, "AC1:=%d AC2:=%d AC3:=%d AC4:=%u AC5:=%u AC6:=%u", dev->AC1, dev->AC2, dev->AC3, dev->AC4, dev->AC5, dev->AC6);
    ESP_LOGD(TAG, "B1:=%d B2:=%d", dev->B1, dev->B2);
    ESP_LOGD(TAG, "MB:=%d MC:=%d MD:=%d", dev->MB, dev->MC, dev->MD);

    if (dev->AC1== 0  || dev->AC2 == 0 || dev->AC3 == 0 ||
        dev->AC4 == 0 || dev->AC5 == 0 || dev->AC6 == 0 ||
        dev->B1  == 0 || dev->B2  == 0 ||
        dev->MB  == 0 || dev->MC  == 0 || dev->MD  == 0)
    {
        return ESP_ERR_INVALID_RESPONSE;
    }

    return ESP_OK;
}

///////////////////////////////////////////////////////////////////////////////

esp_err_t bmp180_measure(bmp180_dev_t *dev, float *temperature, uint32_t *pressure, bmp180_mode_t oss)
{
    CHECK_ARG(dev && temperature && pressure);

    I2C_DEV_TAKE_MUTEX(&dev->i2c_dev);

    // Temperature is always needed, also required for pressure only.
    //
    // Calculation taken from BMP180 Datasheet
    int32_t T, P;
    int32_t UT, X1, X2, B5;
    UT = 0;
    I2C_DEV_CHECK(&dev->i2c_dev, bmp180_get_uncompensated_temperature(&dev->i2c_dev, &UT));

    X1 = ((UT - (int32_t)dev->AC6) * (int32_t)dev->AC5) >> 15;
    X2 = ((int32_t)dev->MC << 11) / (X1 + (int32_t)dev->MD);
    B5 = X1 + X2;
    T = (B5 + 8) >> 4;

    if (temperature)
        *temperature = T / 10.0;

    ESP_LOGD(TAG, "T:= %" PRIi32 ".%d", T / 10, abs(T % 10));

    if (pressure)
    {
        int32_t X3, B3, B6;
        uint32_t B4, B7, UP = 0;

        I2C_DEV_CHECK(&dev->i2c_dev, bmp180_get_uncompensated_pressure(&dev->i2c_dev, oss, &UP));

        // Calculation taken from BMP180 Datasheet
        B6 = B5 - 4000;
        X1 = ((int32_t)dev->B2 * ((B6 * B6) >> 12)) >> 11;
        X2 = ((int32_t)dev->AC2 * B6) >> 11;
        X3 = X1 + X2;

        B3 = ((((int32_t)dev->AC1 * 4 + X3) << oss) + 2) >> 2;
        X1 = ((int32_t)dev->AC3 * B6) >> 13;
        X2 = ((int32_t)dev->B1 * ((B6 * B6) >> 12)) >> 16;
        X3 = ((X1 + X2) + 2) >> 2;
        B4 = ((uint32_t)dev->AC4 * (uint32_t)(X3 + 32768)) >> 15;
        B7 = ((uint32_t)UP - B3) * (uint32_t)(50000UL >> oss);

        if (B7 < 0x80000000UL)
            P = (B7 * 2) / B4;
        else
            P = (B7 / B4) * 2;

        X1 = (P >> 8) * (P >> 8);
        X1 = (X1 * 3038) >> 16;
        X2 = (-7357 * P) >> 16;
        P = P + ((X1 + X2 + (int32_t)3791) >> 4);

        *pressure = P;

        ESP_LOGD(TAG, "P:= %" PRIi32, P);
    }

    I2C_DEV_GIVE_MUTEX(&dev->i2c_dev);

    return ESP_OK;
}

mercurial