From 34d783a2893dadff67bbf1a5e318e73a0c5f8e62 Mon Sep 17 00:00:00 2001 From: mr-nice Date: Sat, 24 Dec 2016 18:08:42 +0100 Subject: [PATCH] Feature/ms561101ba03 (#308) Driver for the ms561101ba03 barometric pressure sensor --- examples/ms561101ba03/Makefile | 4 + examples/ms561101ba03/main.c | 39 ++++++ extras/ms561101ba03/component.mk | 9 ++ extras/ms561101ba03/ms561101ba03.c | 218 +++++++++++++++++++++++++++++ extras/ms561101ba03/ms561101ba03.h | 96 +++++++++++++ 5 files changed, 366 insertions(+) create mode 100644 examples/ms561101ba03/Makefile create mode 100644 examples/ms561101ba03/main.c create mode 100644 extras/ms561101ba03/component.mk create mode 100644 extras/ms561101ba03/ms561101ba03.c create mode 100644 extras/ms561101ba03/ms561101ba03.h diff --git a/examples/ms561101ba03/Makefile b/examples/ms561101ba03/Makefile new file mode 100644 index 0000000..8f1b28c --- /dev/null +++ b/examples/ms561101ba03/Makefile @@ -0,0 +1,4 @@ +PROGRAM = ms561101ba03 +EXTRA_COMPONENTS = extras/i2c extras/ms561101ba03 +ESPBAUD = 460800 +include ../../common.mk diff --git a/examples/ms561101ba03/main.c b/examples/ms561101ba03/main.c new file mode 100644 index 0000000..915f055 --- /dev/null +++ b/examples/ms561101ba03/main.c @@ -0,0 +1,39 @@ +/* + * Example of using MS561101ba03 driver + * + * Copyright (C) 2016 Bernhard Guillon + * + * Loosely based on main.c with: + * Copyright (C) 2016 Ruslan V. Uss + * BSD Licensed as described in the file LICENSE + */ +#include +#include +#include +#include +#include + +#define SCL_PIN 5 +#define SDA_PIN 4 + +void user_init(void) +{ + i2c_init(SCL_PIN, SDA_PIN); + + uart_set_baud(0, 115200); + printf("SDK version:%s\n\n", sdk_system_get_sdk_version()); + + ms561101ba03_config_data_t conf = {0,0,0,0,0,0}; + ms561101ba03_result_t result = {0,0}; + ms561101ba03_t device= {MS561101BA03_ADDR_CSB_LOW, MS561101BA03_OSR_4096, conf, result, 0}; + + while (!ms561101ba03_init(&device)) + printf("Device not found\n"); + + while (true) + { + if (!ms561101ba03_get_sensor_data(&device)) + printf("Error reading sensor data from device"); + printf("Temperature in C * 100: %i \nPressure in mbar * 100: %i\n", device.result.temperature, device.result.pressure); + } +} diff --git a/extras/ms561101ba03/component.mk b/extras/ms561101ba03/component.mk new file mode 100644 index 0000000..b4986d2 --- /dev/null +++ b/extras/ms561101ba03/component.mk @@ -0,0 +1,9 @@ +# Component makefile for extras/ms561101ba03 + +# expected anyone using this driver includes it as 'ms561101ba03/ms561101ba03.h' +INC_DIRS += $(ms561101ba03_ROOT).. + +# args for passing into compile rule generation +ms561101ba03_SRC_DIR = $(ms561101ba03_ROOT) + +$(eval $(call component_compile_rules,ms561101ba03)) diff --git a/extras/ms561101ba03/ms561101ba03.c b/extras/ms561101ba03/ms561101ba03.c new file mode 100644 index 0000000..34ed6d3 --- /dev/null +++ b/extras/ms561101ba03/ms561101ba03.c @@ -0,0 +1,218 @@ +/* + * Driver for barometic pressure sensor ms511-01BA03 + * + * Copyright (C) 2016 Bernhard Guillon + * + * Loosely based on hmc5831 with: + * Copyright (C) 2016 Ruslan V. Uss + * BSD Licensed as described in the file LICENSE + */ +#include "ms561101ba03.h" +#include +#include +#include "FreeRTOS.h" +#include "task.h" + +#define CONVERT_D1 0x40 +#define CONVERT_D2 0x50 +#define ADC_READ 0x00 + +/* + * FIXME: + * The chip has different response times for the different oversampling rates + * (0.5 ms/1.1ms/2.1ms/4.1ms/8.22ms) + * For now use a save value. + */ +#define CONVERSION_TIME 20 / portTICK_PERIOD_MS // milliseconds + +static const uint8_t RESET = 0x1E; + +static inline bool reset(uint8_t addr) +{ + uint8_t buf[1] = { RESET }; + return i2c_slave_write(addr, buf, 1); +} + +static inline bool read_prom(ms561101ba03_t *dev) +{ + uint8_t tmp[2] = {0,0}; + + if (!i2c_slave_read(dev->addr, 0xA2 , tmp, 2)) + return false; + dev->config_data.sens = tmp[0] << 8 | tmp[1]; + + if (!i2c_slave_read(dev->addr, 0xA4 , tmp, 2)) + return false; + dev->config_data.off = tmp[0] << 8 | tmp[1]; + + if (!i2c_slave_read(dev->addr, 0xA6 , tmp, 2)) + return false; + dev->config_data.tcs = tmp[0] << 8 | tmp[1]; + + if (!i2c_slave_read(dev->addr, 0xA8 , tmp, 2)) + return false; + dev->config_data.tco = tmp[0] << 8 | tmp[1]; + + if (!i2c_slave_read(dev->addr, 0xAA , tmp, 2)) + return false; + dev->config_data.t_ref = tmp[0] << 8 | tmp[1]; + + if (!i2c_slave_read(dev->addr, 0xAC , tmp, 2)) + return false; + dev->config_data.tempsens = tmp[0] << 8 | tmp[1]; + + return true; +} + +static inline bool start_pressure_conversion(ms561101ba03_t *dev) //D1 +{ + uint8_t buf = CONVERT_D1 + dev->osr; + return i2c_slave_write(dev->addr, &buf, 1); +} + +static inline bool start_temperature_conversion(ms561101ba03_t *dev) //D2 +{ + uint8_t buf = CONVERT_D2 + dev->osr; + return i2c_slave_write(dev->addr, &buf, 1); +} + +static inline bool read_adc(uint8_t addr, uint32_t *result) +{ + *result = 0; + uint8_t tmp[3]; + if (!i2c_slave_read(addr, 0x00, tmp, 3)) + return false; + + *result = (tmp[0] << 16) | (tmp[1] << 8) | tmp[2]; + + // If we are to fast the ADC will return 0 instead of the actual result + if (*result == 0) + return false; + + return true; +} + +static inline void calc_dt(ms561101ba03_t *dev, uint32_t digital_temperature) +{ + // Difference between actual and reference digital_temperature + // dT = D2 - T_ref = D2 - C5 *2^8 + dev->dT = digital_temperature - ((int32_t)dev->config_data.t_ref << 8); +} + +static inline int32_t calc_temp(ms561101ba03_t *dev) +{ + // Actual temerature (-40...85C with 0.01 resulution) + // TEMP = 20C +dT * TEMPSENSE =2000 + dT * C6 / 2^23 + return (int32_t)((int64_t)2000 +(int64_t)dev->dT * (int64_t)dev->config_data.tempsens / (int64_t)8388608); +} + +static inline int64_t calc_off(ms561101ba03_t *dev) +{ + // Offset at actual temperature + // OFF=OFF_t1 + TCO * dT = OFF_t1(C2) * 2^16 + (C4*dT)/2^7 + return (int64_t)((int64_t)dev->config_data.off * (int64_t)65536) + (((int64_t)dev->config_data.tco * (int64_t)dev->dT ) /(int64_t)128); +} + +static inline int64_t calc_sens(ms561101ba03_t *dev) +{ + // Senisitivity at actual temperature + // SENS=SENS_t1 + TCS *dT = SENS_t1(C1) *2^15 + (TCS(C3) *dT)/2^8 + return (int64_t)(((int64_t)dev->config_data.sens) *(int64_t)32768) + (((int64_t)dev->config_data.tcs * (int64_t)dev->dT ) /(int64_t)256); +} + +static inline int32_t calc_p(uint32_t digital_pressure, int64_t sens, int64_t off) +{ + // Temperature compensated pressure (10...1200mbar with 0.01mbar resolution + // P = digital pressure value * SENS - OFF = (D1 * SENS/2^21 -OFF)/2^15 + return (int32_t) (((int64_t)digital_pressure * (int64_t)((int64_t)sens / (int64_t)0x200000) - (int64_t)off) / (int64_t)32768); +} + +static inline bool get_raw_temperature(ms561101ba03_t *dev, uint32_t *result) +{ + if (!start_temperature_conversion(dev)) + return false; + + vTaskDelay(CONVERSION_TIME); + + if (!read_adc(dev->addr, result)) + return false; + + return true; +} + +static inline bool get_raw_pressure(ms561101ba03_t *dev, uint32_t *result) +{ + if (!start_pressure_conversion(dev)) + return false; + + vTaskDelay(CONVERSION_TIME); + + if (!read_adc(dev->addr, result)) + return false; + + return true; +} + +/////////////////////////Public////////////////////////////////////// + +bool ms561101ba03_get_sensor_data(ms561101ba03_t *dev) +{ + // Second order temperature compensation see datasheet p8 + uint32_t raw_pressure = 0; + if (!get_raw_pressure(dev, &raw_pressure)) + return false; + + uint32_t raw_temperature = 0; + if(!get_raw_temperature(dev, &raw_temperature)) + return false; + + calc_dt(dev, raw_temperature); + int64_t temp = calc_temp(dev); + int64_t off = calc_off(dev); + int64_t sens = calc_sens(dev); + + //Set defaults for temp >= 2000 + int64_t t_2 = 0; + int64_t off_2 = 0; + int64_t sens_2 = 0; + int64_t help = 0; + if (temp < 2000) + { + //Low temperature + t_2 = ((dev->dT * dev->dT) >> 31); // T2 = dT^2/2^31 + help = (temp-2000); + help = 5 * help * help; + off_2 = help >> 1; // OFF_2 = 5 * (TEMP - 2000)^2/2^1 + sens_2 = help >> 2; // SENS_2 = 5 * (TEMP - 2000)^2/2^2 + if(temp < -1500) + { + // Very low temperature + help = (temp+1500); + help = help * help; + off_2 = off_2 + 7 * help; // OFF_2 = OFF_2 + 7 * (TEMP + 1500)^2 + sens_2 = sens_2 + ((11 * help) >> 1); // SENS_2 = SENS_2 + 7 * (TEMP + 1500)^2/2^1 + } + } + + temp = temp - t_2; + off = off - off_2; + sens = sens - sens_2; + + dev->result.pressure = calc_p(raw_pressure, sens, off); + dev->result.temperature = (int32_t)temp; + return true; +} + +bool ms561101ba03_init(ms561101ba03_t *dev) +{ + // First of all we need to reset the chip + if(!reset(dev->addr)) + return false; + // Wait a bit for the device to reset + vTaskDelay(CONVERSION_TIME); + // Get the config + if(!read_prom(dev)) + return false; + // Every thing went fine + return true; +} diff --git a/extras/ms561101ba03/ms561101ba03.h b/extras/ms561101ba03/ms561101ba03.h new file mode 100644 index 0000000..d658be2 --- /dev/null +++ b/extras/ms561101ba03/ms561101ba03.h @@ -0,0 +1,96 @@ +/* + * Driver for barometic pressure sensor MS5611-01BA03 + * + * Copyright (C) 2016 Bernhard Guillon + * + * Loosely based on hmc5831 with: + * Copyright (C) 2016 Ruslan V. Uss + * BSD Licensed as described in the file LICENSE + */ +#ifndef EXTRAS_MS561101BA03_H_ +#define EXTRAS_MS561101BA03_H_ + +#include +#include + +#ifdef __cplusplus +extern "C" +{ +#endif + +#define MS561101BA03_ADDR_CSB_HIGH 0x76 +#define MS561101BA03_ADDR_CSB_LOW 0x77 + +/** + * Oversampling ratio + */ +typedef enum +{ + MS561101BA03_OSR_256 = 0x00, //!< 256 samples per measurement + MS561101BA03_OSR_512 = 0x02, //!< 512 samples per measurement + MS561101BA03_OSR_1024 = 0x04, //!< 1024 samples per measurement + MS561101BA03_OSR_2048 = 0x06, //!< 2048 samples per measurement + MS561101BA03_OSR_4096 = 0x08 //!< 4096 samples per measurement +} ms561101ba03_osr_t; + +/** + * Configuration data + */ +typedef struct +{ + uint16_t sens; //!< C1 Pressure sensitivity | SENS_t1 + uint16_t off; //!< C2 Pressure offset | OFF_t1 + uint16_t tcs; //!< C3 Temperature coefficient of pressure sensitivity | TCS + uint16_t tco; //!< C4 Temperature coefficient of pressuer offset | TCO + uint16_t t_ref; //!< C5 Reference temperature | T_ref + uint16_t tempsens; //!< C6 Temperature coefficient of the temperature | TEMPSENSE +} ms561101ba03_config_data_t; + +/** + * Result + */ +typedef struct +{ + int32_t pressure; //!< Compensated pressure from 10 mbar to 1200 mbar with 0.01 mbar resolution + int32_t temperature; //!< Temperature from -40 C to 85 C with 0.01 C resulution +} ms561101ba03_result_t; + +/** + * Device descriptor + */ +typedef struct +{ + uint8_t addr; //!< I2C address + ms561101ba03_osr_t osr; //!< Oversampling setting + ms561101ba03_config_data_t config_data; //!< Device configuration, filled upon initalize + ms561101ba03_result_t result; //!< Result, filled upon co + int32_t dT; //!< delta temperature, filled uppon co and for internal use only +} ms561101ba03_t; + +/** + * Initialize device and read its configuration + * @param dev Pointer to device descriptor + * @return true if no errors occured + */ +bool ms561101ba03_init(ms561101ba03_t *dev); + +/** + * Get sensor data with second order temperature compensation + * + * The result will be: + * Compensated pressure from 10 mbar to 1200 mbar with 0.01 mbar resolution + * dev->result.pressure + * + * Temperature from -40 C to 85 C with 0.01 C resulution + * dev->result.temperature + * + * @param dev Pointer to device descriptor + * @return true if no errors occured + */ +bool ms561101ba03_get_sensor_data(ms561101ba03_t *dev); + +#ifdef __cplusplus +} +#endif + +#endif /* EXTRAS_MS561101BA03_H_ */