Просмотр исходного кода

Added support for the BMP280 sensor. Minor changes in the sensor API

Victor 3 лет назад
Родитель
Сommit
e3e3b18bf9
10 измененных файлов с 275 добавлено и 85 удалено
  1. 17 4
      Sensors.c
  2. 1 1
      Sensors.h
  3. 11 1
      interfaces/I2CSensor.c
  4. 9 1
      interfaces/I2CSensor.h
  5. 3 2
      interfaces/SingleWireSensor.c
  6. 1 1
      interfaces/SingleWireSensor.h
  7. 179 49
      sensors/BMP280.c
  8. 51 24
      sensors/BMP280.h
  9. 2 1
      sensors/LM75.c
  10. 1 1
      sensors/LM75.h

+ 17 - 4
Sensors.c

@@ -34,7 +34,8 @@ const GPIO GPIOList[] = {
     {17, "17 (1W)", &ibutton_gpio}};
 
 //Перечень датчиков
-static const SensorType* sensorTypes[] = {&DHT11, &DHT12_SW, &DHT21, &DHT22, &AM2320_SW, &LM75};
+static const SensorType* sensorTypes[] =
+    {&DHT11, &DHT12_SW, &DHT21, &DHT22, &AM2320_SW, &LM75, &BMP280};
 
 const SensorType* unitemp_getTypeFromInt(int type) {
     if(type > SENSOR_TYPES_COUNT) return NULL;
@@ -267,13 +268,19 @@ void unitemp_sensor_free(Sensor* sensor) {
         FURI_LOG_E(APP_NAME, "Sensor releaser is null");
         return;
     }
+    bool status = false;
     //Высвобождение памяти под инстанс
     if(sensor->type->interface == SINGLE_WIRE) {
-        sensor->type->mem_releaser(sensor);
+        status = sensor->type->mem_releaser(sensor);
     }
 
     if(sensor->type->interface == I2C) {
-        unitemp_I2C_sensorFree(sensor);
+        status = unitemp_I2C_sensorFree(sensor);
+    }
+    if(status) {
+        FURI_LOG_D(APP_NAME, "Sensor %s memory successfully released", sensor->name);
+    } else {
+        FURI_LOG_E(APP_NAME, "Sensor %s memory is not released", sensor->name);
     }
     free(sensor->name);
     free(sensor);
@@ -348,7 +355,13 @@ UnitempStatus unitemp_sensor_updateData(Sensor* sensor) {
         furi_hal_power_enable_otg();
     }
 
-    sensor->status = sensor->type->updater(sensor);
+    if(sensor->type->interface == I2C) {
+        sensor->status = unitemp_I2C_sensor_update(sensor);
+    }
+    if(sensor->type->interface == SINGLE_WIRE) {
+        sensor->status = sensor->type->updater(sensor);
+    }
+
     FURI_LOG_D(APP_NAME, "Sensor %s update status %d", sensor->name, sensor->status);
     if(app->settings.unit == FAHRENHEIT && sensor->status == UT_OK)
         uintemp_celsiumToFarengate(sensor);

+ 1 - 1
Sensors.h

@@ -36,7 +36,7 @@ typedef bool(SensorAllocator)(void* sensor, uint16_t* anotherValues);
 /**
  * @brief Указатель на функцию высвобождении памяти датчика
  */
-typedef void(SensorFree)(void* sensor);
+typedef bool(SensorFree)(void* sensor);
 /**
  * @brief Указатель функции инициализации датчика
  */

+ 11 - 1
interfaces/I2CSensor.c

@@ -50,6 +50,16 @@ bool unitemp_I2C_sensorAlloc(void* s, uint16_t* anotherValues) {
     return status;
 }
 
-void unitemp_I2C_sensorFree(Sensor* sensor) {
+bool unitemp_I2C_sensorFree(Sensor* sensor) {
+    bool status = sensor->type->mem_releaser(sensor);
     free(sensor->instance);
+    return status;
+}
+
+UnitempStatus unitemp_I2C_sensor_update(void* s) {
+    Sensor* sensor = (Sensor*)s;
+    if(sensor->status != UT_OK) {
+        sensor->type->initializer(sensor);
+    }
+    return sensor->type->updater(sensor);
 }

+ 9 - 1
interfaces/I2CSensor.h

@@ -33,7 +33,15 @@ bool unitemp_I2C_sensorAlloc(void* s, uint16_t* anotherValues);
  * 
  * @param sensor Указатель на датчик
  */
-void unitemp_I2C_sensorFree(Sensor* sensor);
+bool unitemp_I2C_sensorFree(Sensor* sensor);
+
+/**
+ * @brief Обновить значение с датчка
+ * 
+ * @param sensor Указатель на датчик (тип Sensor)
+ * @return Статус обновления
+ */
+UnitempStatus unitemp_I2C_sensor_update(void* sensor);
 /**
  * @brief Прочитать значение регистра reg
  *

+ 3 - 2
interfaces/SingleWireSensor.c

@@ -71,10 +71,11 @@ bool unitemp_singleWire_alloc(void* s, uint16_t* anotherValues) {
     free(instance);
     return false;
 }
-void unitemp_singleWire_free(void* s) {
+bool unitemp_singleWire_free(void* s) {
     Sensor* sensor = (Sensor*)s;
     free(sensor->instance);
-    FURI_LOG_D(APP_NAME, "Sensor %s memory successfully released", sensor->name);
+
+    return true;
 }
 
 bool unitemp_singleWire_init(void* sensor) {

+ 1 - 1
interfaces/SingleWireSensor.h

@@ -70,5 +70,5 @@ bool unitemp_singleWire_alloc(void* sensor, uint16_t* anotherValues);
  * 
  * @param sensor Указатель на датчик
  */
-void unitemp_singleWire_free(void* sensor);
+bool unitemp_singleWire_free(void* sensor);
 #endif

+ 179 - 49
sensors/BMP280.c

@@ -1,49 +1,184 @@
-// #include "SensorsDriver.h"
-// #include "BMP280.h"
-
-// #define TEMP_CAL_START_ADDR 0x88
-// #define PRESS_CAL_START_ADDR 0x8E
-
-// static double bmp280_compensate_T_double(I2CSensor* i2c_sensor, int32_t adc_T) {
-//     BMP280_instance* bmp280_instance = (BMP280_instance*)i2c_sensor->sensorInstance;
-//     double var1, var2, T;
-//     var1 = (((double)adc_T) / (double)16384.0 -
-//             ((double)bmp280_instance->temp_cal.dig_T1) / (double)1024.0) *
-//            ((double)bmp280_instance->temp_cal.dig_T2);
-//     var2 = ((((double)adc_T) / (double)131072.0 -
-//              ((double)bmp280_instance->temp_cal.dig_T1) / (double)8192.0) *
-//             (((double)adc_T) / (double)131072.0 -
-//              ((double)bmp280_instance->temp_cal.dig_T1) / (double)8192.0)) *
-//            ((double)bmp280_instance->temp_cal.dig_T3);
-//     T = (var1 + var2) / (double)5120.0;
-//     return T;
-// }
+#include "SensorsDriver.h"
+#include "BMP280.h"
 
-// static bool readCalValues(I2CSensor* i2c_sensor) {
-//     BMP280_instance* bmp280_instance = (BMP280_instance*)i2c_sensor->sensorInstance;
-//     if(!readRegArray(i2c_sensor, TEMP_CAL_START_ADDR, 6, (uint8_t*)&bmp280_instance->temp_cal))
-//         return false;
+const SensorType BMP280 = {
+    .typename = "BMP280",
+    .interface = I2C,
+    .pollingInterval = 500,
+    .allocator = unitemp_BMP280_alloc,
+    .mem_releaser = unitemp_BMP280_free,
+    .initializer = unitemp_BMP280_init,
+    .deinitializer = unitemp_BMP280_deinit,
+    .updater = unitemp_BMP280_update};
 
-//     if(!readRegArray(i2c_sensor, PRESS_CAL_START_ADDR, 18, (uint8_t*)&bmp280_instance->press_cal))
-//         return false;
-//     FURI_LOG_D(
-//         APP_NAME,
-//         "Sensor BMP280 (0x%02X): T1-3: %d, %d, %d; P1-9: %d, %d, %d, %d, %d, %d, %d, %d, %d",
-//         i2c_sensor->currentI2CAdr,
-//         bmp280_instance->temp_cal.dig_T1,
-//         bmp280_instance->temp_cal.dig_T2,
-//         bmp280_instance->temp_cal.dig_T3,
-//         bmp280_instance->press_cal.dig_P1,
-//         bmp280_instance->press_cal.dig_P2,
-//         bmp280_instance->press_cal.dig_P3,
-//         bmp280_instance->press_cal.dig_P4,
-//         bmp280_instance->press_cal.dig_P5,
-//         bmp280_instance->press_cal.dig_P6,
-//         bmp280_instance->press_cal.dig_P7,
-//         bmp280_instance->press_cal.dig_P8,
-//         bmp280_instance->press_cal.dig_P9);
-//     return true;
-// }
+#define TEMP_CAL_START_ADDR 0x88
+//#define PRESS_CAL_START_ADDR 0x8E
+#define BMP280_ID 0x58
+
+#define BMP280_REG_STATUS 0xF3
+#define BMP280_REG_CTRL_MEAS 0xF4
+#define BMP280_REG_CONFIG 0xF5
+//Преддескретизация температуры
+#define BMP280_TEMP_OVERSAMPLING_SKIP 0b00000000
+#define BMP280_TEMP_OVERSAMPLING_1 0b00100000
+#define BMP280_TEMP_OVERSAMPLING_2 0b01000000
+#define BMP280_TEMP_OVERSAMPLING_4 0b01100000
+#define BMP280_TEMP_OVERSAMPLING_8 0b10000000
+#define BMP280_TEMP_OVERSAMPLING_16 0b10100000
+//Режимы работы датчика
+#define BMP280_MODE_SLEEP 0b00000000 //Спит и мало кушает
+#define BMP280_MODE_FORCED 0b00000001 //Обновляет значения 1 раз, после чего уходит в сон
+#define BMP280_MODE_NORMAL 0b00000011 //Регулярно обновляет значения
+//Период обновления в нормальном режиме
+#define BMP280_STANDBY_TIME_0_5 0b00000000
+#define BMP280_STANDBY_TIME_62_5 0b00100000
+#define BMP280_STANDBY_TIME_125 0b01000000
+#define BMP280_STANDBY_TIME_250 0b01100000
+#define BMP280_STANDBY_TIME_500 0b10000000
+#define BMP280_STANDBY_TIME_1000 0b10100000
+#define BMP280_STANDBY_TIME_2000 0b11000000
+#define BMP280_STANDBY_TIME_4000 0b11100000
+//Коэффициент фильтрации значений
+#define BMP280_FILTER_COEFF_1 0b00000000
+#define BMP280_FILTER_COEFF_2 0b00000100
+#define BMP280_FILTER_COEFF_4 0b00001000
+#define BMP280_FILTER_COEFF_8 0b00001100
+#define BMP280_FILTER_COEFF_16 0b00010000
+//Разрешить работу по SPI
+#define BMP280_SPI_3W_ENABLE 0b00000001
+#define BMP280_SPI_3W_DISABLE 0b00000000
+
+static double bmp280_compensate_T_double(I2CSensor* i2c_sensor, int32_t adc_T) {
+    BMP280_instance* bmp280_instance = (BMP280_instance*)i2c_sensor->sensorInstance;
+    double var1, var2, T;
+    var1 = (((double)adc_T) / (double)16384.0 -
+            ((double)bmp280_instance->temp_cal.dig_T1) / (double)1024.0) *
+           ((double)bmp280_instance->temp_cal.dig_T2);
+    var2 = ((((double)adc_T) / (double)131072.0 -
+             ((double)bmp280_instance->temp_cal.dig_T1) / (double)8192.0) *
+            (((double)adc_T) / (double)131072.0 -
+             ((double)bmp280_instance->temp_cal.dig_T1) / (double)8192.0)) *
+           ((double)bmp280_instance->temp_cal.dig_T3);
+    T = (var1 + var2) / (double)5120.0;
+    return T;
+}
+
+static bool bmp280_readCalValues(I2CSensor* i2c_sensor) {
+    BMP280_instance* bmp280_instance = (BMP280_instance*)i2c_sensor->sensorInstance;
+    if(!readRegArray(i2c_sensor, TEMP_CAL_START_ADDR, 6, (uint8_t*)&bmp280_instance->temp_cal))
+        return false;
+    FURI_LOG_D(
+        APP_NAME,
+        "Sensor BMP280 (0x%02X) calibration values: T1: %d, T2: %d, T3: %d",
+        i2c_sensor->currentI2CAdr,
+        bmp280_instance->temp_cal.dig_T1,
+        bmp280_instance->temp_cal.dig_T2,
+        bmp280_instance->temp_cal.dig_T3);
+    // if(!readRegArray(i2c_sensor, PRESS_CAL_START_ADDR, 18, (uint8_t*)&bmp280_instance->press_cal))
+    //     return false;
+    // FURI_LOG_D(
+    //     APP_NAME,
+    //     "Sensor BMP280 (0x%02X): T1-3: %d, %d, %d; P1-9: %d, %d, %d, %d, %d, %d, %d, %d, %d",
+    //     i2c_sensor->currentI2CAdr,
+    //     bmp280_instance->temp_cal.dig_T1,
+    //     bmp280_instance->temp_cal.dig_T2,
+    //     bmp280_instance->temp_cal.dig_T3,
+    //     bmp280_instance->press_cal.dig_P1,
+    //     bmp280_instance->press_cal.dig_P2,
+    //     bmp280_instance->press_cal.dig_P3,
+    //     bmp280_instance->press_cal.dig_P4,
+    //     bmp280_instance->press_cal.dig_P5,
+    //     bmp280_instance->press_cal.dig_P6,
+    //     bmp280_instance->press_cal.dig_P7,
+    //     bmp280_instance->press_cal.dig_P8,
+    //     bmp280_instance->press_cal.dig_P9);
+    return true;
+}
+static bool bmp280_isMeasuring(Sensor* sensor) {
+    I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance;
+    return (bool)((readReg(i2c_sensor, BMP280_REG_STATUS) & 0x08) >> 3);
+}
+
+bool unitemp_BMP280_alloc(void* s, uint16_t* anotherValues) {
+    UNUSED(anotherValues);
+    Sensor* sensor = (Sensor*)s;
+    I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance;
+    BMP280_instance* bmp280_instance = malloc(sizeof(BMP280_instance));
+    if(bmp280_instance == NULL) {
+        FURI_LOG_E(APP_NAME, "Failed to allocation sensor %s instance", sensor->name);
+        return false;
+    }
+    i2c_sensor->sensorInstance = bmp280_instance;
+
+    i2c_sensor->minI2CAdr = 0x76;
+    i2c_sensor->maxI2CAdr = 0x77;
+    return true;
+}
+
+bool unitemp_BMP280_init(void* s) {
+    Sensor* sensor = (Sensor*)s;
+    I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance;
+    //Перезагрузка
+    writeReg(i2c_sensor, 0xE0, 0xB6);
+    //Чтение ID датчика
+    uint8_t id = readReg(i2c_sensor, 0xD0);
+    if(id != BMP280_ID) {
+        FURI_LOG_E(
+            APP_NAME,
+            "Sensor %s returned wrong ID 0x%02X, expected 0x%02X",
+            sensor->name,
+            id,
+            BMP280_ID);
+        return false;
+    }
+
+    //Чтение калибровочных значений
+    if(!bmp280_readCalValues(i2c_sensor)) {
+        FURI_LOG_E(APP_NAME, "Failed to read calibration values sensor %s", sensor->name);
+        return false;
+    }
+    //Настройка режимов работы
+    writeReg(i2c_sensor, BMP280_REG_CTRL_MEAS, BMP280_TEMP_OVERSAMPLING_2 | BMP280_MODE_NORMAL);
+    //Настройка периода опроса и фильтрации значений
+    writeReg(
+        i2c_sensor,
+        BMP280_REG_CONFIG,
+        BMP280_STANDBY_TIME_500 | BMP280_FILTER_COEFF_16 | BMP280_SPI_3W_DISABLE);
+
+    return true;
+}
+
+bool unitemp_BMP280_deinit(void* s) {
+    Sensor* sensor = (Sensor*)s;
+    I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance;
+    //Перевод в сон
+    writeReg(i2c_sensor, BMP280_REG_CTRL_MEAS, BMP280_MODE_SLEEP);
+    return true;
+}
+
+UnitempStatus unitemp_BMP280_update(void* s) {
+    Sensor* sensor = (Sensor*)s;
+    I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance;
+
+    uint32_t t = furi_get_tick();
+    while(bmp280_isMeasuring(sensor)) {
+        if(furi_get_tick() - t > 100) {
+            return UT_TIMEOUT;
+        }
+    }
+    uint8_t buff[3];
+    if(!readRegArray(i2c_sensor, 0xFA, 3, buff)) return UT_TIMEOUT;
+    int32_t adc_T = ((int32_t)buff[0] << 12) | ((int32_t)buff[1] << 4) | ((int32_t)buff[2] >> 4);
+    sensor->temp = bmp280_compensate_T_double(i2c_sensor, adc_T);
+    return UT_OK;
+}
+
+bool unitemp_BMP280_free(void* s) {
+    Sensor* sensor = (Sensor*)s;
+    I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance;
+    free(i2c_sensor->sensorInstance);
+    return true;
+}
 
 // bool BMP280_init(I2CSensor* i2c_sensor) {
 //     //Перезагрузка
@@ -63,11 +198,6 @@
 
 //     return true;
 // }
-// //Настройки для BMP280
-// if(st == BMP280) {
-//     instance->minI2CAdr = 0x76;
-//     instance->maxI2CAdr = 0x77;
-// }
 
 // bool BMP280_updateData(Sensor* sensor) {
 //     I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance;

+ 51 - 24
sensors/BMP280.h

@@ -1,15 +1,15 @@
-// #ifndef UNITEMP_BMP280
-// #define UNITEMP_BMP280
-// #include "../unitemp.h"
-// #include "../Sensors.h"
-// #include "../interfaces/I2CSensor.h"
-// #include "SensorsDriver.h"
+#ifndef UNITEMP_BMP280
+#define UNITEMP_BMP280
+#include "../unitemp.h"
+#include "../Sensors.h"
+#include "../interfaces/I2CSensor.h"
+#include "SensorsDriver.h"
 
-// typedef struct {
-//     uint16_t dig_T1;
-//     int16_t dig_T2;
-//     int16_t dig_T3;
-// } BMP280_temp_cal;
+typedef struct {
+    uint16_t dig_T1;
+    int16_t dig_T2;
+    int16_t dig_T3;
+} BMP280_temp_cal;
 
 // typedef struct {
 //     uint16_t dig_P1;
@@ -23,21 +23,48 @@
 //     int16_t dig_P9;
 // } BMP280_press_cal;
 
-// typedef struct {
-//     BMP280_temp_cal temp_cal;
-//     BMP280_press_cal press_cal;
+typedef struct {
+    BMP280_temp_cal temp_cal;
+    // BMP280_press_cal press_cal;
+} BMP280_instance;
+
+extern const SensorType BMP280;
+/**
+ * @brief Выделение памяти и установка начальных значений датчика BMP280
+ *
+ * @param sensor Указатель на создаваемый датчик
+ * @return Истина при успехе
+ */
+bool unitemp_BMP280_alloc(void* s, uint16_t* anotherValues);
 
-// } BMP280_instance;
+/**
+ * @brief Инициализации датчика BMP280
+ *
+ * @param sensor Указатель на датчик (тип Sensor)
+ * @return Истина если инициализация упспешная
+ */
+bool unitemp_BMP280_init(void* sensor);
 
-// /**
-//  * @brief Инициализация датчика
-//  *
-//  * @param i2c_sensor Указатель на датчик
-//  * @return Инстина если инициализация успешная
-//  */
+/**
+ * @brief Деинициализация датчика
+ *
+ * @param sensor Указатель на датчик (тип Sensor)
+ */
+bool unitemp_BMP280_deinit(void* s);
 
-// bool BMP280_init(I2CSensor* i2c_sensor);
+/**
+ * @brief Обновление значений из датчика
+ *
+ * @param sensor Указатель на датчик (тип Sensor)
+ * @return Истина если данныее были получены
+ */
+UnitempStatus unitemp_BMP280_update(void* s);
 
-// bool BMP280_updateData(Sensor* sensor);
+/**
+ * @brief Высвободить память датчика
+ *
+ * @param sensor Указатель на датчик (тип Sensor)
+ */
+bool unitemp_BMP280_free(void* sensor);
 
-// #endif
+#endif

+ 2 - 1
sensors/LM75.c

@@ -33,9 +33,10 @@ bool unitemp_LM75_alloc(void* s, uint16_t* anotherValues) {
     i2c_sensor->maxI2CAdr = 0b1001111;
     return true;
 }
-void unitemp_LM75_free(void* s) {
+bool unitemp_LM75_free(void* s) {
     //Нечего высвобождать, так как ничего не было выделено
     UNUSED(s);
+    return true;
 }
 
 bool unitemp_LM75_init(void* s) {

+ 1 - 1
sensors/LM75.h

@@ -41,6 +41,6 @@ UnitempStatus unitemp_LM75_update(void* s);
  *
  * @param sensor Указатель на датчик (тип Sensor)
  */
-void unitemp_LM75_free(void* sensor);
+bool unitemp_LM75_free(void* sensor);
 
 #endif