Преглед изворни кода

Added support for AM2320 sensor by I2C. Optimized work with I2C

Victor пре 3 година
родитељ
комит
90b6d5f21c
9 измењених фајлова са 259 додато и 12 уклоњено
  1. 1 1
      Sensors.c
  2. 1 0
      Sensors.h
  3. 43 7
      interfaces/I2CSensor.c
  4. 42 0
      interfaces/I2CSensor.h
  5. 106 0
      sensors/AM2320.c
  6. 62 0
      sensors/AM2320.h
  7. 2 2
      sensors/BMP280.c
  8. 2 2
      sensors/LM75.c
  9. BIN
      sensors/Sensors.xlsx

+ 1 - 1
Sensors.c

@@ -72,7 +72,7 @@ const Interface ONE_WIRE = {
 //static const Interface* interfaces[] = {&SINGLE_WIRE, &I2C, &ONE_WIRE};
 //Перечень датчиков
 static const SensorType* sensorTypes[] =
-    {&DHT11, &DHT12_SW, &DHT21, &DHT22, &AM2320_SW, &LM75, &BMP280, &Dallas};
+    {&DHT11, &DHT12_SW, &DHT21, &DHT22, &AM2320_SW, &AM2320_I2C, &LM75, &BMP280, &Dallas};
 
 const SensorType* unitemp_sensors_getTypeFromInt(uint8_t index) {
     if(index > SENSOR_TYPES_COUNT) return NULL;

+ 1 - 0
Sensors.h

@@ -319,4 +319,5 @@ const GPIO*
 #include "./interfaces/OneWireSensor.h"
 #include "./sensors/LM75.h"
 #include "./sensors/BMP280.h"
+#include "./sensors/AM2320.h"
 #endif

+ 43 - 7
interfaces/I2CSensor.c

@@ -19,29 +19,65 @@
 
 static uint8_t sensors_count = 0;
 
+void unitemp_i2c_acquire(FuriHalI2cBusHandle* handle) {
+    furi_hal_i2c_acquire(handle);
+    LL_GPIO_SetPinPull(gpio_ext_pc1.port, gpio_ext_pc1.pin, LL_GPIO_PULL_UP);
+    LL_GPIO_SetPinPull(gpio_ext_pc0.port, gpio_ext_pc0.pin, LL_GPIO_PULL_UP);
+}
+
+bool unitemp_i2c_isDeviceReady(I2CSensor* i2c_sensor) {
+    unitemp_i2c_acquire(i2c_sensor->i2c);
+    bool status = furi_hal_i2c_is_device_ready(i2c_sensor->i2c, i2c_sensor->currentI2CAdr, 10);
+    furi_hal_i2c_release(i2c_sensor->i2c);
+    return status;
+}
+
 uint8_t unitemp_i2c_readReg(I2CSensor* i2c_sensor, uint8_t reg) {
     //Блокировка шины
-    furi_hal_i2c_acquire(i2c_sensor->i2c);
+    unitemp_i2c_acquire(i2c_sensor->i2c);
     uint8_t buff[1] = {0};
-    furi_hal_i2c_read_mem(i2c_sensor->i2c, i2c_sensor->currentI2CAdr << 1, reg, buff, 1, 10);
+    furi_hal_i2c_read_mem(i2c_sensor->i2c, i2c_sensor->currentI2CAdr, reg, buff, 1, 10);
     furi_hal_i2c_release(i2c_sensor->i2c);
     return buff[0];
 }
 
+bool unitemp_i2c_readArray(I2CSensor* i2c_sensor, uint8_t len, uint8_t* data) {
+    unitemp_i2c_acquire(i2c_sensor->i2c);
+    bool status = furi_hal_i2c_rx(i2c_sensor->i2c, i2c_sensor->currentI2CAdr, data, len, 10);
+    furi_hal_i2c_release(i2c_sensor->i2c);
+    return status;
+}
+
 bool unitemp_i2c_readRegArray(I2CSensor* i2c_sensor, uint8_t startReg, uint8_t len, uint8_t* data) {
-    furi_hal_i2c_acquire(i2c_sensor->i2c);
-    bool status = furi_hal_i2c_read_mem(
-        i2c_sensor->i2c, i2c_sensor->currentI2CAdr << 1, startReg, data, len, 10);
+    unitemp_i2c_acquire(i2c_sensor->i2c);
+    bool status =
+        furi_hal_i2c_read_mem(i2c_sensor->i2c, i2c_sensor->currentI2CAdr, startReg, data, len, 10);
     furi_hal_i2c_release(i2c_sensor->i2c);
     return status;
 }
 
 bool unitemp_i2c_writeReg(I2CSensor* i2c_sensor, uint8_t reg, uint8_t value) {
     //Блокировка шины
-    furi_hal_i2c_acquire(i2c_sensor->i2c);
+    unitemp_i2c_acquire(i2c_sensor->i2c);
     uint8_t buff[1] = {value};
     bool status =
-        furi_hal_i2c_write_mem(i2c_sensor->i2c, i2c_sensor->currentI2CAdr << 1, reg, buff, 1, 10);
+        furi_hal_i2c_write_mem(i2c_sensor->i2c, i2c_sensor->currentI2CAdr, reg, buff, 1, 10);
+    furi_hal_i2c_release(i2c_sensor->i2c);
+    return status;
+}
+
+bool unitemp_i2c_writeArray(I2CSensor* i2c_sensor, uint8_t len, uint8_t* data) {
+    unitemp_i2c_acquire(i2c_sensor->i2c);
+    bool status = furi_hal_i2c_tx(i2c_sensor->i2c, i2c_sensor->currentI2CAdr, data, len, 10);
+    furi_hal_i2c_release(i2c_sensor->i2c);
+    return status;
+}
+
+bool unitemp_i2c_writeRegArray(I2CSensor* i2c_sensor, uint8_t startReg, uint8_t len, uint8_t* data) {
+    //Блокировка шины
+    unitemp_i2c_acquire(i2c_sensor->i2c);
+    bool status = furi_hal_i2c_write_mem(
+        i2c_sensor->i2c, i2c_sensor->currentI2CAdr, startReg, data, len, 10);
     furi_hal_i2c_release(i2c_sensor->i2c);
     return status;
 }

+ 42 - 0
interfaces/I2CSensor.h

@@ -36,6 +36,21 @@ typedef struct I2CSensor {
     void* sensorInstance;
 } I2CSensor;
 
+/**
+ * @brief Заблокировать шину I2C
+ * 
+ * @param handle Указатель на шину
+ */
+void unitemp_i2c_acquire(FuriHalI2cBusHandle* handle);
+
+/**
+ * @brief Проверить наличие датчика на шине
+ * 
+ * @param i2c_sensor Указатель на датчик
+ * @return Истина если устройство отозвалось
+ */
+bool unitemp_i2c_isDeviceReady(I2CSensor* i2c_sensor);
+
 /**
  * @brief Выделение памяти для датчика на шине I2C
  * @param sensor Указатель на датчик
@@ -83,4 +98,31 @@ bool unitemp_i2c_readRegArray(I2CSensor* i2c_sensor, uint8_t startReg, uint8_t l
  */
 bool unitemp_i2c_writeReg(I2CSensor* i2c_sensor, uint8_t reg, uint8_t value);
 
+/**
+ * @brief Записать масссив значений в память
+ * @param i2c_sensor Указатель на инстанс датчика
+ * @param startReg Адрес регистра с которого начнётся запись
+ * @param len Количество байт для считывания из регистра
+ * @param data Указатель на массив откуда будут записаны данные
+ * @return Истина если устройство вернуло данные
+ */
+bool unitemp_i2c_writeRegArray(I2CSensor* i2c_sensor, uint8_t startReg, uint8_t len, uint8_t* data);
+
+/**
+ * @brief Прочитать массив данных по шине I2C
+ * @param i2c_sensor Указатель на инстанс датчика
+ * @param startReg Адрес регистра с которого начнётся чтение
+ * @param data Указатель на массив куда будут считаны данные
+ * @return Истина если устройство вернуло данные
+ */
+bool unitemp_i2c_readArray(I2CSensor* i2c_sensor, uint8_t len, uint8_t* data);
+
+/**
+ * @brief Записать масссив данных по шине I2C
+ * @param i2c_sensor Указатель на инстанс датчика
+ * @param len Количество байт для считывания из регистра
+ * @param data Указатель на массив откуда будут записаны данные
+ * @return Истина если устройство вернуло данные
+ */
+bool unitemp_i2c_writeArray(I2CSensor* i2c_sensor, uint8_t len, uint8_t* data);
 #endif

+ 106 - 0
sensors/AM2320.c

@@ -0,0 +1,106 @@
+/*
+    Unitemp - Universal temperature reader
+    Copyright (C) 2022  Victor Nikitchuk (https://github.com/quen0n)
+
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <https://www.gnu.org/licenses/>.
+*/
+#include "AM2320.h"
+#include "../interfaces/I2CSensor.h"
+
+const SensorType AM2320_I2C = {
+    .typename = "AM2320_I2C",
+    .altname = "AM2320 (I2C)",
+    .interface = &I2C,
+    .datatype = UT_TEMPERATURE | UT_HUMIDITY,
+    .pollingInterval = 2000,
+    .allocator = unitemp_AM2320_I2C_alloc,
+    .mem_releaser = unitemp_AM2320_I2C_free,
+    .initializer = unitemp_AM2320_init,
+    .deinitializer = unitemp_AM2320_I2C_deinit,
+    .updater = unitemp_AM2320_I2C_update};
+
+static uint16_t AM2320_calc_CRC(uint8_t* ptr, uint8_t len) {
+    uint16_t crc = 0xFFFF;
+    uint8_t i;
+    while(len--) {
+        crc ^= *ptr++;
+        for(i = 0; i < 8; i++) {
+            if(crc & 0x01) {
+                crc >>= 1;
+                crc ^= 0xA001;
+            } else {
+                crc >>= 1;
+            }
+        }
+    }
+    return crc;
+}
+
+bool unitemp_AM2320_I2C_alloc(Sensor* sensor, char* args) {
+    UNUSED(args);
+    I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance;
+
+    //Адреса на шине I2C (7 бит)
+    i2c_sensor->minI2CAdr = 0x5C << 1;
+    i2c_sensor->maxI2CAdr = 0x5C << 1;
+    return true;
+}
+
+bool unitemp_AM2320_I2C_free(Sensor* sensor) {
+    //Нечего высвобождать, так как ничего не было выделено
+    UNUSED(sensor);
+    return true;
+}
+
+bool unitemp_AM2320_init(Sensor* sensor) {
+    //Нечего инициализировать
+    UNUSED(sensor);
+    return true;
+}
+
+bool unitemp_AM2320_I2C_deinit(Sensor* sensor) {
+    //Нечего деинициализировать
+    UNUSED(sensor);
+    return true;
+}
+
+UnitempStatus unitemp_AM2320_I2C_update(Sensor* sensor) {
+    I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance;
+
+    uint8_t data[8] = {0x03, 0x00, 0x04};
+
+    //Wake up
+    unitemp_i2c_isDeviceReady(i2c_sensor);
+    furi_delay_ms(1);
+
+    //Запрос
+    if(!unitemp_i2c_writeArray(i2c_sensor, 3, data)) return UT_SENSORSTATUS_TIMEOUT;
+    furi_delay_ms(2);
+    //Ответ
+    if(!unitemp_i2c_readArray(i2c_sensor, 8, data)) return UT_SENSORSTATUS_TIMEOUT;
+
+    if(AM2320_calc_CRC(data, 6) != ((data[7] << 8) | data[6])) {
+        return UT_SENSORSTATUS_BADCRC;
+    }
+
+    sensor->hum = (float)(((uint16_t)data[2] << 8) | data[3]) / 10;
+    //Проверка на отрицательность температуры
+    if(!(data[4] & (1 << 7))) {
+        sensor->temp = (float)(((uint16_t)data[4] << 8) | data[5]) / 10;
+    } else {
+        data[4] &= ~(1 << 7);
+        sensor->temp = (float)(((uint16_t)data[4] << 8) | data[5]) / -10;
+    }
+    return UT_SENSORSTATUS_OK;
+}

+ 62 - 0
sensors/AM2320.h

@@ -0,0 +1,62 @@
+/*
+    Unitemp - Universal temperature reader
+    Copyright (C) 2022  Victor Nikitchuk (https://github.com/quen0n)
+
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <https://www.gnu.org/licenses/>.
+*/
+#ifndef UNITEMP_AM2320
+#define UNITEMP_AM2320
+
+#include "../unitemp.h"
+#include "../Sensors.h"
+extern const SensorType AM2320_I2C;
+/**
+ * @brief Выделение памяти и установка начальных значений датчика AM2320
+ *
+ * @param sensor Указатель на создаваемый датчик
+ * @return Истина при успехе
+ */
+bool unitemp_AM2320_I2C_alloc(Sensor* sensor, char* args);
+
+/**
+ * @brief Инициализации датчика AM2320
+ *
+ * @param sensor Указатель на датчик
+ * @return Истина если инициализация упспешная
+ */
+bool unitemp_AM2320_init(Sensor* sensor);
+
+/**
+ * @brief Деинициализация датчика
+ *
+ * @param sensor Указатель на датчик
+ */
+bool unitemp_AM2320_I2C_deinit(Sensor* sensor);
+
+/**
+ * @brief Обновление значений из датчика
+ *
+ * @param sensor Указатель на датчик
+ * @return Статус обновления
+ */
+UnitempStatus unitemp_AM2320_I2C_update(Sensor* sensor);
+
+/**
+ * @brief Высвободить память датчика
+ *
+ * @param sensor Указатель на датчик
+ */
+bool unitemp_AM2320_I2C_free(Sensor* sensor);
+
+#endif

+ 2 - 2
sensors/BMP280.c

@@ -172,8 +172,8 @@ bool unitemp_BMP280_alloc(Sensor* sensor, char* args) {
     }
     i2c_sensor->sensorInstance = bmp280_instance;
 
-    i2c_sensor->minI2CAdr = 0x76;
-    i2c_sensor->maxI2CAdr = 0x77;
+    i2c_sensor->minI2CAdr = 0x76 << 1;
+    i2c_sensor->maxI2CAdr = 0x77 << 1;
     return true;
 }
 

+ 2 - 2
sensors/LM75.c

@@ -47,8 +47,8 @@ bool unitemp_LM75_alloc(Sensor* sensor, char* args) {
     I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance;
 
     //Адреса на шине I2C (7 бит)
-    i2c_sensor->minI2CAdr = 0b1001000;
-    i2c_sensor->maxI2CAdr = 0b1001111;
+    i2c_sensor->minI2CAdr = 0b1001000 << 1;
+    i2c_sensor->maxI2CAdr = 0b1001111 << 1;
     return true;
 }
 

BIN
sensors/Sensors.xlsx