kopia lustrzana https://github.com/luigifcruz/pico-stuff
256 wiersze
6.4 KiB
C
256 wiersze
6.4 KiB
C
#ifndef BMP180_H
|
|
#define BMP180_H
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
|
|
#include "pico/stdio.h"
|
|
#include "pico/stdlib.h"
|
|
#include "hardware/i2c.h"
|
|
|
|
#define BMP_REG_CONTROL 0xF4
|
|
#define BMP_REG_RESULT 0xF6
|
|
#define BMP_COM_TEMP 0x2E
|
|
#define BMP_COM_PRES 0x34
|
|
#define BMP_CALIB_COEFF_LEN 0x16
|
|
#define BMP_CALIB_COEFF_REG 0xAA
|
|
#define BMP_CHIP_ID_REG 0xD0
|
|
#define BMP_CHIP_ID_VAL 0x55
|
|
#define BMP_MIN_TEMP_THRESHOLD -40
|
|
#define BMP_MAX_TEMP_THRESHOLD +85
|
|
#define BMP_TEMP_DELAY 5
|
|
|
|
#define ASSERT_OK(X) { if (X == false) return false; };
|
|
|
|
typedef struct {
|
|
int16_t AC1;
|
|
int16_t AC2;
|
|
int16_t AC3;
|
|
uint16_t AC4;
|
|
uint16_t AC5;
|
|
uint16_t AC6;
|
|
int16_t B1;
|
|
int16_t B2;
|
|
int16_t MB;
|
|
int16_t MC;
|
|
int16_t MD;
|
|
} bmp_calib_param_t;
|
|
|
|
typedef struct {
|
|
int addr;
|
|
int rate;
|
|
int scl;
|
|
int sda;
|
|
i2c_inst_t* inst;
|
|
} i2c_t;
|
|
|
|
typedef struct {
|
|
i2c_t i2c;
|
|
uint8_t oss;
|
|
float temperature;
|
|
int32_t pressure;
|
|
bmp_calib_param_t calib;
|
|
int32_t B5;
|
|
} bmp_t;
|
|
|
|
const uint32_t oss_delay[] = {5, 8, 14, 26};
|
|
|
|
bool bmp_check_chip_id(bmp_t* bmp) {
|
|
uint8_t chip_id_reg = BMP_CHIP_ID_REG;
|
|
uint8_t chip_id_val[1];
|
|
|
|
i2c_write_blocking(bmp->i2c.inst, bmp->i2c.addr, &chip_id_reg, 1, true);
|
|
i2c_read_blocking(bmp->i2c.inst, bmp->i2c.addr, chip_id_val, 1, false);
|
|
|
|
if (chip_id_val[0] != BMP_CHIP_ID_VAL) {
|
|
#ifdef DEBUG
|
|
printf("Returned Chip ID: 0x%02x\n", chip_id_val[0]);
|
|
printf("Check your I2C configuration and connection.\n");
|
|
#endif
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool bmp_get_calib_coeffs(bmp_t* bmp) {
|
|
uint8_t calib_coeffs_reg = BMP_CALIB_COEFF_REG;
|
|
uint8_t calib_coeffs_val[BMP_CALIB_COEFF_LEN];
|
|
|
|
i2c_write_blocking(bmp->i2c.inst, bmp->i2c.addr, &calib_coeffs_reg, 1, true);
|
|
i2c_read_blocking(bmp->i2c.inst, bmp->i2c.addr, calib_coeffs_val, BMP_CALIB_COEFF_LEN, false);
|
|
|
|
int16_t* data = (int16_t*)&bmp->calib;
|
|
for (int i = 0, j = 1; i < BMP_CALIB_COEFF_LEN / 2; i++, j += 2) {
|
|
data[i] = (calib_coeffs_val[i * 2] << 8) | calib_coeffs_val[j];
|
|
|
|
if ((data[i] == 0) | (data[i] == -1)) {
|
|
#ifdef DEBUG
|
|
printf("Calibation data invalid.\n");
|
|
#endif
|
|
return false;
|
|
}
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
printf("==== CALIBRATION COEFFS ====\n");
|
|
printf("AC1: %d\n", bmp->calib.AC1);
|
|
printf("AC2: %d\n", bmp->calib.AC2);
|
|
printf("AC3: %d\n", bmp->calib.AC3);
|
|
printf("AC4: %d\n", bmp->calib.AC4);
|
|
printf("AC5: %d\n", bmp->calib.AC5);
|
|
printf("AC6: %d\n", bmp->calib.AC6);
|
|
printf("B1: %d\n", bmp->calib.B1);
|
|
printf("B2: %d\n", bmp->calib.B2);
|
|
printf("MB: %d\n", bmp->calib.MB);
|
|
printf("MC: %d\n", bmp->calib.MC);
|
|
printf("MD: %d\n", bmp->calib.MD);
|
|
printf("============================\n");
|
|
#endif
|
|
|
|
return true;
|
|
}
|
|
|
|
uint32_t bmp_start_temperature(bmp_t* bmp) {
|
|
uint8_t temp_reg[] = {
|
|
BMP_REG_CONTROL,
|
|
BMP_COM_TEMP
|
|
};
|
|
i2c_write_blocking(bmp->i2c.inst, bmp->i2c.addr, temp_reg, 2, false);
|
|
return BMP_TEMP_DELAY;
|
|
}
|
|
|
|
bool bmp_read_temperature(bmp_t* bmp) {
|
|
uint8_t temp_reg = BMP_REG_RESULT;
|
|
uint8_t temp_val[2];
|
|
|
|
i2c_write_blocking(bmp->i2c.inst, bmp->i2c.addr, &temp_reg, 1, true);
|
|
if (i2c_read_blocking(bmp->i2c.inst, bmp->i2c.addr, temp_val, 2, false) != 2) {
|
|
#ifdef DEBUG
|
|
printf("Wrong read length.\n");
|
|
#endif
|
|
return false;
|
|
}
|
|
|
|
int16_t UT = (temp_val[0] << 8) + temp_val[1];
|
|
|
|
if (UT == (int16_t)0x8000) {
|
|
#ifdef DEBUG
|
|
printf("Non-initialized register detected.\n");
|
|
#endif
|
|
return false;
|
|
}
|
|
|
|
int32_t X1 = (((int32_t)UT - bmp->calib.AC6) * bmp->calib.AC5) >> 15;
|
|
int32_t X2 = (bmp->calib.MC << 11) / (X1 + bmp->calib.MD);
|
|
bmp->B5 = X1 + X2;
|
|
float temp = ((bmp->B5 + 8) >> 4) * 0.1f;
|
|
|
|
if ((temp <= BMP_MIN_TEMP_THRESHOLD) || (temp >= BMP_MAX_TEMP_THRESHOLD)) {
|
|
#ifdef DEBUG
|
|
printf("Temperature beyond threshold: %f\n", temp);
|
|
#endif
|
|
return false;
|
|
}
|
|
|
|
bmp->temperature = temp;
|
|
|
|
return true;
|
|
}
|
|
|
|
uint32_t bmp_start_pressure(bmp_t* bmp) {
|
|
uint8_t pres_reg[] = {
|
|
BMP_REG_CONTROL,
|
|
BMP_COM_PRES + (bmp->oss << 6)
|
|
};
|
|
i2c_write_blocking(bmp->i2c.inst, bmp->i2c.addr, pres_reg, 2, false);
|
|
return oss_delay[bmp->oss];
|
|
}
|
|
|
|
bool bmp_read_pressure(bmp_t* bmp) {
|
|
uint8_t pres_reg = BMP_REG_RESULT;
|
|
uint8_t pres_val[3];
|
|
|
|
i2c_write_blocking(bmp->i2c.inst, bmp->i2c.addr, &pres_reg, 1, true);
|
|
if (i2c_read_blocking(bmp->i2c.inst, bmp->i2c.addr, pres_val, 3, false) != 3) {
|
|
#ifdef DEBUG
|
|
printf("Wrong read length.\n");
|
|
#endif
|
|
return false;
|
|
}
|
|
|
|
int32_t UP = ((pres_val[0] << 16) + (pres_val[1] << 8) + pres_val[2]) >> (8 - bmp->oss);
|
|
|
|
int32_t X1, X2, X3, B3, B6, p = 0;
|
|
uint32_t B4, B7 = 0;
|
|
|
|
B6 = bmp->B5 - 4000;
|
|
X1 = (bmp->calib.B2 * ((B6 * B6) >> 12)) >> 11;
|
|
X2 = (bmp->calib.AC2 * B6) >> 11;
|
|
X3 = X1 + X2;
|
|
B3 = (((bmp->calib.AC1 * 4 + X3) << bmp->oss) + 2) / 4;
|
|
X1 = (bmp->calib.AC3 * B6) >> 13;
|
|
X2 = (bmp->calib.B1 * ((B6 * B6) >> 12)) >> 16;
|
|
X3 = ((X1 + X2) + 2) >> 2;
|
|
B4 = (bmp->calib.AC4 * (uint32_t)(X3 + 32768)) >> 15;
|
|
B7 = ((uint32_t)(UP) - B3) * (50000 >> bmp->oss);
|
|
|
|
if (B7 < 0x80000000) {
|
|
p = (B7 * 2) / B4;
|
|
} else {
|
|
p = (B7 / B4) * 2;
|
|
}
|
|
|
|
X1 = (p >> 8) * (p >> 8);
|
|
X1 = (X1 * 3038) >> 16;
|
|
X2 = (-7357 * p) >> 16;
|
|
|
|
bmp->pressure = p + ((X1 + X2 + 3791) >> 4);
|
|
|
|
return true;
|
|
}
|
|
|
|
bool bmp_get_temperature(bmp_t* bmp) {
|
|
sleep_ms(bmp_start_temperature(bmp));
|
|
return bmp_read_temperature(bmp);
|
|
}
|
|
|
|
// User must call bmp_get_temperature() before calling this method.
|
|
// Or use the combo bmp_get_pressure_temperature().
|
|
bool bmp_get_pressure(bmp_t* bmp) {
|
|
sleep_ms(bmp_start_pressure(bmp));
|
|
return bmp_read_pressure(bmp);
|
|
}
|
|
|
|
bool bmp_get_pressure_temperature(bmp_t* bmp) {
|
|
bool res = true;
|
|
res &= bmp_get_temperature(bmp);
|
|
res &= bmp_get_pressure(bmp);
|
|
return res;
|
|
}
|
|
|
|
bool bmp_init(bmp_t* bmp) {
|
|
i2c_init(bmp->i2c.inst, bmp->i2c.rate);
|
|
|
|
if (bmp->oss < 0 || bmp->oss > 3) {
|
|
#ifdef DEBUG
|
|
printf("Invalid over-sampling rate (%d). Valid 0 to 3.\n", bmp->oss);
|
|
#endif
|
|
return false;
|
|
}
|
|
|
|
gpio_set_function(bmp->i2c.scl, GPIO_FUNC_I2C);
|
|
gpio_set_function(bmp->i2c.sda, GPIO_FUNC_I2C);
|
|
gpio_pull_up(bmp->i2c.scl);
|
|
gpio_pull_up(bmp->i2c.sda);
|
|
|
|
sleep_ms(100);
|
|
|
|
ASSERT_OK(bmp_check_chip_id(bmp));
|
|
ASSERT_OK(bmp_get_calib_coeffs(bmp));
|
|
|
|
return true;
|
|
}
|
|
|
|
#endif
|