vrahane closed pull request #998: Add driver for ms5840 pressure sensor
URL: https://github.com/apache/mynewt-core/pull/998
 
 
   

This is a PR merged from a forked repository.
As GitHub hides the original diff on merge, it is displayed below for
the sake of provenance:

As this is a foreign pull request (from a fork), the diff is supplied
below (as it won't show otherwise due to GitHub magic):

diff --git a/hw/drivers/sensors/ms5840/include/ms5840/ms5840.h 
b/hw/drivers/sensors/ms5840/include/ms5840/ms5840.h
new file mode 100644
index 000000000..97f45fc35
--- /dev/null
+++ b/hw/drivers/sensors/ms5840/include/ms5840/ms5840.h
@@ -0,0 +1,172 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+
+
+#ifndef __MS5840_H__
+#define __MS5840_H__
+
+#include <os/os.h>
+#include "os/os_dev.h"
+#include "sensor/sensor.h"
+
+#define MS5840_I2C_ADDRESS             0x76
+#define MS5840_NUMBER_COEFFS     7
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct ms5840_pdd {
+    uint16_t eeprom_coeff[MS5840_NUMBER_COEFFS + 1];
+};
+
+struct ms5840_cfg {
+    uint8_t mc_s_temp_res_osr;
+    uint8_t mc_s_press_res_osr;
+    sensor_type_t mc_s_mask;
+};
+
+struct ms5840 {
+    struct os_dev dev;
+    struct sensor sensor;
+    struct ms5840_cfg cfg;
+    struct ms5840_pdd pdd;
+    os_time_t last_read_time;
+};
+
+#define MS5840_RES_OSR_256    0x0
+#define MS5840_RES_OSR_512    0x2
+#define MS5840_RES_OSR_1024   0x4
+#define MS5840_RES_OSR_2048   0x6
+#define MS5840_RES_OSR_4096   0x8
+#define MS5840_RES_OSR_8192   0xA
+
+/**
+ * Initialize the ms5840.
+ *
+ * @param dev  Pointer to the ms5840_dev device descriptor
+ *
+ * @return 0 on success, and non-zero error code on failure
+ */
+int
+ms5840_init(struct os_dev *dev, void *arg);
+
+/**
+ * Reads the temperature ADC value
+ *
+ * @param the sensor interface
+ * @param raw adc temperature value
+ * @param resolution osr
+ *
+ * @return 0 on success, non-zero on failure
+ */
+int
+ms5840_get_rawtemp(struct sensor_itf *itf, uint32_t *rawtemp,
+                   uint8_t res_osr);
+
+/**
+ * Reads the pressure ADC value
+ *
+ * @param the sensor interface
+ * @param raw adc pressure value
+ * @param resolution osr
+ *
+ * @return 0 on success, non-zero on failure
+ */
+int
+ms5840_get_rawpress(struct sensor_itf *itf, uint32_t *rawpress,
+                    uint8_t res_osr);
+
+/**
+ * Resets the MS5840 chip
+ *
+ * @param The sensor interface
+ * @return 0 on success, non-zero on failure
+ */
+int
+ms5840_reset(struct sensor_itf *itf);
+
+/**
+ * Configure MS5840 sensor
+ *
+ * @param Sensor device MS5840 structure
+ * @param Sensor device MS5840 config
+ *
+ * @return 0 on success, and non-zero error code on failure
+ */
+int
+ms5840_config(struct ms5840 *ms5840, struct ms5840_cfg *cfg);
+
+/**
+ * crc4 check for MS5840 EEPROM
+ *
+ * @param buffer containing EEPROM coefficients
+ * @param crc to compare with
+ *
+ * return 0 on success (CRC is OK), non-zero on failure
+ */
+int
+ms5840_crc_check(uint16_t *prom, uint8_t crc);
+
+/**
+ * Reads the ms5840 EEPROM coefficients for computation and
+ * does a CRC check on them
+ *
+ * @param the sensor interface
+ * @param buffer to fill up the coefficients
+ *
+ * @return 0 on success, non-zero on failure
+ */
+int
+ms5840_read_eeprom(struct sensor_itf *itf, uint16_t *coeff);
+
+/**
+ * Compensate for pressure using coefficients from the EEPROM
+ *
+ * @param ptr to coefficients
+ * @param first order compensated temperature
+ * @param raw pressure
+ * @param deltat temperature
+ *
+ * @return second order temperature compensated pressure
+ */
+float
+ms5840_compensate_pressure(uint16_t *coeffs, int32_t temp,
+                           uint32_t rawpress, int32_t deltat);
+
+/**
+ * Compensate for temperature using coefficients from the EEPROM
+ *
+ * @param ptr to coefficients
+ * @param compensated temperature
+ * @param raw temperature
+ * @param optional ptr to fill up first order compensated temperature
+ * @param optional ptr to fill up delta temperature
+ *
+ * @return second order temperature compensated temperature
+ */
+float
+ms5840_compensate_temperature(uint16_t *coeffs, uint32_t rawtemp,
+                              int32_t *comptemp, int32_t *deltat);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __MS5840_H__ */
diff --git a/hw/drivers/sensors/ms5840/pkg.yml 
b/hw/drivers/sensors/ms5840/pkg.yml
new file mode 100644
index 000000000..c75b2054c
--- /dev/null
+++ b/hw/drivers/sensors/ms5840/pkg.yml
@@ -0,0 +1,37 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you 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.
+#
+
+pkg.name: hw/drivers/sensors/ms5840
+pkg.description: Driver for the MS5840 pressure sensor
+pkg.author: "Vipul Rahane <vi...@runtime.io>"
+pkg.homepage: "http://www.runtime.io/";
+pkg.keywords:
+    - TE connectivity
+    - ms5840
+    - i2c
+    - sensor
+
+pkg.deps:
+    - "@apache-mynewt-core/kernel/os"
+    - "@apache-mynewt-core/hw/hal"
+    - "@apache-mynewt-core/hw/sensor"
+
+pkg.req_apis:
+    - stats
+    - log
diff --git a/hw/drivers/sensors/ms5840/src/ms5840.c 
b/hw/drivers/sensors/ms5840/src/ms5840.c
new file mode 100644
index 000000000..3205d3585
--- /dev/null
+++ b/hw/drivers/sensors/ms5840/src/ms5840.c
@@ -0,0 +1,690 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 <assert.h>
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+
+#include "defs/error.h"
+#include "os/os.h"
+#include "sysinit/sysinit.h"
+#include "hal/hal_i2c.h"
+#include "sensor/sensor.h"
+#include "ms5840/ms5840.h"
+#include "sensor/temperature.h"
+#include "sensor/pressure.h"
+#include "ms5840_priv.h"
+#include "os/os_cputime.h"
+#include "console/console.h"
+#include "log/log.h"
+#include "stats/stats.h"
+
+static uint16_t cnv_time[6] = {
+    MS5840_CNV_TIME_OSR_256,
+    MS5840_CNV_TIME_OSR_512,
+    MS5840_CNV_TIME_OSR_1024,
+    MS5840_CNV_TIME_OSR_2048,
+    MS5840_CNV_TIME_OSR_4096,
+    MS5840_CNV_TIME_OSR_8192
+};
+
+/* Define the stats section and records */
+STATS_SECT_START(ms5840_stat_section)
+    STATS_SECT_ENTRY(read_errors)
+    STATS_SECT_ENTRY(write_errors)
+    STATS_SECT_ENTRY(eeprom_crc_errors)
+STATS_SECT_END
+
+/* Define stat names for querying */
+STATS_NAME_START(ms5840_stat_section)
+    STATS_NAME(ms5840_stat_section, read_errors)
+    STATS_NAME(ms5840_stat_section, write_errors)
+    STATS_NAME(ms5840_stat_section, eeprom_crc_errors)
+STATS_NAME_END(ms5840_stat_section)
+
+/* Global variable used to hold stats data */
+STATS_SECT_DECL(ms5840_stat_section) g_ms5840stats;
+
+#define LOG_MODULE_MS5840    (5840)
+#define MS5840_INFO(...)     LOG_INFO(&_log, LOG_MODULE_MS5840, __VA_ARGS__)
+#define MS5840_ERR(...)      LOG_ERROR(&_log, LOG_MODULE_MS5840, __VA_ARGS__)
+static struct log _log;
+
+/* Exports for the sensor API */
+static int ms5840_sensor_read(struct sensor *, sensor_type_t,
+        sensor_data_func_t, void *, uint32_t);
+static int ms5840_sensor_get_config(struct sensor *, sensor_type_t,
+        struct sensor_cfg *);
+static int ms5840_sensor_set_config(struct sensor *, void *);
+
+static const struct sensor_driver g_ms5840_sensor_driver = {
+    .sd_read = ms5840_sensor_read,
+    .sd_get_config = ms5840_sensor_get_config,
+    .sd_set_config = ms5840_sensor_set_config,
+};
+
+/**
+ * Expects to be called back through os_dev_create().
+ *
+ * @param The device object associated with ms5840
+ * @param Argument passed to OS device init, unused
+ *
+ * @return 0 on success, non-zero error on failure.
+ */
+int
+ms5840_init(struct os_dev *dev, void *arg)
+{
+    struct ms5840 *ms5840;
+    struct sensor *sensor;
+    struct sensor_itf *itf;
+    int rc;
+
+    if (!arg || !dev) {
+        rc = SYS_ENODEV;
+        goto err;
+    }
+
+    ms5840 = (struct ms5840 *)dev;
+
+    log_register(dev->od_name, &_log, &log_console_handler, NULL, 
LOG_SYSLEVEL);
+
+    sensor = &ms5840->sensor;
+
+    itf = SENSOR_GET_ITF(sensor);
+
+    /* Initialise the stats entry */
+    rc = stats_init(
+        STATS_HDR(g_ms5840stats),
+        STATS_SIZE_INIT_PARMS(g_ms5840stats, STATS_SIZE_32),
+        STATS_NAME_INIT_PARMS(ms5840_stat_section));
+    SYSINIT_PANIC_ASSERT(rc == 0);
+    /* Register the entry with the stats registry */
+    rc = stats_register(dev->od_name, STATS_HDR(g_ms5840stats));
+    SYSINIT_PANIC_ASSERT(rc == 0);
+
+    rc = sensor_init(sensor, dev);
+    if (rc != 0) {
+        goto err;
+    }
+
+    /* Add the driver with all the supported type */
+    rc = sensor_set_driver(sensor, SENSOR_TYPE_AMBIENT_TEMPERATURE |
+                           SENSOR_TYPE_PRESSURE,
+                           (struct sensor_driver *)&g_ms5840_sensor_driver);
+    if (rc) {
+        goto err;
+    }
+
+    /* Set the interface */
+    rc = sensor_set_interface(sensor, arg);
+    if (rc) {
+        goto err;
+    }
+
+    rc = sensor_mgr_register(sensor);
+    if (rc) {
+        goto err;
+    }
+
+    rc = ms5840_read_eeprom(itf, ms5840->pdd.eeprom_coeff);
+    if (rc) {
+        goto err;
+    }
+
+    return 0;
+err:
+    return rc;
+
+}
+
+static int
+ms5840_sensor_read(struct sensor *sensor, sensor_type_t type,
+        sensor_data_func_t data_func, void *data_arg, uint32_t timeout)
+{
+    uint32_t rawtemp;
+    uint32_t rawpress;
+    int32_t comptemp;
+    int32_t deltat;
+    float temperature;
+    float pressure;
+    struct sensor_itf *itf;
+    struct ms5840 *ms5840;
+    struct ms5840_cfg *cfg;
+
+    int rc;
+    union {
+        struct sensor_temp_data std;
+        struct sensor_press_data spd;
+    } databuf;
+
+    if (!(type & SENSOR_TYPE_PRESSURE)    &&
+        !(type & SENSOR_TYPE_AMBIENT_TEMPERATURE)) {
+        rc = SYS_EINVAL;
+        goto err;
+    }
+
+    itf = SENSOR_GET_ITF(sensor);
+
+    ms5840 = (struct ms5840 *)SENSOR_GET_DEVICE(sensor);
+
+    cfg = &(ms5840->cfg);
+
+    temperature = pressure = 0;
+
+    /* Get a new pressure sample */
+    if (type & SENSOR_TYPE_PRESSURE) {
+        rc = ms5840_get_rawtemp(itf, &rawtemp, cfg->mc_s_temp_res_osr);
+        if (rc) {
+            goto err;
+        }
+
+        rc = ms5840_get_rawpress(itf, &rawpress, cfg->mc_s_press_res_osr);
+        if (rc) {
+            goto err;
+        }
+
+        /* compensate using temperature and pressure coefficients
+         * competemp is the first order compensated temperature
+         * which is used as input to the pressure compensation
+         */
+        temperature = ms5840_compensate_temperature(ms5840->pdd.eeprom_coeff, 
rawtemp,
+                                                    &comptemp, &deltat);
+        pressure = ms5840_compensate_pressure(ms5840->pdd.eeprom_coeff, 
comptemp,
+                                              rawpress, deltat);
+
+        databuf.spd.spd_press = pressure;
+        databuf.spd.spd_press_is_valid = 1;
+
+        /* Call data function */
+        rc = data_func(sensor, data_arg, &databuf.spd, SENSOR_TYPE_PRESSURE);
+        if (rc) {
+            goto err;
+        }
+    }
+
+    /* Get a new temperature sample */
+    if (type & SENSOR_TYPE_AMBIENT_TEMPERATURE) {
+        if (!temperature) {
+            rc = ms5840_get_rawtemp(itf, &rawtemp, cfg->mc_s_temp_res_osr);
+            if (rc) {
+                goto err;
+            }
+
+            temperature = 
ms5840_compensate_temperature(ms5840->pdd.eeprom_coeff, rawtemp,
+                                                        NULL, NULL);
+        }
+
+        databuf.std.std_temp = temperature;
+        databuf.std.std_temp_is_valid = 1;
+
+        /* Call data function */
+        rc = data_func(sensor, data_arg, &databuf.std,
+                       SENSOR_TYPE_AMBIENT_TEMPERATURE);
+        if (rc) {
+            goto err;
+        }
+    }
+    
+    return 0;
+err:
+    return rc;
+}
+
+static int
+ms5840_sensor_get_config(struct sensor *sensor, sensor_type_t type,
+        struct sensor_cfg *cfg)
+{
+    int rc;
+
+    if (!(type & SENSOR_TYPE_PRESSURE) ||
+        !(type & SENSOR_TYPE_AMBIENT_TEMPERATURE)) {
+        rc = SYS_EINVAL;
+        goto err;
+    }
+
+    cfg->sc_valtype = SENSOR_VALUE_TYPE_FLOAT;
+
+    return (0);
+err:
+    return (rc);
+}
+
+static int
+ms5840_sensor_set_config(struct sensor *sensor, void *cfg)
+{
+    struct ms5840* ms5840 = (struct ms5840 *)SENSOR_GET_DEVICE(sensor);
+    
+    return ms5840_config(ms5840, (struct ms5840_cfg*)cfg);
+}
+
+/**
+ * Configure MS5840 sensor
+ *
+ * @param Sensor device MS5840 structure
+ * @param Sensor device MS5840 config
+ *
+ * @return 0 on success, non-zero on failure
+ */
+int
+ms5840_config(struct ms5840 *ms5840, struct ms5840_cfg *cfg)
+{
+    int rc;
+    struct sensor_itf *itf;
+
+    itf = SENSOR_GET_ITF(&(ms5840->sensor));
+
+    rc = ms5840_reset(itf);
+    if (rc) {
+        goto err;
+    }
+
+    rc = sensor_set_type_mask(&(ms5840->sensor),  cfg->mc_s_mask);
+    if (rc) {
+        goto err;
+    }
+
+    ms5840->cfg.mc_s_temp_res_osr = cfg->mc_s_temp_res_osr;
+
+    ms5840->cfg.mc_s_press_res_osr = cfg->mc_s_press_res_osr;
+
+    ms5840->cfg.mc_s_mask = cfg->mc_s_mask;
+
+    return 0;
+err:
+    return (rc);
+}
+
+/**
+ * Write multiple length data to MS5840 sensor over I2C
+ *
+ * @param The sensor interface
+ * @param register address
+ * @param variable length payload
+ * @param length of the payload to write
+ *
+ * @return 0 on success, non-zero on failure
+ */
+int
+ms5840_writelen(struct sensor_itf *itf, uint8_t addr, uint8_t *buffer,
+                uint8_t len)
+{
+    int rc;
+
+    struct hal_i2c_master_data data_struct = {
+        .address = itf->si_addr,
+        .len = 1,
+        .buffer = &addr
+    };
+
+    /* Register write */
+    rc = hal_i2c_master_write(itf->si_num, &data_struct, OS_TICKS_PER_SEC / 
10, 1);
+    if (rc) {
+        MS5840_ERR("I2C write command write failed at address 0x%02X\n",
+                   data_struct.address);
+        STATS_INC(g_ms5840stats, write_errors);
+        goto err;
+    }
+
+    return 0;
+err:
+    return rc;
+}
+
+/**
+ * Read multiple length data from MS5840 sensor over I2C
+ *
+ * @param The sensor interface
+ * @param register address
+ * @param variable length buffer
+ * @param length of the payload to read
+ *
+ * @return 0 on success, non-zero on failure
+ */
+int
+ms5840_readlen(struct sensor_itf *itf, uint8_t addr, uint8_t *buffer,
+               uint8_t len)
+{
+    int rc;
+    uint8_t payload[3] = {addr, 0, 0};
+
+    struct hal_i2c_master_data data_struct = {
+        .address = itf->si_addr,
+        .len = 1,
+        .buffer = payload
+    };
+
+    /* Clear the supplied buffer */
+    memset(buffer, 0, len);
+
+    /* Command write */
+    rc = hal_i2c_master_write(itf->si_num, &data_struct, OS_TICKS_PER_SEC / 
10, 1);
+    if (rc) {
+        MS5840_ERR("I2C read command write failed at address 0x%02X\n",
+                   data_struct.address);
+        STATS_INC(g_ms5840stats, write_errors);
+        goto err;
+    }
+
+    /* Read len bytes back */
+    memset(payload, 0, sizeof(payload));
+    data_struct.len = len;
+    rc = hal_i2c_master_read(itf->si_num, &data_struct, OS_TICKS_PER_SEC / 10, 
1);
+    if (rc) {
+        MS5840_ERR("Failed to read from 0x%02X:0x%02X\n", data_struct.address, 
addr);
+        STATS_INC(g_ms5840stats, read_errors);
+        goto err;
+    }
+
+    /* Copy the I2C results into the supplied buffer */
+    memcpy(buffer, payload, len);
+
+    return 0;
+err:
+    return rc;
+}
+
+/**
+ * Reads the ms5840 EEPROM coefficients for computation and
+ * does a CRC check on them
+ *
+ * @param the sensor interface
+ * @param buffer to fill up the coefficients
+ *
+ * @return 0 on success, non-zero on failure
+ */
+int
+ms5840_read_eeprom(struct sensor_itf *itf, uint16_t *coeff)
+{
+    int idx;
+    int rc;
+    uint16_t payload[MS5840_NUMBER_COEFFS];
+
+    for(idx = 0; idx < MS5840_NUMBER_COEFFS; idx++) {
+        rc = ms5840_readlen(itf, MS5840_CMD_PROM_READ_ADDR0 + idx * 2,
+                            (uint8_t *)(payload + idx), 2);
+        if (rc) {
+            goto err;
+        }
+
+        payload[idx] = (((payload[idx] & 0xFF00) >> 8)|
+                        ((payload[idx] & 0x00FF) << 8));
+    }
+
+    rc = ms5840_crc_check(payload, (payload[MS5840_IDX_CRC] & 0xF000) >> 12);
+    if (rc) {
+        rc = SYS_EINVAL;
+        MS5840_ERR("Failure in CRC, 0x%02X\n",
+                   payload[MS5840_IDX_CRC] &  0xF000 >> 12);
+        STATS_INC(g_ms5840stats, eeprom_crc_errors);
+        goto err;
+    }
+
+    memcpy(coeff, payload, sizeof(payload));
+
+    return 0;
+err:
+    return rc;
+}
+
+/**
+ * Compensate for pressure using coefficients from the EEPROM
+ *
+ * @param ptr to coefficients
+ * @param first order compensated temperature
+ * @param raw pressure
+ * @param deltat temperature
+ *
+ * @return second order temperature compensated pressure
+ */
+float
+ms5840_compensate_pressure(uint16_t *coeffs, int32_t temp,
+                           uint32_t rawpress, int32_t deltat)
+{
+    int64_t off, sens, off2, sens2;
+
+    off2 = sens2 = 0;
+
+    /* off = off_T1 + TCO * dt */
+    off = ((int64_t)(coeffs[MS5840_IDX_PRESS_OFF]) << 17) +
+          (((int64_t)(coeffs[MS5840_IDX_TEMP_COEFF_PRESS_OFF]) * deltat) >> 6);
+
+    /* sensitivity at actual temperature = sens_T1 + TCS * dt */
+    sens = ((int64_t)coeffs[MS5840_IDX_PRESS_SENS] << 16) +
+           (((int64_t)coeffs[MS5840_IDX_TEMP_COEFF_PRESS_SENS] * deltat) >> 7);
+
+    /* second order temperature compensation */
+    if(temp < 1000) {
+        /* low temperature */
+        off2 = (35 * ((int64_t)temp - 2000) * ((int64_t)temp - 2000)) >> 3;
+        sens2 = (63 * ((int64_t)temp - 2000) * ((int64_t)temp - 2000)) >> 5;
+    } else if (temp < 2000) {
+        off2 = (30 * ((int64_t)temp - 2000) * ((int64_t)temp - 2000)) >> 8;
+    }
+
+    off2  = off - off2;
+
+    sens2 = sens - sens2;
+
+    /* temperature compensated second order pressure = D1 * sens - off */
+    return ((float)(((rawpress * sens2) >> 21) - off2)/32768);
+}
+
+/**
+ * Compensate for temperature using coefficients from the EEPROM
+ *
+ * @param ptr to coefficients
+ * @param compensated temperature
+ * @param raw temperature
+ * @param optional ptr to fill up first order compensated temperature
+ * @param optional ptr to fill up delta temperature
+ *
+ * @return second order temperature compensated temperature
+ */
+float
+ms5840_compensate_temperature(uint16_t *coeffs, uint32_t rawtemp,
+                              int32_t *comptemp, int32_t *deltat)
+{
+    int32_t dt, temp;
+    int64_t t2;
+
+    t2 = 0;
+
+    /* difference between actual and reference temperature = D2 - Tref */
+    dt = (int32_t)rawtemp - ((int32_t)coeffs[MS5840_IDX_REF_TEMP] << 8);
+
+    /* actual temperature = 2000 + dt * tempsens */
+    temp = 2000 + ((int64_t)((int64_t)dt * 
(int64_t)coeffs[MS5840_IDX_TEMP_COEFF_TEMP]) >> 23);
+
+    if (comptemp) {
+        *comptemp = temp;
+    }
+
+    if (deltat) {
+        *deltat = dt;
+    }
+
+    if(temp < 1000) {
+        /* low temperature */
+        t2 = (11 * (int64_t)dt  * (int64_t)dt) >> 35;
+    }
+
+    /* second order temperature */
+    return (((float)temp - t2)/100);
+}
+
+/**
+ * Triggers conversion and reads ADC value
+ *
+ * @param the sensor interface
+ * @param cmd used for conversion, considers temperature, pressure and OSR
+ * @param ptr to ADC value
+ *
+ * @return 0 on success, non-zero on failure
+ */
+static int
+ms5840_get_raw_data(struct sensor_itf *itf, uint8_t cmd, uint32_t *data)
+{
+    int rc;
+    uint8_t payload[3] = {0};
+
+    /* send conversion command based on OSR, temperature and pressure */
+    rc = ms5840_writelen(itf, cmd, payload, 0);
+    if (rc) {
+        goto err;
+    }
+
+    /* delay conversion depending on resolution */
+    os_cputime_delay_usecs(cnv_time[(cmd & MS5840_CNV_OSR_MASK)/2]);
+
+    /* read adc value */
+    rc = ms5840_readlen(itf, MS5840_CMD_ADC_READ, payload, 3);
+    if (rc) {
+        goto err;
+    }
+
+    *data = ((uint32_t)payload[0] << 16) | ((uint32_t)payload[1] << 8) | 
payload[2];
+
+    return 0;
+err:
+    return rc;
+}
+
+/**
+ * Reads the temperature ADC value
+ *
+ * @param the sensor interface
+ * @param raw adc temperature value
+ * @param resolution osr
+ *
+ * @return 0 on success, non-zero on failure
+ */
+int
+ms5840_get_rawtemp(struct sensor_itf *itf, uint32_t *rawtemp,
+                   uint8_t res_osr)
+{
+    uint8_t cmd;
+    uint32_t tmp;
+    int rc;
+
+    /* read temperature ADC value */
+    cmd = res_osr | MS5840_CMD_TEMP;
+    rc = ms5840_get_raw_data(itf, cmd, &tmp);
+    if (rc) {
+        goto err;
+    }
+
+    *rawtemp = tmp;
+
+    return 0;
+err:
+    return rc;
+}
+
+/**
+ * Reads the pressure ADC value
+ *
+ * @param the sensor interface
+ * @param raw adc pressure value
+ * @param resolution osr
+ *
+ * @return 0 on success, non-zero on failure
+ */
+int
+ms5840_get_rawpress(struct sensor_itf *itf, uint32_t *rawpress,
+                    uint8_t res_osr)
+{
+    uint8_t cmd;
+    uint32_t tmp;
+    int rc;
+
+    /* read pressure ADC value */
+    cmd = res_osr | MS5840_CMD_PRESS;
+    rc = ms5840_get_raw_data(itf, cmd, &tmp);
+    if (rc) {
+        goto err;
+    }
+
+    *rawpress = tmp;
+
+    return 0;
+err:
+    return rc;
+}
+
+/**
+ * Resets the MS5840 chip
+ *
+ * @param the sensor interface
+ *
+ * @return 0 on success, non-zero on failure
+ */
+int
+ms5840_reset(struct sensor_itf *itf)
+{
+    uint8_t txdata;
+
+    txdata = 0;
+
+    return ms5840_writelen(itf, MS5840_CMD_RESET, &txdata, 0);
+}
+
+/**
+ * crc4 check for MS5840 EEPROM
+ *
+ * @param buffer containing EEPROM coefficients
+ * @param crc to compare with
+ *
+ * return 0 on success (CRC is OK), non-zero on failure
+ */
+int
+ms5840_crc_check(uint16_t *prom, uint8_t crc)
+{
+    uint8_t cnt, bit;
+    uint16_t rem, crc_read;
+
+    rem = 0x00;
+    crc_read = prom[0];
+    prom[MS5840_NUMBER_COEFFS] = 0;
+
+    /* Clear the CRC byte */
+    prom[0] = (0x0FFF & prom[0]);
+
+    for(cnt = 0; cnt < (MS5840_NUMBER_COEFFS + 1) * 2; cnt++) {
+        /* Get next byte */
+        if (cnt%2 == 1) {
+            rem ^=  (prom[cnt>>1] & 0x00FF);
+        } else {
+            rem ^=  (prom[cnt>>1] >> 8);
+        }
+
+        for(bit = 8; bit > 0; bit--) {
+            if(rem & 0x8000) {
+                rem = (rem << 1) ^ 0x3000;
+            } else {
+                rem <<= 1;
+            }
+        }
+    }
+
+    rem >>= 12;
+    prom[0] = crc_read;
+
+    return  (rem != crc);
+}
diff --git a/hw/drivers/sensors/ms5840/src/ms5840_priv.h 
b/hw/drivers/sensors/ms5840/src/ms5840_priv.h
new file mode 100644
index 000000000..dfd33a892
--- /dev/null
+++ b/hw/drivers/sensors/ms5840/src/ms5840_priv.h
@@ -0,0 +1,113 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+
+#ifndef __MS5840_PRIV_H__
+#define __MS5840_PRIV_H__
+
+/* Commands */
+#define MS5840_CMD_RESET            0x1E
+/* Max conversion time: 0.56 ms ; 0.11  mbar RMS resolution */
+#define MS5840_CMD_D1_256           MS5840_CMD_PRESS|MS5840_RES_OSR_256
+/* Max conversion time: 1.10 ms : 0.062 mbar RMS resolution */
+#define MS5840_CMD_D1_512           MS5840_CMD_PRESS|MS5840_RES_OSR_512
+/* Max conversion time: 2.17 ms : 0.039 mbar RMS resolution */
+#define MS5840_CMD_D1_1024          MS5840_CMD_PRESS|MS5840_RES_OSR_1024
+/* Max conversion time: 4.32 ms ; 0.028 mbar RMS resolution */
+#define MS5840_CMD_D1_2048          MS5840_CMD_PRESS|MS5840_RES_OSR_2048
+/* Max conversion time: 8.61 ms : 0.021 mbar RMS resolution */
+#define MS5840_CMD_D1_4096          MS5840_CMD_PRESS|MS5840_RES_OSR_4096
+/* Max conversion time: 17.2 ms : 0.016 mbar RMS resolution */
+#define MS5840_CMD_D1_8192          MS5840_CMD_PRESS|MS5840_RES_OSR_8192
+/* Max conversion time: 0.56 ms : 0.012   °C RMS resolution */
+#define MS5840_CMD_D2_256           MS5840_CMD_TEMP|MS5840_RES_OSR_256
+/* Max conversion time: 1.10 ms : 0.009   °C RMS resolution */
+#define MS5840_CMD_D2_512           MS5840_CMD_TEMP|MS5840_RES_OSR_512
+/* Max conversion time: 2.17 ms : 0.006   °C RMS resolution */
+#define MS5840_CMD_D2_1024          MS5840_CMD_TEMP|MS5840_RES_OSR_1024
+/* Max conversion time: 4.32 ms ; 0.004   °C RMS resolution */
+#define MS5840_CMD_D2_2048          MS5840_CMD_TEMP|MS5840_RES_OSR_2048
+/* Max conversion time: 8.61 ms : 0.003   °C RMS resolution */
+#define MS5840_CMD_D2_4096          MS5840_CMD_TEMP|MS5840_RES_OSR_4096
+/* Max conversion time: 17.2 ms : 0.002   °C RMS resolution */
+#define MS5840_CMD_D2_8192          MS5840_CMD_TEMP|MS5840_RES_OSR_8192
+
+#define MS5840_CMD_ADC_READ         0x00
+#define MS5840_CMD_PRESS            0x40
+#define MS5840_CMD_TEMP             0x50
+#define MS5840_CMD_PROM_READ        0xA0
+
+/* PROM Address commands */
+#define MS5840_CMD_PROM_READ_ADDR0  0xA0
+#define MS5840_CMD_PROM_READ_ADDR1  0xA2
+#define MS5840_CMD_PROM_READ_ADDR2  0xA4
+#define MS5840_CMD_PROM_READ_ADDR3  0xA6
+#define MS5840_CMD_PROM_READ_ADDR4  0xA8
+#define MS5840_CMD_PROM_READ_ADDR5  0xAA
+#define MS5840_CMD_PROM_READ_ADDR6  0xAC
+#define MS5840_CMD_PROM_READ_ADDR7  0xAE
+
+/* Conversion time in micro seconds */
+#define MS5840_CNV_TIME_OSR_256      560
+#define MS5840_CNV_TIME_OSR_512     1100
+#define MS5840_CNV_TIME_OSR_1024    2170
+#define MS5840_CNV_TIME_OSR_2048    4320
+#define MS5840_CNV_TIME_OSR_4096    8610
+#define MS5840_CNV_TIME_OSR_8192   17200
+
+/* Coefficient EEPROM indexes for temperature and pressure compensation */
+#define MS5840_IDX_CRC                      0
+#define MS5840_IDX_PRESS_SENS               1
+#define MS5840_IDX_PRESS_OFF                2
+#define MS5840_IDX_TEMP_COEFF_PRESS_SENS    3
+#define MS5840_IDX_TEMP_COEFF_PRESS_OFF     4
+#define MS5840_IDX_REF_TEMP                 5
+#define MS5840_IDX_TEMP_COEFF_TEMP          6
+#define MS5840_NUMBER_COEFFS                7
+
+#define MS5840_CNV_OSR_MASK         0x0F
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Write multiple length data to MS5840 sensor over I2C
+ *
+ * @param The sensor interface
+ * @param register address
+ * @param variable length payload
+ * @param length of the payload to write
+ */
+int ms5840_writelen(struct sensor_itf *itf, uint8_t addr, uint8_t *payload, 
uint8_t len);
+
+/**
+ * Read multiple length data from MS5840 sensor over I2C
+ *
+ * @param The sensor interface
+ * @param register address
+ * @param variable length payload
+ * @param length of the payload to read
+ */
+int ms5840_readlen(struct sensor_itf *itf, uint8_t addr, uint8_t *payload, 
uint8_t len);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __MS5840_PRIV_H_ */
diff --git a/hw/sensor/creator/pkg.yml b/hw/sensor/creator/pkg.yml
index 3039501c0..1c6a2ecd6 100644
--- a/hw/sensor/creator/pkg.yml
+++ b/hw/sensor/creator/pkg.yml
@@ -40,6 +40,8 @@ pkg.deps.TCS34725_OFB:
     - hw/drivers/sensors/tcs34725
 pkg.deps.MS5837_OFB:
     - hw/drivers/sensors/ms5837
+pkg.deps.MS5840_OFB:
+    - hw/drivers/sensors/ms5840
 pkg.deps.MCU_NATIVE:
     - hw/drivers/sensors/sim
 pkg.deps.BMP280_OFB:
diff --git a/hw/sensor/creator/src/sensor_creator.c 
b/hw/sensor/creator/src/sensor_creator.c
index 40e393923..b198e68a4 100644
--- a/hw/sensor/creator/src/sensor_creator.c
+++ b/hw/sensor/creator/src/sensor_creator.c
@@ -50,6 +50,10 @@
 #include <ms5837/ms5837.h>
 #endif
 
+#if MYNEWT_VAL(MS5840_OFB)
+#include <ms5840/ms5840.h>
+#endif
+
 #if MYNEWT_VAL(BMP280_OFB)
 #include <bmp280/bmp280.h>
 #endif
@@ -104,6 +108,10 @@ static struct bme280 bme280;
 static struct ms5837 ms5837;
 #endif
 
+#if MYNEWT_VAL(MS5840_OFB)
+static struct ms5840 ms5840;
+#endif
+
 #if MYNEWT_VAL(BMP280_OFB)
 static struct bmp280 bmp280;
 #endif
@@ -220,6 +228,16 @@ static struct sensor_itf i2c_0_itf_ms = {
 };
 #endif
 
+#if MYNEWT_VAL(I2C_0) && MYNEWT_VAL(MS5840_OFB)
+static struct sensor_itf i2c_0_itf_ms = {
+    .si_type = SENSOR_ITF_I2C,
+    .si_num  = 0,
+    /* HW I2C address for the MS5840 */
+    .si_addr = 0x76
+};
+#endif
+
+
 #if MYNEWT_VAL(I2C_0) && MYNEWT_VAL(BMA253_OFB)
 static struct sensor_itf i2c_0_itf_lis = {
     .si_type = SENSOR_ITF_I2C,
@@ -295,6 +313,38 @@ config_ms5837_sensor(void)
 }
 #endif
 
+/**
+ * MS5840 Sensor default configuration used by the creator package
+ *
+ * @return 0 on success, non-zero on failure
+ */
+#if MYNEWT_VAL(MS5840_OFB)
+static int
+config_ms5840_sensor(void)
+{
+    int rc;
+    struct os_dev *dev;
+    struct ms5840_cfg mscfg;
+
+    dev = (struct os_dev *) os_dev_open("ms5840_0", OS_TIMEOUT_NEVER, NULL);
+    assert(dev != NULL);
+
+    memset(&mscfg, 0, sizeof(mscfg));
+
+
+    mscfg.mc_s_temp_res_osr  = MS5840_RES_OSR_256;
+    mscfg.mc_s_press_res_osr = MS5840_RES_OSR_256;
+    mscfg.mc_s_mask = SENSOR_TYPE_AMBIENT_TEMPERATURE|
+                      SENSOR_TYPE_PRESSURE;
+
+    rc = ms5840_config((struct ms5840 *)dev, &mscfg);
+
+    os_dev_close(dev);
+    return rc;
+}
+#endif
+
+
 /* Sensor default configuration used by the creator package */
 
 /**
@@ -826,6 +876,15 @@ sensor_dev_create(void)
     assert(rc == 0);
 #endif
 
+#if MYNEWT_VAL(MS5840_OFB)
+    rc = os_dev_create((struct os_dev *) &ms5840, "ms5840_0",
+      OS_DEV_INIT_PRIMARY, 0, ms5840_init, (void *)&i2c_0_itf_ms);
+    assert(rc == 0);
+
+    rc = config_ms5840_sensor();
+    assert(rc == 0);
+#endif
+
 #if MYNEWT_VAL(BMP280_OFB)
     rc = os_dev_create((struct os_dev *) &bmp280, "bmp280_0",
       OS_DEV_INIT_PRIMARY, 0, bmp280_init, (void *)&i2c_0_itf_bmp);
diff --git a/hw/sensor/creator/syscfg.yml b/hw/sensor/creator/syscfg.yml
index 1f761998b..2d750c8c5 100644
--- a/hw/sensor/creator/syscfg.yml
+++ b/hw/sensor/creator/syscfg.yml
@@ -40,6 +40,9 @@ syscfg.defs:
     MS5837_OFB:
         description: 'MS5837 is present'
         value : 0
+    MS5840_OFB:
+        description: 'MS5840 is present'
+        value : 0
     BMP280_OFB:
         description: 'BMP280 is present'
         value : 0


 

----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on GitHub and use the
URL above to go to the specific comment.
 
For queries about this service, please contact Infrastructure at:
us...@infra.apache.org


With regards,
Apache Git Services

Reply via email to