From 803931f2e214147da6005cb396cc0bc9a5f03162 Mon Sep 17 00:00:00 2001 From: Gunar Schorcht <31932013+gschorcht@users.noreply.github.com> Date: Tue, 3 Oct 2017 13:32:43 +0200 Subject: [PATCH 01/14] Driver for Sensirion SHT3x sensor added This is a driver for Sensirion SHT3x temperature and humidity sensors connected via I2C. This commit is a rebasing and contains some interface changes based on the review from @ourairquality. --- examples/sht3x/README.md | 48 ++ examples/sht3x/sht3x_one_sensor/Makefile | 3 + .../sht3x/sht3x_one_sensor/sht3x_one_sensor.c | 126 +++++ examples/sht3x/sht3x_two_sensors/Makefile | 3 + .../sht3x_two_sensors/sht3x_two_sensors.c | 135 ++++++ extras/sht3x/README.md | 259 ++++++++++ extras/sht3x/component.mk | 9 + extras/sht3x/sht3x.c | 442 ++++++++++++++++++ extras/sht3x/sht3x.h | 258 ++++++++++ 9 files changed, 1283 insertions(+) create mode 100644 examples/sht3x/README.md create mode 100644 examples/sht3x/sht3x_one_sensor/Makefile create mode 100644 examples/sht3x/sht3x_one_sensor/sht3x_one_sensor.c create mode 100644 examples/sht3x/sht3x_two_sensors/Makefile create mode 100644 examples/sht3x/sht3x_two_sensors/sht3x_two_sensors.c create mode 100644 extras/sht3x/README.md create mode 100644 extras/sht3x/component.mk create mode 100644 extras/sht3x/sht3x.c create mode 100644 extras/sht3x/sht3x.h diff --git a/examples/sht3x/README.md b/examples/sht3x/README.md new file mode 100644 index 0000000..2abe606 --- /dev/null +++ b/examples/sht3x/README.md @@ -0,0 +1,48 @@ +# SHT3x Driver Examples + +These examples references two addtional drivers [i2c](https://github.com/kanflo/esp-open-rtos-driver-i2c) and [sht3x](https://github.com/gschorcht/esp-open-rtos/extras/sht3x), which are provided in the `../../extras` folder. + +If you plan to use one or both of this drivers in your own projects, please check the main development pages for updated versions or reported issues. + +## Hardware setup + +There are examples for only one sensor and examples for two sensors. + +To run examples with **one sensor**, just use GPIO5 (SCL) and GPIO4 (SDA) to connect to the SHT3x sensor's I2C interface. + +``` + +------------------------+ +--------+ + | ESP8266 Bus 0 | | SHT3x | + | GPIO 5 (SCL) >---- > SCL | + | GPIO 4 (SDA) ------- SDA | + | | +--------+ + +------------------------+ +``` + +If you want to run examples with **two sensors**, you could do this with only one bus and different I2C addresses or with two buses and the same or different I2C addresses. In later case, use GPIO14 (SCL) and GPIO12 (SDA) for the second bus to connect to the second SHT3x sensor's I2C interface. + +``` + +------------------------+ +----------+ + | ESP8266 Bus 0 | | SHT3x_1 | + | GPIO 5 (SCL) >-----> SCL | + | GPIO 4 (SDA) ------- SDA | + | | +----------+ + | Bus 1 | | SHT3x_2 | + | GPIO 14 (SCL) >-----> SCL | + | GPIO 12 (SDA) ------- SDA | + +------------------------+ +----------+ +``` + +## Example description + +Examples show how to use the driver in single shot as well as in periodic mode. + + +### _sht3x_one_sensor_ + +The simple example show how to use the driver with one SHT3x sensor. It demonstrates two different user task implementations, one in *single shot mode* and one in *periodic mode*. In addition, it shows both approaches for the implementation of waiting for measurement results, one as busy waiting and one as passive waiting using *vTaskDelay*. + +### _sht3x_two_sensors_ + +This simple example shows how to use the driver for two sensors. As with the example _sht3x_one_sensor_, it uses two different user task implementations and waiting approaches, in this example one for each of the tasks. + diff --git a/examples/sht3x/sht3x_one_sensor/Makefile b/examples/sht3x/sht3x_one_sensor/Makefile new file mode 100644 index 0000000..5db0eed --- /dev/null +++ b/examples/sht3x/sht3x_one_sensor/Makefile @@ -0,0 +1,3 @@ +PROGRAM=SHT3x_One_Sensor +EXTRA_COMPONENTS = extras/i2c extras/sht3x +include ../../../common.mk diff --git a/examples/sht3x/sht3x_one_sensor/sht3x_one_sensor.c b/examples/sht3x/sht3x_one_sensor/sht3x_one_sensor.c new file mode 100644 index 0000000..e906f1d --- /dev/null +++ b/examples/sht3x/sht3x_one_sensor/sht3x_one_sensor.c @@ -0,0 +1,126 @@ +/** + * Simple example with one SHT3x sensor. + * + * It shows two different user task implementations, one in *single shot mode* + * and one in *periodic mode*. In addition, it shows both approaches for the + * implementation of waiting for measurement results, one as busy waiting and + * one as passive waiting using *vTaskDelay*. + * + * The implementation that is used is defined by constant SINGLE_SHOT_MODE. + * + * Harware configuration: + * + * +------------------------+ +----------+ + * | ESP8266 Bus 0 | | SHT3x | + * | GPIO 5 (SCL) ------> SCL | + * | GPIO 4 (SDA) ------- SDA | + * +------------------------+ +----------+ + */ + +#include "espressif/esp_common.h" +#include "esp/uart.h" + +#include "FreeRTOS.h" +#include "task.h" + +// include SHT3x driver +#include "sht3x/sht3x.h" + +// define I2C interfaces at which SHTx3 sensors are connected +#define I2C_BUS 0 +#define I2C_SCL_PIN GPIO_ID_PIN((5)) +#define I2C_SDA_PIN GPIO_ID_PIN((4)) + +static sht3x_sensor_t* sensor; // sensor device data structure + +// #define SINGLE_SHOT_MODE + +#ifdef SINGLE_SHOT_MODE +/* + * User task that triggers measurements of sensor every 5 seconds. Due to + * power efficiency reasons, it uses the SHT3x *single_shot* and *vTaskDelay* + * to wait for measurement results. + */ +void user_task (void *pvParameters) +{ + sht3x_values_t values; + int32_t duration; + + TickType_t last_wakeup = xTaskGetTickCount(); + + while (1) + { + // trigger one measurement in single shot mode + duration = sht3x_start_measurement (sensor, single_shot); + + // passive waiting until measurement results are available + if (duration > 0) + vTaskDelay (duration/portTICK_PERIOD_MS); + + // retrieve the values and do something with them + if (sht3x_get_results (sensor, &values)) + printf("%.3f SHT3x Sensor: %.2f °C, %.2f %%\n", + (double)sdk_system_get_time()*1e-3, + values.temperature, values.humidity); + + // passive waiting until 5 seconds are over + vTaskDelayUntil(&last_wakeup, 5000 / portTICK_PERIOD_MS); + } +} +#else // PERIODIC MODE +/* + * User task that fetches latest measurement results of sensor every 2 + * seconds. It starts the SHT3x in periodic mode with 1 measurements per + * second (*periodic_1mps*). It uses busy waiting for first measurement + * results. + */ +void user_task (void *pvParameters) +{ + sht3x_values_t values; + + // start periodic measurement mode + sht3x_start_measurement (sensor, periodic_1mps); + + // busy waiting until measurement results are available + while (sht3x_is_measuring (sensor) > 0) ; + + TickType_t last_wakeup = xTaskGetTickCount(); + + while (1) + { + // retrieve the values and do something with them + if (sht3x_get_results (sensor, &values)) + printf("%.3f SHT3x Sensor: %.2f °C, %.2f %%\n", + (double)sdk_system_get_time()*1e-3, + values.temperature, values.humidity); + + // passive waiting until 2 seconds are over + vTaskDelayUntil(&last_wakeup, 2000 / portTICK_PERIOD_MS); + } +} +#endif + +void user_init(void) +{ + // Please note: Return values are not considered in this example for + // readability reasons. All functions return boolean and set an error + // code that allows effective error handling. + + // Set UART Parameter + uart_set_baud(0, 115200); + + // Give the UART some time to settle + sdk_os_delay_us(500); + + // Init I2C bus interfaces at which SHT3x sensors are connected + // (different busses are possible) + i2c_init(I2C_BUS, I2C_SCL_PIN, I2C_SDA_PIN, I2C_FREQ_100K); + + // Create sensors + sensor = sht3x_init_sensor (I2C_BUS, SHT3x_ADDR_2); + + // Create a user task that uses the sensor + xTaskCreate(user_task, "user_task", 256, NULL, 2, 0); + + // That's it. +} diff --git a/examples/sht3x/sht3x_two_sensors/Makefile b/examples/sht3x/sht3x_two_sensors/Makefile new file mode 100644 index 0000000..ddf329f --- /dev/null +++ b/examples/sht3x/sht3x_two_sensors/Makefile @@ -0,0 +1,3 @@ +PROGRAM=SHT3x_Two_Sensors +EXTRA_COMPONENTS = extras/i2c extras/sht3x +include ../../../common.mk diff --git a/examples/sht3x/sht3x_two_sensors/sht3x_two_sensors.c b/examples/sht3x/sht3x_two_sensors/sht3x_two_sensors.c new file mode 100644 index 0000000..ee40cce --- /dev/null +++ b/examples/sht3x/sht3x_two_sensors/sht3x_two_sensors.c @@ -0,0 +1,135 @@ +/** + * Simple example with two SHT3x sensors. + * + * It shows two different user task implementations, one in *single shot mode* + * and one in *periodic mode*. In addition, it shows both approaches for the + * implementation of waiting for measurement results, one as busy waiting and + * one as passive waiting using *vTaskDelay*. + * + * Harware configuration: + * + * +------------------------+ +----------+ + * | ESP8266 Bus 0 | | SHT3x_1 | + * | GPIO 5 (SCL) ------> SCL | + * | GPIO 4 (SDA) ------- SDA | + * | | +----------+ + * | Bus 1 | | SHT3x_2 | + * | GPIO 14 (SCL) ------> SCL | + * | GPIO 12 (SDA) ------- SDA | + * +------------------------+ +----------+ + */ + +#include "espressif/esp_common.h" +#include "esp/uart.h" + +#include "FreeRTOS.h" +#include "task.h" + +// include SHT3x driver + +#include "sht3x/sht3x.h" + +// define I2C interfaces at which SHTx3 sensors are connected + +#define I2C_1_BUS 0 +#define I2C_1_SCL_PIN GPIO_ID_PIN((5)) +#define I2C_1_SDA_PIN GPIO_ID_PIN((4)) + +#define I2C_2_BUS 1 +#define I2C_2_SCL_PIN GPIO_ID_PIN((14)) +#define I2C_2_SDA_PIN GPIO_ID_PIN((12)) + +static sht3x_sensor_t* sensor1; +static sht3x_sensor_t* sensor2; + +/* + * User task that triggers measurements of sensor1 every 5 seconds. Due to + * power efficiency reasons, it uses the SHT3x *single_shot* and *vTaskDelay* + * to wait for measurement results. + */ +void user_task_sensor1 (void *pvParameters) +{ + sht3x_values_t values; + int32_t duration; + + TickType_t last_wakeup = xTaskGetTickCount(); + + while (1) + { + // trigger one measurement in single shot mode + duration = sht3x_start_measurement (sensor1, single_shot); + + // passive waiting until measurement results are available + if (duration > 0) + vTaskDelay (duration/portTICK_PERIOD_MS); + + // retrieve the values and do something with them + if (sht3x_get_results (sensor1, &values)) + printf("%.3f SHT3x Sensor1: %.2f °C, %.2f %%\n", + (double)sdk_system_get_time()*1e-3, + values.temperature, values.humidity); + + // passive waiting until 5 seconds are over + vTaskDelayUntil(&last_wakeup, 5000 / portTICK_PERIOD_MS); + } +} + +/* + * User task that fetches latest measurement results of sensor2 every 2 + * seconds. It starts the SHT3x in periodic mode with 10 measurements per + * second (*periodic_10mps*). It uses busy waiting for first measurement + * results. + */ +void user_task_sensor2 (void *pvParameters) +{ + sht3x_values_t values; + + // start periodic measurement mode + sht3x_start_measurement (sensor2, periodic_10mps); + + // busy waiting until measurement results are available + while (sht3x_is_measuring (sensor2) > 0); + + TickType_t last_wakeup = xTaskGetTickCount(); + + while (1) + { + // retrieve the values and do something with them + if (sht3x_get_results (sensor2, &values)) + printf("%.3f SHT3x Sensor2: %.2f °C, %.2f %%\n", + (double)sdk_system_get_time()*1e-3, + values.temperature, values.humidity); + + // passive waiting until 2 seconds are over + vTaskDelayUntil(&last_wakeup, 2000 / portTICK_PERIOD_MS); + } +} + + +void user_init(void) +{ + // Please note: Return values are not considered in this example for + // readability reasons. All functions return boolean and set an error + // code that allows effective error handling. + + // Set UART Parameter + uart_set_baud(0, 115200); + + // Give the UART some time to settle + sdk_os_delay_us(500); + + // Init I2C bus interfaces at which SHT3x sensors are connected + // (different busses are possible) + i2c_init(I2C_1_BUS, I2C_1_SCL_PIN, I2C_1_SDA_PIN, I2C_FREQ_100K); + i2c_init(I2C_2_BUS, I2C_2_SCL_PIN, I2C_2_SDA_PIN, I2C_FREQ_100K); + + // Create sensors + sensor1 = sht3x_init_sensor (I2C_1_BUS, SHT3x_ADDR_2); + sensor2 = sht3x_init_sensor (I2C_2_BUS, SHT3x_ADDR_1); + + // Create tasks that use the sensors + xTaskCreate(user_task_sensor1, "user_task_sensor1", 256, NULL, 2, 0); + xTaskCreate(user_task_sensor2, "user_task_sensor2", 256, NULL, 2, 0); + + // That's it. +} diff --git a/extras/sht3x/README.md b/extras/sht3x/README.md new file mode 100644 index 0000000..2d52329 --- /dev/null +++ b/extras/sht3x/README.md @@ -0,0 +1,259 @@ +# Driver for **SHT3x** digital **temperature and humidity sensor** + +This driver is written for usage with the ESP8266 and FreeRTOS using the I2C interface driver. It supports multiple sensors connected to the same or different I2C interfaces. + +## About the sensor + +SHT3x is a digital temperature and humidity sensor that uses an I2C interface with up to 1 MHz communication speed. It can operate with **three levels of repeatability** (low, medium and high) and in two different modes, the **single shot data acquisition mode** (or short **single shot mode**) and the **periodic data acquisition mode** (or short **periodic mode**). + +### Repeatability + +Repeatability or test–retest reliability is the variation in measurement results taken by the sensor under the same conditions, and in a short period of time. It is a measure for the noise on the physical sensor output. The higher the repeatability the smaller are changes in the output subsequent measurements. + +The repeatability settings influences the measurement duration as well as the power consumption of the sensor. The measurement takes 3 ms with low repeatability, 5 ms with medium repeatability and 13.5 ms with high repeatability. That is, the measurement produces a noticeable delay in execution. + +While the sensor measures at the lowest repeatability, the average current consumption is 800 μA. That is, the higher the repeatability level, the longer the measurement takes and the higher the power consumption. The sensor consumes only 0.2 μA in standby mode. + +### Single shot data acquisition mode + +In this mode, a measurement command triggers the acquisition of **exactly one data pair**. Each data pair consists of temperature and humidity as 16-bit decimal values. + +### Periodic data acquisition mode + +In this mode, one issued measurement command yields a stream of data pairs. Each data pair again consists of temperature and humidity as 16-bit decimal values. As soon as the measurement command has been sent to the sensor, it performs measurements **periodically at a rate of 0.5, 1, 2, 4 or 10 measurements per second (mps)**. The data pairs can be read with a fetch command at the same rate. + +As in the *single shot mode*, the repeatability setting affects both the measurement duration and the current consumption of the sensor, see above. + + +## How the driver works + +The driver supports multiple SHT3x sensors at the same time. They can be connected with different addresses at the same I2C bus or with arbitrary addresses to different I2C buses. Each sensor has to be initialized at the beginning using function **_sht3x_init_sensor_**. Parameters are the I2C bus and address at which the sensor is connected. + +### Measurement process + +Once the sensor is initialized and tested, it can be used for measurements. In order to avoid blocking of user tasks during measurements due to their duration, the measurement process is splitted into the following steps: + +1. Trigger the sensor to start the measurement either in *single shot mode* or in *periodic mode*. + +2. Fetch the values from the sensor once in *single shot mode* or periodically in *periodic mode* + +Between the first step and the second step, the sensor performs the measurement, which can take up to 30 ms. During that time the user task has to wait. + +#### Single shot data acquisition mode + +In the *single shot mode*, the user task has to execute both steps every time new sensor values are needed, including the waiting time. The advantage of this mode is that the sensor can switch between successive measurements into the sleep mode which is more power-efficient. However, using the *single shot mode* produces a delay of up to 30 ms for each measurement. + +#### Periodic data acquisition mode + +In the *periodic mode*, the sensor automatically performs periodic measurements. Once the sensor has been triggered to start periodic measurements, new measurement results become available every 100 ms, 250 ms, 500 ms, 1000 ms or 2000 ms. The user task has simply to fetch them. Of course, the rate of fetching new measurement results must be less than the rate used by the sensor. The only waiting time required in this mode is the time between the start of the periodic measurements and the time when the first measurement results become available. + +As in the *single shot mode* the sensor switches to the sleep mode between successive measurements. Thus, the *periodic mode* becomes as power-efficient as the *single shot mode* when at least one measurement result per second is required by the user task. Only, if the user task requires new measurement results seldom, e.g. one measurement per minute, then the *single shot mode* is the better choice. + +### Starting measurement + +Measurements are started using function **_sht3x_start_measurement_**. The SHT3x data acquisition mode to be used is defined by a parameter. In both modes, the highest repeatability is used. + +If the measurement could be started successfully, the function returns an estimated duration until the first measurement results become available. The user task can use this duration with function **_vTaskDelay_** to wait until the measurement results are available. Alternatively, function **_sht3x_is_running_** can be used to realize a busy waiting. This function returns the remaining duration until the measurement will be finished. + +Please note: Since *vTaskDelay* can only handle delays as multiples of 10 ms, the duration obtained as return value from function *sht3x_start_measurement* is 30 ms for high repeatability and 20 ms for medium as well as low repeatability. + +### Measured data + +Once new measurement results are available, either function **_sht3x_get_raw_data_** or function **_sht3x_get_results_** can be used to fetch the results. + +Function **__sht3x_get_raw_data_** fetches only the raw sensor data in 16-decimal format, checks the CRC checksums and stores them in an byte array of type **_sht3x_raw_data_t_**. The user task then can use them directly or to call function **_sht3x_compute_values_** to compute floating point sensor values from them. + +Function **_sht3x_get_results_** combines function *sht3x_read_raw_data* and function + *sht3x_compute_valus_* to get the latest sensor values. This is the preferred approach to get sensor values by the user task. + +In the **periodic mode**, the function *sht3x get_results* can be executed repeatedly without a new call of function *sht3_start_measurement* and without a new waiting time. However, the rate of the repeated call should be less than the half of the periodic measuring rate of the sensor. + +## Error Handling + +Most driver functions return a simple boolean value to indicate whether its execution was successful or an error happened. In later case, the member **_error_code_** of the sensor device data structure is set which indicates what error happened. + +There are two different error levels that are ORed into one single *error_code*, errors in I2C communication and errors with the SHT3x sensor itself. To test for a certain error you can AND the *error_code* with one of the error masks, **_SHT3x_I2C_ERROR_MASK_** for I2C errors and **_SHT3x_DRV_ERROR_MASK_** for other errors and then test for a certain error code. + +## Usage + +Before using the SHT3x driver, function **_i2c_init_** needs to be called for each I2C interface to setup them. + +``` +#include "sht3x/sht3x.h" +... +#define I2C_BUS 0 +#define I2C_SCL_PIN GPIO_ID_PIN((5)) +#define I2C_SDA_PIN GPIO_ID_PIN((4)) + +... +i2c_init(I2C_BUS, I2C_SCL_PIN, I2C_SDA_PIN, I2C_FREQ_100K)) +... +``` + +``` +sht3x_init_driver(); +``` + +Once I2C interfaces are initialized, function **_sht3x_init_sensor_** has to be called for each sensor to initialize the sensor and to check its availability as well as its error state. The parameters specify the I2C bus and address to which it is connected. + +``` +static sht3x_sensor_t* sensor; // pointer to sensor device data structure +... +sensor = sht3x_init_sensor (I2C_BUS, SHT3x_ADDR_2); +``` + +Function **_sht3x_init_sensor_** returns a pointer to the sensor device data structure or NULL in case of error. + +Last, the user task that uses the sensor has to be created. + +``` +xTaskCreate(user_task, "user_task", 256, NULL, 2, 0); +``` + +The user task can use the sensor in two different ways, either in *periodic mode* or in *single shot mode*. + +In *periodic mode* the user task calls function **_sht3x_start_measurement_** only once and fetches the measurement result in each cycle with function **_sht3x_get_results_** without any delay. In this mode the user task could look like the following: + +``` +void user_task(void *pvParameters) +{ + sht3x_values_t values; + int32_t duration; + + duration = sht3x_start_measurement (sensor, periodic_1mps); + + // busy waiting + // while (sht3x_is_measuring (sensor) > 0) ; + + // suspend the task for waiting + if (duration > 0) + vTaskDelay (duration/portTICK_PERIOD_MS); + + TickType_t last_wakeup = xTaskGetTickCount(); + + while (1) + { + // retrieve the values and do something with them + if (sht3x_get_results (sensor, &values)) + printf("%.3f SHT3x Sensor: %.2f °C, %.2f %%\n", + (double)sdk_system_get_time()*1e-3, + values.temperature, values.humidity); + + // passive waiting until 2 seconds are over + vTaskDelayUntil(&last_wakeup, 2000 / portTICK_PERIOD_MS); + } +} +``` +At the beginning of the task, the periodic measurement is started by function **_sht3x_start_measurement_** with a rate of 1 measurements per second. Using the duration returned from this function, the task is delayed using **_vTaskDelay_**. This is the duration until the first measurement results become available. The busy waiting alternative is shown in comments. + +Inside the task loop, the measurement results are fetched periodically using function **_sht3x_get_results_** with a rate of once per second. + +In the *single shot mode*, the measurement in each cycle consist of the three steps: + +- start the measurement using function **sht3x_start_measurement_** +- waiting the measurement duration +- fetch the results using function **sht3x_get_results_** + +Thus the user task could look like the following: + +``` +void user_task(void *pvParameters) +{ + sht3x_values_t values; + int32_t duration; + + TickType_t last_wakeup = xTaskGetTickCount(); + + while (1) + { + // trigger one measurement in single shot mode + duration = sht3x_start_measurement (sensor, single_shot); + + // busy waiting + // while (sht3x_is_measuring (sensor) > 0) ; + + // passive waiting until measurement results are available + if (duration > 0) + vTaskDelay (duration/portTICK_PERIOD_MS); + + // retrieve the values and do something with them + if (sht3x_get_results (sensor, &values)) + printf("%.3f SHT3x Sensor: %.2f °C, %.2f %%\n", + (double)sdk_system_get_time()*1e-3, + values.temperature, values.humidity); + + // passive waiting until 5 seconds are over + vTaskDelayUntil(&last_wakeup, 5000 / portTICK_PERIOD_MS); + } +``` +In contrast to the *periodic mode*, the function **_sht3x_start_measurement_** is called inside the task loop to start the measurement in each cycle. The task is then also delayed every time. + +## Full Example + +``` +#include "espressif/esp_common.h" +#include "esp/uart.h" + +#include "FreeRTOS.h" +#include "task.h" + +// include SHT3x driver +#include "sht3x/sht3x.h" + +// define I2C interfaces at which SHTx3 sensors are connected +#define I2C_BUS 0 +#define I2C_SCL_PIN GPIO_ID_PIN((5)) +#define I2C_SDA_PIN GPIO_ID_PIN((4)) + +static sht3x_sensor_t* sensor; // sensor device data structure + +void user_task (void *pvParameters) +{ + sht3x_values_t values; + + // start periodic measurement mode + sht3x_start_measurement (sensor, periodic_1mps); + + // busy waiting until measurement results are available + while (sht3x_is_measuring (sensor) > 0) ; + + TickType_t last_wakeup = xTaskGetTickCount(); + + while (1) + { + // retrieve the values and do something with them + if (sht3x_get_results (sensor, &values)) + printf("%.3f SHT3x Sensor: %.2f °C, %.2f %%\n", + (double)sdk_system_get_time()*1e-3, + values.temperature, values.humidity); + + // passive waiting until 2 seconds are over + vTaskDelayUntil(&last_wakeup, 2000 / portTICK_PERIOD_MS); + } +} + +void user_init(void) +{ + // Set UART Parameter + uart_set_baud(0, 115200); + + // Give the UART some time to settle + sdk_os_delay_us(500); + + // Init I2C bus interfaces at which SHT3x sensors are connected + // (different busses are possible) + i2c_init(I2C_BUS, I2C_SCL_PIN, I2C_SDA_PIN, I2C_FREQ_100K); + + // Create sensors + sensor = sht3x_init_sensor (I2C_BUS, SHT3x_ADDR_2); + + // Create a user task that uses the sensor + xTaskCreate(user_task, "user_task", 256, NULL, 2, 0); + + // That's it. +} +``` + +## Further Examples + +See also the examples in the examples directory [examples directory](../../examples/sht3x/README.md). diff --git a/extras/sht3x/component.mk b/extras/sht3x/component.mk new file mode 100644 index 0000000..3d8c544 --- /dev/null +++ b/extras/sht3x/component.mk @@ -0,0 +1,9 @@ +# Component makefile for extras/sht3x + +# expected anyone using SHT3x driver includes it as 'sht3x/sht3x.h' +INC_DIRS += $(sht3x_ROOT).. + +# args for passing into compile rule generation +sht3x_SRC_DIR = $(sht3x_ROOT) + +$(eval $(call component_compile_rules,sht3x)) diff --git a/extras/sht3x/sht3x.c b/extras/sht3x/sht3x.c new file mode 100644 index 0000000..a15fb2e --- /dev/null +++ b/extras/sht3x/sht3x.c @@ -0,0 +1,442 @@ +/* + * Driver for Sensirion SHT3x digital temperature and humidity sensor + * connected to I2C + * + * Part of esp-open-rtos + * + * ---------------------------------------------------------------- + * + * The BSD License (3-clause license) + * + * Copyright (c) 2017 Gunar Schorcht (https://github.com/gschorcht + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * Driver for Sensirion SHT3x digital temperature and humity sensor + * connected to I2C + * + * Part of esp-open-rtos + */ + +#include + +#include "sht3x.h" + +#include "FreeRTOS.h" + +#include "espressif/esp_common.h" +#include "espressif/sdk_private.h" + +#define SHT3x_STATUS_CMD 0xF32D +#define SHT3x_CLEAR_STATUS_CMD 0x3041 +#define SHT3x_RESET_CMD 0x30A2 +#define SHT3x_FETCH_DATA_CMD 0xE000 +#define SHT3x_HEATER_OFF_CMD 0x3066 + +uint16_t SHT3x_MEASURE_CMD[6][3] = { {0x2c06,0x2c0d,0x2c10}, // [SINGLE_SHOT][H,M,L] + {0x2032,0x2024,0x202f}, // [PERIODIC_05][H,M,L] + {0x2130,0x2126,0x212d}, // [PERIODIC_05][H,M,L] + {0x2236,0x2220,0x222b}, // [PERIODIC_05][H,M,L] + {0x2234,0x2322,0x2329}, // [PERIODIC_05][H,M,L] + {0x2737,0x2721,0x272a} }; // [PERIODIC_05][H,M,L] + +int32_t SHT3x_MEASURE_DURATION[3] = {30,20,20}; // [High, Medium, Low] + +#ifdef SHT3x_DEBUG +#define debug(s, f, ...) printf("%s %s: " s "\n", "SHT3x", f, ## __VA_ARGS__) +#define debug_dev(s, f, d, ...) printf("%s %s: bus %d, addr %02x - " s "\n", "SHT3x", f, d->bus, d->addr, ## __VA_ARGS__) +#else +#define debug(s, f, ...) +#define debug_dev(s, f, d, ...) +#endif + +#define error(s, f, ...) printf("%s %s: " s "\n", "SHT3x", f, ## __VA_ARGS__) +#define error_dev(s, f, d, ...) printf("%s %s: bus %d, addr %02x - " s "\n", "SHT3x", f, d->bus, d->addr, ## __VA_ARGS__) + +/** Forward declaration of function for internal use */ + +static bool sht3x_send_command (sht3x_sensor_t*, uint16_t); +static bool sht3x_read_data (sht3x_sensor_t*, uint8_t*, uint32_t); +static bool sht3x_get_status (sht3x_sensor_t*, uint16_t*); + +static uint8_t crc8 (uint8_t data[], int len); + +/** ------------------------------------------------ */ + +bool sht3x_init_driver() +{ + return true; +} + + +sht3x_sensor_t* sht3x_init_sensor(uint8_t bus, uint8_t addr) +{ + sht3x_sensor_t* dev; + + if ((dev = malloc (sizeof(sht3x_sensor_t))) == NULL) + return NULL; + + // init sensor data structure + dev->bus = bus; + dev->addr = addr; + dev->mode = single_shot; + dev->repeatability = high; + dev->meas_started = false; + dev->meas_start_time = 0; + + dev->active = true; + + uint16_t status; + + // soft-reset including status check leads to i2c problems. + // if (!sht3x_reset (dev)) + if (!sht3x_get_status (dev, & status)) + { + error_dev ("could not reset or check the status of the sensor", __FUNCTION__, dev); + free(dev); + return NULL; + } + + // clear sensor status register + if (!sht3x_send_command(dev, SHT3x_CLEAR_STATUS_CMD)) + { + error_dev ("could not clear sensor status", __FUNCTION__, dev); + free(dev); + return NULL; + } + + // check the again the status after clear status command + if (!sht3x_get_status(dev, &status)) + { + error_dev ("could not get sensor status", __FUNCTION__, dev); + free(dev); + return NULL; + } + + debug_dev ("sensor initialized", __FUNCTION__, dev); + return dev; +} + + +int32_t sht3x_start_measurement (sht3x_sensor_t* dev, sht3x_mode_t mode) +{ + if (!dev || !dev->active) return -1; + + dev->error_code = SHT3x_OK; + + // return remaining time when measurement is already running + if (dev->meas_started) + { + debug_dev ("measurement already started", __FUNCTION__, dev); + dev->error_code = SHT3x_MEAS_ALREADY_RUNNING; + return sht3x_is_measuring (dev); + } + + dev->mode = mode; + + // start measurement according to selected mode and return an duration estimate + if (sht3x_send_command(dev, SHT3x_MEASURE_CMD[dev->mode][dev->repeatability])) + { + dev->meas_start_time = sdk_system_get_time (); + dev->meas_started = true; + dev->meas_first = true; + return SHT3x_MEASURE_DURATION[dev->repeatability]; // in ms + } + + dev->error_code |= SHT3x_SEND_MEAS_CMD_FAILED; + return -1; // on error +} + + +// returns 0 when finished, -1 on error, remaining measurement time otherwise +int32_t sht3x_is_measuring (sht3x_sensor_t* dev) +{ + if (!dev || !dev->active) return -1; + + dev->error_code = SHT3x_OK; + + if (!dev->meas_started) + { + error_dev ("measurement not started", __FUNCTION__, dev); + dev->error_code = SHT3x_MEAS_NOT_STARTED; + return -1; + } + + // computation is necessary in periodic mode only for first measurement + // in single shot mode every measurment is the first one + if (!dev->meas_first) + return 0; + + uint32_t start_time = dev->meas_start_time ; // in us + uint32_t system_time = sdk_system_get_time(); // in us + uint32_t elapsed_time; + + if (system_time < start_time) + // in case of timer overflow + elapsed_time = (UINT32_MAX - start_time + system_time) / 1000; // in ms + else + // normal case + elapsed_time = (system_time - start_time) / 1000; // in ms + + if (elapsed_time >= SHT3x_MEASURE_DURATION[dev->repeatability]) + return 0; + else + return SHT3x_MEASURE_DURATION[dev->repeatability] - elapsed_time; +} + + +bool sht3x_get_raw_data(sht3x_sensor_t* dev, sht3x_raw_data_t raw_data) +{ + if (!dev || !dev->active || !raw_data) return false; + + dev->error_code = SHT3x_OK; + + if (sht3x_is_measuring (dev) == -1) + { + error_dev ("measurement is still running", __FUNCTION__, dev); + return false; + } + + if (dev->mode == single_shot && + sht3x_read_data(dev, raw_data, sizeof(sht3x_raw_data_t))) + { + debug_dev ("single shot data available", __FUNCTION__, dev); + dev->meas_started = false; + } + else if (dev->mode != single_shot && + sht3x_send_command(dev, SHT3x_FETCH_DATA_CMD) && + sht3x_read_data(dev, raw_data, sizeof(sht3x_raw_data_t))) + { + debug_dev ("periodic data available", __FUNCTION__, dev); + dev->meas_first = false; + } + else + { + error_dev ("read raw data failed", __FUNCTION__, dev); + dev->error_code |= SHT3x_READ_RAW_DATA_FAILED; + return false; + } + + if (crc8(raw_data,2) != raw_data[2]) + { + error_dev ("CRC check for temperature data failed", __FUNCTION__, dev); + dev->error_code |= SHT3x_WRONG_CRC_TEMPERATURE; + return false; + } + + if (crc8(raw_data+3,2) != raw_data[5]) + { + error_dev ("CRC check for humidity data failed", __FUNCTION__, dev); + dev->error_code |= SHT3x_WRONG_CRC_HUMIDITY; + return false; + } + + return true; +} + + +bool sht3x_compute_values (sht3x_raw_data_t raw_data, sht3x_values_t* values) +{ + if (!raw_data || !values) return false; + + values->temperature = ((((raw_data[0] * 256.0) + raw_data[1]) * 175) / 65535.0) - 45; + values->humidity = ((((raw_data[3] * 256.0) + raw_data[4]) * 100) / 65535.0); + + return true; +} + + +bool sht3x_get_results (sht3x_sensor_t* dev, sht3x_values_t* values) +{ + if (!dev || !dev->active || !values) return false; + + sht3x_raw_data_t raw_data; + + if (!sht3x_get_raw_data (dev, raw_data)) + return false; + + return sht3x_compute_values (raw_data, values); +} + +/* Functions for internal use only */ + +static bool sht3x_send_command(sht3x_sensor_t* dev, uint16_t cmd) +{ + if (!dev || !dev->active) return false; + + uint8_t data[2] = { cmd >> 8, cmd & 0xff }; + + debug_dev ("send command MSB=%02x LSB=%02x", __FUNCTION__, dev, data[0], data[1]); + + int err; + int count = 10; + + // in case i2c is busy, try to write up to ten times and 100 ms + // tested with a task that is disturbing by using i2c bus almost all the time + while ((err=i2c_slave_write(dev->bus, dev->addr, 0, data, 2)) == -EBUSY && count--) + vTaskDelay (10 / portTICK_PERIOD_MS); + + if (err) + { + dev->error_code |= (err == -EBUSY) ? SHT3x_I2C_BUSY : SHT3x_I2C_SEND_CMD_FAILED; + error_dev ("i2c error %d on write command %02x", __FUNCTION__, dev, err, cmd); + return false; + } + + return true; +} + + +static bool sht3x_read_data(sht3x_sensor_t* dev, uint8_t *data, uint32_t len) +{ + if (!dev || !dev->active) return false; + + int err; + int count = 10; + + // in case i2c is busy, try to read up to ten times and 100 ms + while ((err=i2c_slave_read(dev->bus, dev->addr, 0, data, len)) == -EBUSY && count--) + vTaskDelay (10 / portTICK_PERIOD_MS); + + if (err) + { + dev->error_code |= (err == -EBUSY) ? SHT3x_I2C_BUSY : SHT3x_I2C_READ_FAILED; + error_dev ("error %d on read %d byte", __FUNCTION__, dev, err, len); + return false; + } + +# ifdef SHT3x_DEBUG + printf("SHT3x %s: bus %d, addr %02x - read following bytes: ", + __FUNCTION__, dev->bus, dev->addr); + for (int i=0; i < len; i++) + printf("%02x ", data[i]); + printf("\n"); +# endif + + return true; +} + + +/* +static bool sht3x_reset (sht3x_sensor_t* dev) +{ + if (!dev || !dev->active) return false; + + debug_dev ("soft-reset triggered", __FUNCTION__, dev); + + dev->error_code = SHT3x_OK; + + // send reset command + if (!sht3x_send_command(dev, SHT3x_RESET_CMD)) + { + dev->error_code |= SHT3x_SEND_RESET_CMD_FAILED; + return false; + } + // wait for small amount of time needed (according to datasheet 0.5ms) + vTaskDelay (20 / portTICK_PERIOD_MS); + + uint16_t status; + + // check the status after reset + if (!sht3x_get_status(dev, &status)) + return false; + + return true; +} +*/ + + +static bool sht3x_get_status (sht3x_sensor_t* dev, uint16_t* status) +{ + if (!dev || !dev->active || !status) return false; + + dev->error_code = SHT3x_OK; + + uint8_t data[3]; + + if (!sht3x_send_command(dev, SHT3x_STATUS_CMD) || !sht3x_read_data(dev, data, 3)) + { + dev->error_code |= SHT3x_STATUS_CMD_FAILED; + return false; + } + + *status = data[0] << 8 | data[1]; + debug_dev ("status=%02x", __FUNCTION__, dev, *status); + return true; +} + + + +static uint8_t* crc8_table; // lookup table with precomputed crc values +static bool crc8_first_time = true; // indicator whether table has still to be created + +static void generate_crc8_table() +{ + const uint8_t g_polynom = 0x31; + + for (int i=0; i < 256; i++) + { + uint8_t value = (uint8_t)i; + for (uint8_t bit = 0; bit < 8; bit++) + { + bool xor = value & 0x80; + value = value << 1; + value = xor ? value ^ g_polynom : value; + } + crc8_table[i] = value; + } +} + + +static uint8_t crc8 (uint8_t data[], int len) +{ + // generate crc lookup table first time it is called + if (crc8_first_time) + { + crc8_first_time = false; + crc8_table = malloc(256); + generate_crc8_table (); + } + + // initialization value + uint8_t crc = 0xff; + + // iterate over all bytes + for (int i=0; i < len; i++) + { + uint8_t b = data[i]; + uint8_t data = (uint8_t)(b ^ crc); + crc = (uint8_t)(crc8_table[data]); + } + + return crc; +} + + diff --git a/extras/sht3x/sht3x.h b/extras/sht3x/sht3x.h new file mode 100644 index 0000000..8a6e94e --- /dev/null +++ b/extras/sht3x/sht3x.h @@ -0,0 +1,258 @@ +/* + * Driver for Sensirion SHT3x digital temperature and humidity sensor + * connected to I2C + * + * Part of esp-open-rtos + * + * ---------------------------------------------------------------- + * + * The BSD License (3-clause license) + * + * Copyright (c) 2017 Gunar Schorcht (https://github.com/gschorcht + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef DRIVER_SHT3x_H_ +#define DRIVER_SHT3x_H_ + +#include "stdint.h" +#include "stdbool.h" + +#include "FreeRTOS.h" + +#include "i2c/i2c.h" + +// Uncomment to enable debug output +// #define SHT3x_DEBUG + +#ifdef __cplusplus +extern "C" { +#endif + +// definition of possible I2C slave addresses +#define SHT3x_ADDR_1 0x44 // ADDR pin connected to GND/VSS (default) +#define SHT3x_ADDR_2 0x45 // ADDR pin connected to VDD + +// definition of error codes +#define SHT3x_OK 0 + +#define SHT3x_I2C_ERROR_MASK 0x000f +#define SHT3x_DRV_ERROR_MASK 0xfff0 + +// error codes for I2C interface ORed with SHT3x error codes +#define SHT3x_I2C_READ_FAILED 1 +#define SHT3x_I2C_SEND_CMD_FAILED 2 +#define SHT3x_I2C_BUSY 3 + +// SHT3x driver error codes OR ed with error codes for I2C interface +#define SHT3x_MEAS_NOT_STARTED (1 << 8) +#define SHT3x_MEAS_ALREADY_RUNNING (2 << 8) +#define SHT3x_MEAS_STILL_RUNNING (3 << 8) +#define SHT3x_READ_RAW_DATA_FAILED (4 << 8) + +#define SHT3x_SEND_MEAS_CMD_FAILED (5 << 8) +#define SHT3x_SEND_RESET_CMD_FAILED (6 << 8) +#define SHT3x_STATUS_CMD_FAILED (7 << 8) + +#define SHT3x_WRONG_CRC_TEMPERATURE (8 << 8) +#define SHT3x_WRONG_CRC_HUMIDITY (9 << 8) + +#define SHT3x_RAW_DATA_SIZE 6 + +/** + * @brief raw data type + */ +typedef uint8_t sht3x_raw_data_t [SHT3x_RAW_DATA_SIZE]; + +/** + * @brief sensor values type + */ +typedef struct { + float temperature; // temperature in degree Celcius + float humidity; // humidity in percent +} sht3x_values_t; + + +/** + * @brief possible measurement modes + */ +typedef enum { + single_shot = 0, // one single measurement + periodic_05mps, // periodic with 0.5 measurements per second (mps) + periodic_1mps, // periodic with 1 measurements per second (mps) + periodic_2mps, // periodic with 2 measurements per second (mps) + periodic_4mps, // periodic with 4 measurements per second (mps) + periodic_10mps // periodic with 10 measurements per second (mps) +} sht3x_mode_t; + + +/** + * @brief possible repeatability modes + */ +typedef enum { + high = 0, + medium, + low +} sht3x_repeat_t; + +/** + * @brief SHT3x sensor device data structure type + */ +typedef struct { + + bool active; // indicates whether sensor is active + + uint32_t error_code; // + + uint8_t bus; // I2C bus at which sensor is connected + uint8_t addr; // I2C slave address of the sensor + + sht3x_mode_t mode; // used measurement mode + sht3x_repeat_t repeatability; // used repeatability + + bool meas_started; // indicates whether measurement started + uint32_t meas_start_time; // measurement start time in microseconds + bool meas_first; // first measurement in periodic mode + +} sht3x_sensor_t; + + +/** + * @brief Initialize a SHT3x sensor + * + * The function creates a data structure describing the sensor device, + * initializes, probes for the device, and configures the device that is + * connected at the specified I2C bus with the given slave address. + * + * @param bus I2C bus at which sensor is connected + * @param addr I2C slave address of the sensor + * @return pointer to sensor data structure, or NULL on error + */ +sht3x_sensor_t* sht3x_init_sensor (uint8_t bus, uint8_t addr); + + +/** + * @brief Start single shot or periodic measurements + * + * The function starts the measurement either in *single shot mode* + * (exactly one measurement) or *periodic mode* (periodic measurements). + * + * In the *single shot mode*, this function has to be called for each + * measurement. The measurement duration returned by the function has to be + * waited every time before the results can be fetched. + * + * In the *periodic mode*, this function has to be called only once. Also the + * measurement duration must be waited only once until the first results are + * available. After this first measurement, the sensor then automatically + * performs all subsequent measurements. The rate of periodic measurements can + * be 10, 4, 2, 1 or 0.5 measurements per second (mps). The user task can + * fetch the results with the half or less rate. The rate of the periodic + * measurements is defined by the parameter *mode*. + * + * On success, the function returns an estimated measurement duration. This + * defines the duration needed by the sensor before first results become + * available. The user task has to wait this time before it can fetch the + * results using function *sht3x_get_results* or *sht3x_get_raw_data*. + * + * @param dev pointer to sensor device data structure + * @param mode measurement mode, see type *sht3x_mode_t* + * @return true on success, false on error + */ +int32_t sht3x_start_measurement (sht3x_sensor_t* dev, sht3x_mode_t mode); + + +/** + * @brief Check whether measurement is still running + * + * The function can be used to test whether a measurement has been started + * at all and how long it still takes before measurement results become + * available. The return value can be + * + * >0 in case the measurement is is still running, + * 0 in case the measurement has been already finished, or + * <0 in case of error. + * + * That is, a return value greater than 0 indicates that the measurement + * results are still not available and the user task has to wait that time. + * + * @param dev pointer to sensor device data structure + * @return remaining measurement duration or -1 on error + */ +int32_t sht3x_is_measuring (sht3x_sensor_t* dev); + +/** + * @brief Read the results from sensor as raw data + * + * The function read measurement results from the sensor, checks the CRC + * checksum and stores them in the byte array as following. + * + * data[0] = Temperature MSB + * data[1] = Temperature LSB + * data[2] = Temperature CRC + * data[3] = Pressure MSB + * data[4] = Pressure LSB + * data[2] = Pressure CRC + * + * In case that there are no new data that can be read, the function returns + * false. + * + * @param dev pointer to sensor device data structure + * @param raw_data byte array in which raw data are stored + * @return true on success, false on error + */ +bool sht3x_get_raw_data(sht3x_sensor_t* dev, sht3x_raw_data_t raw_data); + +/** + * @brief Computes sensor values from raw data + * + * @param raw_data byte array that contains raw data + * @param values pointer to data structure in which results are stored + * @return true on success, false on error + */ +bool sht3x_compute_values (sht3x_raw_data_t raw_data, + sht3x_values_t* values); + +/** + * @brief Get the results of latest measurement + * + * The function combines function *sht3x_read_raw_data* and function + * *sht3x_compute_values* to get the latest measurement results. + * + * @param dev pointer to sensor device data structure + * @param values pointer to data structure in which results are stored + * @return true on success, false on error + */ +bool sht3x_get_results (sht3x_sensor_t* dev, sht3x_values_t* values); + + +#ifdef __cplusplus +} +#endif + +#endif /* DRIVER_SHT3x_H_ */ From b0ebf3385ea15d8569357c400c17a3918da4fb09 Mon Sep 17 00:00:00 2001 From: Gunar Schorcht Date: Thu, 12 Oct 2017 16:22:16 +0200 Subject: [PATCH 02/14] SHT3x driver changes Additional include to satisfy the Travis CI test build --- extras/sht3x/README.md | 2 +- extras/sht3x/sht3x.c | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/extras/sht3x/README.md b/extras/sht3x/README.md index 2d52329..9e74c29 100644 --- a/extras/sht3x/README.md +++ b/extras/sht3x/README.md @@ -64,7 +64,7 @@ Once new measurement results are available, either function **_sht3x_get_raw_dat Function **__sht3x_get_raw_data_** fetches only the raw sensor data in 16-decimal format, checks the CRC checksums and stores them in an byte array of type **_sht3x_raw_data_t_**. The user task then can use them directly or to call function **_sht3x_compute_values_** to compute floating point sensor values from them. Function **_sht3x_get_results_** combines function *sht3x_read_raw_data* and function - *sht3x_compute_valus_* to get the latest sensor values. This is the preferred approach to get sensor values by the user task. + *sht3x_compute_values_* to get the latest sensor values. This is the preferred approach to get sensor values by the user task. In the **periodic mode**, the function *sht3x get_results* can be executed repeatedly without a new call of function *sht3_start_measurement* and without a new waiting time. However, the rate of the repeated call should be less than the half of the periodic measuring rate of the sensor. diff --git a/extras/sht3x/sht3x.c b/extras/sht3x/sht3x.c index a15fb2e..465ae32 100644 --- a/extras/sht3x/sht3x.c +++ b/extras/sht3x/sht3x.c @@ -50,6 +50,7 @@ #include "sht3x.h" #include "FreeRTOS.h" +#include "task.h" #include "espressif/esp_common.h" #include "espressif/sdk_private.h" From 3fee4b8f0cb9efb9f9ba746b98c77c012ef658e7 Mon Sep 17 00:00:00 2001 From: Gunar Schorcht Date: Fri, 13 Oct 2017 13:37:01 +0200 Subject: [PATCH 03/14] SHT3x driver - small changes README.md has been shortened --- extras/sht3x/README.md | 188 ++++++++++++++++++++++++----------------- 1 file changed, 110 insertions(+), 78 deletions(-) diff --git a/extras/sht3x/README.md b/extras/sht3x/README.md index 9e74c29..172de81 100644 --- a/extras/sht3x/README.md +++ b/extras/sht3x/README.md @@ -1,63 +1,48 @@ # Driver for **SHT3x** digital **temperature and humidity sensor** -This driver is written for usage with the ESP8266 and FreeRTOS using the I2C interface driver. It supports multiple sensors connected to the same or different I2C interfaces. +This driver is written for usage with the ESP8266 and FreeRTOS using the I2C interface driver. It supports multiple SHT3x sensors connected to the same or different I2C interfaces. ## About the sensor SHT3x is a digital temperature and humidity sensor that uses an I2C interface with up to 1 MHz communication speed. It can operate with **three levels of repeatability** (low, medium and high) and in two different modes, the **single shot data acquisition mode** (or short **single shot mode**) and the **periodic data acquisition mode** (or short **periodic mode**). -### Repeatability +## Measurement process -Repeatability or test–retest reliability is the variation in measurement results taken by the sensor under the same conditions, and in a short period of time. It is a measure for the noise on the physical sensor output. The higher the repeatability the smaller are changes in the output subsequent measurements. +Once the SHT3x sensor is initialized, it can be used for measurements. -The repeatability settings influences the measurement duration as well as the power consumption of the sensor. The measurement takes 3 ms with low repeatability, 5 ms with medium repeatability and 13.5 ms with high repeatability. That is, the measurement produces a noticeable delay in execution. +### Single shot mode -While the sensor measures at the lowest repeatability, the average current consumption is 800 μA. That is, the higher the repeatability level, the longer the measurement takes and the higher the power consumption. The sensor consumes only 0.2 μA in standby mode. +In **single shot mode**, a measurement command triggers the acquisition of **exactly one data pair**. Each data pair consists of temperature and humidity as 16-bit decimal values. -### Single shot data acquisition mode +Due to the measurement duration of up to 30 ms, the measurement process is separated into steps to avoid blocking the user task during measurements: -In this mode, a measurement command triggers the acquisition of **exactly one data pair**. Each data pair consists of temperature and humidity as 16-bit decimal values. +1. Trigger the sensor with function **_sht3x_start_measurement_** to start exactly one single measurement. -### Periodic data acquisition mode +2. Wait the measurement duration until the results are available using passive waiting with function **_vTaskDelay_** or busy waiting with function **_sht3x_is_measuring_**. -In this mode, one issued measurement command yields a stream of data pairs. Each data pair again consists of temperature and humidity as 16-bit decimal values. As soon as the measurement command has been sent to the sensor, it performs measurements **periodically at a rate of 0.5, 1, 2, 4 or 10 measurements per second (mps)**. The data pairs can be read with a fetch command at the same rate. +3. Fetch the results as floating point sensor values with function **sht3x_get_results_** or as raw data with function **sht3x_get_raw_data_**. -As in the *single shot mode*, the repeatability setting affects both the measurement duration and the current consumption of the sensor, see above. +In the *single shot mode*, the user task has to perform all steps every time new sensor values ​​are needed. When using the *single image mode*, however, a delay of up to 30 ms is generated for each measurement. +The advantage of this mode is that the sensor can switch between successive measurements into the sleep mode, which is more energy-efficient. This is particularly useful when the measurement rate is less than 1 measurement per second. -## How the driver works +### Periodic mode -The driver supports multiple SHT3x sensors at the same time. They can be connected with different addresses at the same I2C bus or with arbitrary addresses to different I2C buses. Each sensor has to be initialized at the beginning using function **_sht3x_init_sensor_**. Parameters are the I2C bus and address at which the sensor is connected. +In this mode, one issued measurement command yields a stream of data pairs. Each data pair consists again of temperature and humidity as 16-bit decimal values. As soon as the measurement command has been sent to the sensor, it automatically performs measurements **periodically at a rate of 0.5, 1, 2, 4 or 10 measurements per second (mps)**. The data pairs can be fetched with the same rate or a less rate. -### Measurement process +As in *single shot mode*, the measurement process is separated into the following steps: -Once the sensor is initialized and tested, it can be used for measurements. In order to avoid blocking of user tasks during measurements due to their duration, the measurement process is splitted into the following steps: +1. Trigger the sensor with function **sht3x_start_measurement_** and the rate of periodic measurements to start periodic measurements. -1. Trigger the sensor to start the measurement either in *single shot mode* or in *periodic mode*. +2. Wait the measurement duration until the results are available using passive waiting with function **_vTaskDelay_** or busy waiting with function **_sht3x_is_measuring_**. -2. Fetch the values from the sensor once in *single shot mode* or periodically in *periodic mode* +3. Fetch the results as floating point sensor values with function **sht3x_get_results_** or as raw data with function **sht3x_get_raw_data_**. -Between the first step and the second step, the sensor performs the measurement, which can take up to 30 ms. During that time the user task has to wait. +However, in contrast to the *single shot mode*, steps 1 and 2 have to be executed only once. Once the measurement is started, the user task hast can simply fetch data periodically. -#### Single shot data acquisition mode +The rate of fetching the data must be not greater than the rate of periodic measuring rate of the sensor, however, it *should be less* to avoid conflicts caused by the timing tolerance of the sensor. -In the *single shot mode*, the user task has to execute both steps every time new sensor values are needed, including the waiting time. The advantage of this mode is that the sensor can switch between successive measurements into the sleep mode which is more power-efficient. However, using the *single shot mode* produces a delay of up to 30 ms for each measurement. - -#### Periodic data acquisition mode - -In the *periodic mode*, the sensor automatically performs periodic measurements. Once the sensor has been triggered to start periodic measurements, new measurement results become available every 100 ms, 250 ms, 500 ms, 1000 ms or 2000 ms. The user task has simply to fetch them. Of course, the rate of fetching new measurement results must be less than the rate used by the sensor. The only waiting time required in this mode is the time between the start of the periodic measurements and the time when the first measurement results become available. - -As in the *single shot mode* the sensor switches to the sleep mode between successive measurements. Thus, the *periodic mode* becomes as power-efficient as the *single shot mode* when at least one measurement result per second is required by the user task. Only, if the user task requires new measurement results seldom, e.g. one measurement per minute, then the *single shot mode* is the better choice. - -### Starting measurement - -Measurements are started using function **_sht3x_start_measurement_**. The SHT3x data acquisition mode to be used is defined by a parameter. In both modes, the highest repeatability is used. - -If the measurement could be started successfully, the function returns an estimated duration until the first measurement results become available. The user task can use this duration with function **_vTaskDelay_** to wait until the measurement results are available. Alternatively, function **_sht3x_is_running_** can be used to realize a busy waiting. This function returns the remaining duration until the measurement will be finished. - -Please note: Since *vTaskDelay* can only handle delays as multiples of 10 ms, the duration obtained as return value from function *sht3x_start_measurement* is 30 ms for high repeatability and 20 ms for medium as well as low repeatability. - -### Measured data +## Measurement results Once new measurement results are available, either function **_sht3x_get_raw_data_** or function **_sht3x_get_results_** can be used to fetch the results. @@ -66,13 +51,23 @@ Function **__sht3x_get_raw_data_** fetches only the raw sensor data in 16-decima Function **_sht3x_get_results_** combines function *sht3x_read_raw_data* and function *sht3x_compute_values_* to get the latest sensor values. This is the preferred approach to get sensor values by the user task. -In the **periodic mode**, the function *sht3x get_results* can be executed repeatedly without a new call of function *sht3_start_measurement* and without a new waiting time. However, the rate of the repeated call should be less than the half of the periodic measuring rate of the sensor. - ## Error Handling -Most driver functions return a simple boolean value to indicate whether its execution was successful or an error happened. In later case, the member **_error_code_** of the sensor device data structure is set which indicates what error happened. +Most driver functions return a simple boolean value to indicate whether its execution was successful or an error happened. In the latter case, the member **_error_code_** of the sensor device data structure is set which indicates what error happened. + +There are two different error levels that are ORed into one single *error_code*, errors in the I2C communication and errors with the SHT3x sensor itself. To test for a certain error you can AND the *error_code* with one of the error masks, **_SHT3x_I2C_ERROR_MASK_** for I2C errors and **_SHT3x_DRV_ERROR_MASK_** for other errors and then test for a certain error code. + + +## Repeatability + +The SHT3x sensor supports **three levels of repeatability** (low, medium and high). Repeatability is the variation in measurement results taken by the sensor under the same conditions, and in a short period of time. It is a measure for the noise on the physical sensor output. The higher the repeatability the smaller are changes in the output subsequent measurements. + +The repeatability settings influences the measurement duration as well as the power consumption of the sensor. The measurement takes 3 ms with low repeatability, 5 ms with medium repeatability and 13.5 ms with high repeatability. That is, the measurement produces a noticeable delay in execution. + +While the sensor measures at the lowest repeatability, the average current consumption is 800 μA. That is, the higher the repeatability level, the longer the measurement takes and the higher the power consumption. The sensor consumes only 0.2 μA in standby mode. + +Measurements started using function **_sht3x_start_measurement_** always use highest repeatability level by default. User task can change this by setting member **_repeatability_** of the sensor device data structure before function **_sht3x_start_measurement_** is called. -There are two different error levels that are ORed into one single *error_code*, errors in I2C communication and errors with the SHT3x sensor itself. To test for a certain error you can AND the *error_code* with one of the error masks, **_SHT3x_I2C_ERROR_MASK_** for I2C errors and **_SHT3x_DRV_ERROR_MASK_** for other errors and then test for a certain error code. ## Usage @@ -90,16 +85,15 @@ i2c_init(I2C_BUS, I2C_SCL_PIN, I2C_SDA_PIN, I2C_FREQ_100K)) ... ``` -``` -sht3x_init_driver(); -``` - -Once I2C interfaces are initialized, function **_sht3x_init_sensor_** has to be called for each sensor to initialize the sensor and to check its availability as well as its error state. The parameters specify the I2C bus and address to which it is connected. +Once I2C interfaces are initialized, function **_sht3x_init_sensor_** has to be called for each SHT3x sensor to initialize the sensor and to check its availability as well as its error state. The parameters specify the I2C bus to which it is connected and its I2C slave address. ``` static sht3x_sensor_t* sensor; // pointer to sensor device data structure ... -sensor = sht3x_init_sensor (I2C_BUS, SHT3x_ADDR_2); +if ((sensor = sht3x_init_sensor (I2C_BUS, SHT3x_ADDR_2))) +{ + ... +} ``` Function **_sht3x_init_sensor_** returns a pointer to the sensor device data structure or NULL in case of error. @@ -110,54 +104,51 @@ Last, the user task that uses the sensor has to be created. xTaskCreate(user_task, "user_task", 256, NULL, 2, 0); ``` -The user task can use the sensor in two different ways, either in *periodic mode* or in *single shot mode*. +In the **periodic mode**, the user task has to start the periodic measurement only once at the beginning of the task. After that, it has only to wait for the results of the first measurement. In the task loop itself, it simply fetches the next measurement results in each cycle. -In *periodic mode* the user task calls function **_sht3x_start_measurement_** only once and fetches the measurement result in each cycle with function **_sht3x_get_results_** without any delay. In this mode the user task could look like the following: +Thus, in this mode the user task could look like the following: ``` -void user_task(void *pvParameters) +void user_task (void *pvParameters) { sht3x_values_t values; int32_t duration; + // start periodic measurements with 1 measurement per second duration = sht3x_start_measurement (sensor, periodic_1mps); - // busy waiting - // while (sht3x_is_measuring (sensor) > 0) ; - - // suspend the task for waiting + // passive waiting until first measurement results are available if (duration > 0) vTaskDelay (duration/portTICK_PERIOD_MS); - - TickType_t last_wakeup = xTaskGetTickCount(); + // busy waiting until first measurement results are available + // while (sht3x_is_measuring (sensor) > 0) ; + + TickType_t last_wakeup = xTaskGetTickCount(); + while (1) { - // retrieve the values and do something with them + // get the values and do something with them if (sht3x_get_results (sensor, &values)) printf("%.3f SHT3x Sensor: %.2f °C, %.2f %%\n", (double)sdk_system_get_time()*1e-3, values.temperature, values.humidity); - // passive waiting until 2 seconds are over + // passive waiting until 2 seconds (cycle time) are over vTaskDelayUntil(&last_wakeup, 2000 / portTICK_PERIOD_MS); } } ``` -At the beginning of the task, the periodic measurement is started by function **_sht3x_start_measurement_** with a rate of 1 measurements per second. Using the duration returned from this function, the task is delayed using **_vTaskDelay_**. This is the duration until the first measurement results become available. The busy waiting alternative is shown in comments. -Inside the task loop, the measurement results are fetched periodically using function **_sht3x_get_results_** with a rate of once per second. +At the beginning of the task, the periodic measurement is started by function **_sht3x_start_measurement_** with a rate of 1 measurement per second. Using the measurement duration returned from this function, the task is delayed using **_vTaskDelay_** to wait for first measurement results. The busy waiting alternative using function **_sht3x_is_measuring_** is shown in comments. Inside the task loop, the measurement results are fetched periodically using function **_sht3x_get_results_** with a rate of once per second. -In the *single shot mode*, the measurement in each cycle consist of the three steps: - -- start the measurement using function **sht3x_start_measurement_** -- waiting the measurement duration -- fetch the results using function **sht3x_get_results_** +In the **single shot mode**, the measurement has to be triggered +in each cycle. Waiting for measurement results is also required in each cylce, before the results can be fetched. Thus the user task could look like the following: ``` -void user_task(void *pvParameters) +void user_task (void *pvParameters) { sht3x_values_t values; int32_t duration; @@ -169,13 +160,13 @@ void user_task(void *pvParameters) // trigger one measurement in single shot mode duration = sht3x_start_measurement (sensor, single_shot); - // busy waiting - // while (sht3x_is_measuring (sensor) > 0) ; - // passive waiting until measurement results are available if (duration > 0) vTaskDelay (duration/portTICK_PERIOD_MS); + // busy waiting until first measurement results are available + // while (sht3x_is_measuring (sensor) > 0) ; + // retrieve the values and do something with them if (sht3x_get_results (sensor, &values)) printf("%.3f SHT3x Sensor: %.2f °C, %.2f %%\n", @@ -185,8 +176,40 @@ void user_task(void *pvParameters) // passive waiting until 5 seconds are over vTaskDelayUntil(&last_wakeup, 5000 / portTICK_PERIOD_MS); } +} +``` + +In contrast to the *periodic mode*, the function **_sht3x_start_measurement_** is called inside the task loop to start exactly one measurement in each cycle. The task is then also delayed every time using function **_vTaskDelay_** before the results are fetched with function **_sht3x_get_results_** in each cycle. + +The code could be extended by an error handling. In the event of an error, most driver functions use the **_error_code_** element of the data structure of the sensor device. This indicates which error has occurred. Error codes are a combination of I2C communication error codes and SHT3x sensor error codes. To test a particular error, the *error code* can be AND with one of the error masks **_SHT3x_I2C_ERROR_MASK_** or **_SHT3x_DRV_ERROR_MASK_**. + +For example, error handling for **_sht3x_get_results_** could look like: +``` + +if (sht3x_get_results (sensor, &values)) +{ + // no error happened + ... +} +else +{ + // error happened + + switch (sensor->error_code & SHT3x_I2C_ERROR_MASK) + { + case SHT3x_I2C_BUSY: ... + case SHT3x_I2C_READ_FAILED: ... + ... + } + switch (sensor->error_code & SHT3x_DRV_ERROR_MASK) + { + case SHT3x_MEAS_NOT_RUNNING: ... + case SHT3x_READ_RAW_DATA_FAILED: ... + case SHT3x_WRONG_CRC_TEMPERATURE: ... + ... + } +} ``` -In contrast to the *periodic mode*, the function **_sht3x_start_measurement_** is called inside the task loop to start the measurement in each cycle. The task is then also delayed every time. ## Full Example @@ -207,30 +230,37 @@ In contrast to the *periodic mode*, the function **_sht3x_start_measurement_** i static sht3x_sensor_t* sensor; // sensor device data structure +/* + * User task that fetches latest measurement results of sensor every 2 + * seconds. It starts the SHT3x in periodic mode with 1 measurements per + * second (*periodic_1mps*). It uses busy waiting for first measurement + * results. + */ void user_task (void *pvParameters) { sht3x_values_t values; - // start periodic measurement mode + // start periodic measurements with 1 measurement per second sht3x_start_measurement (sensor, periodic_1mps); - // busy waiting until measurement results are available - while (sht3x_is_measuring (sensor) > 0) ; + if (duration > 0) + vTaskDelay (duration/portTICK_PERIOD_MS); TickType_t last_wakeup = xTaskGetTickCount(); while (1) { - // retrieve the values and do something with them + // get the values and do something with them if (sht3x_get_results (sensor, &values)) printf("%.3f SHT3x Sensor: %.2f °C, %.2f %%\n", (double)sdk_system_get_time()*1e-3, values.temperature, values.humidity); - - // passive waiting until 2 seconds are over + + // passive waiting until 2 seconds (cycle time) are over vTaskDelayUntil(&last_wakeup, 2000 / portTICK_PERIOD_MS); } } +#endif void user_init(void) { @@ -245,11 +275,13 @@ void user_init(void) i2c_init(I2C_BUS, I2C_SCL_PIN, I2C_SDA_PIN, I2C_FREQ_100K); // Create sensors - sensor = sht3x_init_sensor (I2C_BUS, SHT3x_ADDR_2); - - // Create a user task that uses the sensor - xTaskCreate(user_task, "user_task", 256, NULL, 2, 0); + if ((sensor = sht3x_init_sensor (I2C_BUS, SHT3x_ADDR_2))) + { + // Create a user task that uses the sensor + xTaskCreate(user_task, "user_task", 256, NULL, 2, 0); + } + // That's it. } ``` From 6d0545837c1792d8b5c363c600de79169ebe678a Mon Sep 17 00:00:00 2001 From: Gunar Schorcht Date: Fri, 13 Oct 2017 13:39:09 +0200 Subject: [PATCH 04/14] SHT3x driver - small changes --- .../sht3x/sht3x_one_sensor/sht3x_one_sensor.c | 35 +++++++++---------- 1 file changed, 16 insertions(+), 19 deletions(-) diff --git a/examples/sht3x/sht3x_one_sensor/sht3x_one_sensor.c b/examples/sht3x/sht3x_one_sensor/sht3x_one_sensor.c index e906f1d..17fe6ba 100644 --- a/examples/sht3x/sht3x_one_sensor/sht3x_one_sensor.c +++ b/examples/sht3x/sht3x_one_sensor/sht3x_one_sensor.c @@ -16,6 +16,8 @@ * | GPIO 4 (SDA) ------- SDA | * +------------------------+ +----------+ */ + +// #define SINGLE_SHOT_MODE #include "espressif/esp_common.h" #include "esp/uart.h" @@ -33,13 +35,11 @@ static sht3x_sensor_t* sensor; // sensor device data structure -// #define SINGLE_SHOT_MODE - #ifdef SINGLE_SHOT_MODE /* - * User task that triggers measurements of sensor every 5 seconds. Due to - * power efficiency reasons, it uses the SHT3x *single_shot* and *vTaskDelay* - * to wait for measurement results. + * User task that triggers a measurement every 5 seconds. Due to + * power efficiency reasons, it uses the SHT3x *single_shot* and + * *vTaskDelay* to wait for measurement results. */ void user_task (void *pvParameters) { @@ -78,23 +78,23 @@ void user_task (void *pvParameters) { sht3x_values_t values; - // start periodic measurement mode + // start periodic measurements with 1 measurement per second sht3x_start_measurement (sensor, periodic_1mps); - // busy waiting until measurement results are available + // busy waiting until first measurement results are available while (sht3x_is_measuring (sensor) > 0) ; TickType_t last_wakeup = xTaskGetTickCount(); while (1) { - // retrieve the values and do something with them + // get the values and do something with them if (sht3x_get_results (sensor, &values)) printf("%.3f SHT3x Sensor: %.2f °C, %.2f %%\n", (double)sdk_system_get_time()*1e-3, values.temperature, values.humidity); - - // passive waiting until 2 seconds are over + + // passive waiting until 2 seconds (cycle time) are over vTaskDelayUntil(&last_wakeup, 2000 / portTICK_PERIOD_MS); } } @@ -102,10 +102,6 @@ void user_task (void *pvParameters) void user_init(void) { - // Please note: Return values are not considered in this example for - // readability reasons. All functions return boolean and set an error - // code that allows effective error handling. - // Set UART Parameter uart_set_baud(0, 115200); @@ -117,10 +113,11 @@ void user_init(void) i2c_init(I2C_BUS, I2C_SCL_PIN, I2C_SDA_PIN, I2C_FREQ_100K); // Create sensors - sensor = sht3x_init_sensor (I2C_BUS, SHT3x_ADDR_2); - - // Create a user task that uses the sensor - xTaskCreate(user_task, "user_task", 256, NULL, 2, 0); - + if ((sensor = sht3x_init_sensor (I2C_BUS, SHT3x_ADDR_2))) + { + // Create a user task that uses the sensor + xTaskCreate(user_task, "user_task", 256, NULL, 2, 0); + } + // That's it. } From 612dd391c1c14e401f42c6abf974427b8c7eb4c2 Mon Sep 17 00:00:00 2001 From: Gunar Schorcht Date: Fri, 13 Oct 2017 13:39:40 +0200 Subject: [PATCH 05/14] SHT3x driver - small changes - crc8 lookup table is now static to be held in flash memory - special handling for the timer overflow in sht3x_is_measuring removed - initialization reduced to availability check --- extras/sht3x/sht3x.c | 34 +++++----------------------------- 1 file changed, 5 insertions(+), 29 deletions(-) diff --git a/extras/sht3x/sht3x.c b/extras/sht3x/sht3x.c index 465ae32..9122de3 100644 --- a/extras/sht3x/sht3x.c +++ b/extras/sht3x/sht3x.c @@ -86,6 +86,7 @@ int32_t SHT3x_MEASURE_DURATION[3] = {30,20,20}; // [High, Medium, Low] static bool sht3x_send_command (sht3x_sensor_t*, uint16_t); static bool sht3x_read_data (sht3x_sensor_t*, uint8_t*, uint32_t); static bool sht3x_get_status (sht3x_sensor_t*, uint16_t*); +// static bool sht3x_reset (sht3x_sensor_t*); static uint8_t crc8 (uint8_t data[], int len); @@ -116,27 +117,10 @@ sht3x_sensor_t* sht3x_init_sensor(uint8_t bus, uint8_t addr) uint16_t status; - // soft-reset including status check leads to i2c problems. - // if (!sht3x_reset (dev)) - if (!sht3x_get_status (dev, & status)) - { - error_dev ("could not reset or check the status of the sensor", __FUNCTION__, dev); - free(dev); - return NULL; - } - - // clear sensor status register - if (!sht3x_send_command(dev, SHT3x_CLEAR_STATUS_CMD)) - { - error_dev ("could not clear sensor status", __FUNCTION__, dev); - free(dev); - return NULL; - } - // check the again the status after clear status command if (!sht3x_get_status(dev, &status)) { - error_dev ("could not get sensor status", __FUNCTION__, dev); + error_dev ("could not get sensor status", __FUNCTION__, dev); free(dev); return NULL; } @@ -195,16 +179,9 @@ int32_t sht3x_is_measuring (sht3x_sensor_t* dev) if (!dev->meas_first) return 0; - uint32_t start_time = dev->meas_start_time ; // in us - uint32_t system_time = sdk_system_get_time(); // in us - uint32_t elapsed_time; + uint32_t elapsed_time; - if (system_time < start_time) - // in case of timer overflow - elapsed_time = (UINT32_MAX - start_time + system_time) / 1000; // in ms - else - // normal case - elapsed_time = (system_time - start_time) / 1000; // in ms + elapsed_time = (sdk_system_get_time() - dev->meas_start_time) / 1000; // in ms if (elapsed_time >= SHT3x_MEASURE_DURATION[dev->repeatability]) return 0; @@ -395,7 +372,7 @@ static bool sht3x_get_status (sht3x_sensor_t* dev, uint16_t* status) -static uint8_t* crc8_table; // lookup table with precomputed crc values +static uint8_t crc8_table[256]; // lookup table with precomputed crc values static bool crc8_first_time = true; // indicator whether table has still to be created static void generate_crc8_table() @@ -422,7 +399,6 @@ static uint8_t crc8 (uint8_t data[], int len) if (crc8_first_time) { crc8_first_time = false; - crc8_table = malloc(256); generate_crc8_table (); } From 6d7c25ef7885073a343bc205394c010245645d3a Mon Sep 17 00:00:00 2001 From: Gunar Schorcht Date: Fri, 13 Oct 2017 13:39:40 +0200 Subject: [PATCH 06/14] SHT3x driver - some small changes - crc8 lookup table is now static to be held in flash memory - special handling for the timer overflow in sht3x_is_measuring removed - some whitespace removed - initialization reduced to availability check --- extras/sht3x/sht3x.c | 34 +++++----------------------------- 1 file changed, 5 insertions(+), 29 deletions(-) diff --git a/extras/sht3x/sht3x.c b/extras/sht3x/sht3x.c index 465ae32..9122de3 100644 --- a/extras/sht3x/sht3x.c +++ b/extras/sht3x/sht3x.c @@ -86,6 +86,7 @@ int32_t SHT3x_MEASURE_DURATION[3] = {30,20,20}; // [High, Medium, Low] static bool sht3x_send_command (sht3x_sensor_t*, uint16_t); static bool sht3x_read_data (sht3x_sensor_t*, uint8_t*, uint32_t); static bool sht3x_get_status (sht3x_sensor_t*, uint16_t*); +// static bool sht3x_reset (sht3x_sensor_t*); static uint8_t crc8 (uint8_t data[], int len); @@ -116,27 +117,10 @@ sht3x_sensor_t* sht3x_init_sensor(uint8_t bus, uint8_t addr) uint16_t status; - // soft-reset including status check leads to i2c problems. - // if (!sht3x_reset (dev)) - if (!sht3x_get_status (dev, & status)) - { - error_dev ("could not reset or check the status of the sensor", __FUNCTION__, dev); - free(dev); - return NULL; - } - - // clear sensor status register - if (!sht3x_send_command(dev, SHT3x_CLEAR_STATUS_CMD)) - { - error_dev ("could not clear sensor status", __FUNCTION__, dev); - free(dev); - return NULL; - } - // check the again the status after clear status command if (!sht3x_get_status(dev, &status)) { - error_dev ("could not get sensor status", __FUNCTION__, dev); + error_dev ("could not get sensor status", __FUNCTION__, dev); free(dev); return NULL; } @@ -195,16 +179,9 @@ int32_t sht3x_is_measuring (sht3x_sensor_t* dev) if (!dev->meas_first) return 0; - uint32_t start_time = dev->meas_start_time ; // in us - uint32_t system_time = sdk_system_get_time(); // in us - uint32_t elapsed_time; + uint32_t elapsed_time; - if (system_time < start_time) - // in case of timer overflow - elapsed_time = (UINT32_MAX - start_time + system_time) / 1000; // in ms - else - // normal case - elapsed_time = (system_time - start_time) / 1000; // in ms + elapsed_time = (sdk_system_get_time() - dev->meas_start_time) / 1000; // in ms if (elapsed_time >= SHT3x_MEASURE_DURATION[dev->repeatability]) return 0; @@ -395,7 +372,7 @@ static bool sht3x_get_status (sht3x_sensor_t* dev, uint16_t* status) -static uint8_t* crc8_table; // lookup table with precomputed crc values +static uint8_t crc8_table[256]; // lookup table with precomputed crc values static bool crc8_first_time = true; // indicator whether table has still to be created static void generate_crc8_table() @@ -422,7 +399,6 @@ static uint8_t crc8 (uint8_t data[], int len) if (crc8_first_time) { crc8_first_time = false; - crc8_table = malloc(256); generate_crc8_table (); } From 1525f61fe34f542aeb076a009ac86c779b5df51c Mon Sep 17 00:00:00 2001 From: Gunar Schorcht Date: Fri, 13 Oct 2017 17:43:43 +0200 Subject: [PATCH 07/14] SHT3x driver - some minor changes - lookup tables made const to be held in flash - crc8 computation changed to a non table lookup version - measurement duration is now given in ticks and can be used directly for vTaskDelay (documentation and examples changed accordingly) --- .../sht3x/sht3x_one_sensor/sht3x_one_sensor.c | 4 +- .../sht3x_two_sensors/sht3x_two_sensors.c | 4 +- extras/sht3x/README.md | 13 ++-- extras/sht3x/sht3x.c | 62 ++++++------------- extras/sht3x/sht3x.h | 45 +++++++------- 5 files changed, 55 insertions(+), 73 deletions(-) diff --git a/examples/sht3x/sht3x_one_sensor/sht3x_one_sensor.c b/examples/sht3x/sht3x_one_sensor/sht3x_one_sensor.c index 17fe6ba..7bbb4d1 100644 --- a/examples/sht3x/sht3x_one_sensor/sht3x_one_sensor.c +++ b/examples/sht3x/sht3x_one_sensor/sht3x_one_sensor.c @@ -17,7 +17,7 @@ * +------------------------+ +----------+ */ -// #define SINGLE_SHOT_MODE +#define SINGLE_SHOT_MODE #include "espressif/esp_common.h" #include "esp/uart.h" @@ -55,7 +55,7 @@ void user_task (void *pvParameters) // passive waiting until measurement results are available if (duration > 0) - vTaskDelay (duration/portTICK_PERIOD_MS); + vTaskDelay (duration); // retrieve the values and do something with them if (sht3x_get_results (sensor, &values)) diff --git a/examples/sht3x/sht3x_two_sensors/sht3x_two_sensors.c b/examples/sht3x/sht3x_two_sensors/sht3x_two_sensors.c index ee40cce..e149d92 100644 --- a/examples/sht3x/sht3x_two_sensors/sht3x_two_sensors.c +++ b/examples/sht3x/sht3x_two_sensors/sht3x_two_sensors.c @@ -18,7 +18,7 @@ * | GPIO 12 (SDA) ------- SDA | * +------------------------+ +----------+ */ - + #include "espressif/esp_common.h" #include "esp/uart.h" @@ -61,7 +61,7 @@ void user_task_sensor1 (void *pvParameters) // passive waiting until measurement results are available if (duration > 0) - vTaskDelay (duration/portTICK_PERIOD_MS); + vTaskDelay (duration); // retrieve the values and do something with them if (sht3x_get_results (sensor1, &values)) diff --git a/extras/sht3x/README.md b/extras/sht3x/README.md index 172de81..bd3d154 100644 --- a/extras/sht3x/README.md +++ b/extras/sht3x/README.md @@ -119,7 +119,7 @@ void user_task (void *pvParameters) // passive waiting until first measurement results are available if (duration > 0) - vTaskDelay (duration/portTICK_PERIOD_MS); + vTaskDelay (duration); // busy waiting until first measurement results are available // while (sht3x_is_measuring (sensor) > 0) ; @@ -140,7 +140,7 @@ void user_task (void *pvParameters) } ``` -At the beginning of the task, the periodic measurement is started by function **_sht3x_start_measurement_** with a rate of 1 measurement per second. Using the measurement duration returned from this function, the task is delayed using **_vTaskDelay_** to wait for first measurement results. The busy waiting alternative using function **_sht3x_is_measuring_** is shown in comments. Inside the task loop, the measurement results are fetched periodically using function **_sht3x_get_results_** with a rate of once per second. +At the beginning of the task, the periodic measurement is started by function **_sht3x_start_measurement_** with a rate of 1 measurement per second. Using the measurement duration in RTOS ticks returned from this function, the task is delayed using **_vTaskDelay_** to wait for first measurement results. The busy waiting alternative using function **_sht3x_is_measuring_** is shown in comments. Inside the task loop, the measurement results are fetched periodically using function **_sht3x_get_results_** with a rate of once per second. In the **single shot mode**, the measurement has to be triggered in each cycle. Waiting for measurement results is also required in each cylce, before the results can be fetched. @@ -162,7 +162,7 @@ void user_task (void *pvParameters) // passive waiting until measurement results are available if (duration > 0) - vTaskDelay (duration/portTICK_PERIOD_MS); + vTaskDelay (duration); // busy waiting until first measurement results are available // while (sht3x_is_measuring (sensor) > 0) ; @@ -233,7 +233,7 @@ static sht3x_sensor_t* sensor; // sensor device data structure /* * User task that fetches latest measurement results of sensor every 2 * seconds. It starts the SHT3x in periodic mode with 1 measurements per - * second (*periodic_1mps*). It uses busy waiting for first measurement + * second (*periodic_1mps*). It uses passive waiting for first measurement * results. */ void user_task (void *pvParameters) @@ -242,9 +242,10 @@ void user_task (void *pvParameters) // start periodic measurements with 1 measurement per second sht3x_start_measurement (sensor, periodic_1mps); - + + // passive waiting until measurement results are available if (duration > 0) - vTaskDelay (duration/portTICK_PERIOD_MS); + vTaskDelay (duration); TickType_t last_wakeup = xTaskGetTickCount(); diff --git a/extras/sht3x/sht3x.c b/extras/sht3x/sht3x.c index 9122de3..169c35f 100644 --- a/extras/sht3x/sht3x.c +++ b/extras/sht3x/sht3x.c @@ -61,14 +61,14 @@ #define SHT3x_FETCH_DATA_CMD 0xE000 #define SHT3x_HEATER_OFF_CMD 0x3066 -uint16_t SHT3x_MEASURE_CMD[6][3] = { {0x2c06,0x2c0d,0x2c10}, // [SINGLE_SHOT][H,M,L] - {0x2032,0x2024,0x202f}, // [PERIODIC_05][H,M,L] - {0x2130,0x2126,0x212d}, // [PERIODIC_05][H,M,L] - {0x2236,0x2220,0x222b}, // [PERIODIC_05][H,M,L] - {0x2234,0x2322,0x2329}, // [PERIODIC_05][H,M,L] - {0x2737,0x2721,0x272a} }; // [PERIODIC_05][H,M,L] +const uint16_t SHT3x_MEASURE_CMD[6][3] = { {0x2c06,0x2c0d,0x2c10}, // [SINGLE_SHOT][H,M,L] + {0x2032,0x2024,0x202f}, // [PERIODIC_05][H,M,L] + {0x2130,0x2126,0x212d}, // [PERIODIC_05][H,M,L] + {0x2236,0x2220,0x222b}, // [PERIODIC_05][H,M,L] + {0x2234,0x2322,0x2329}, // [PERIODIC_05][H,M,L] + {0x2737,0x2721,0x272a} }; // [PERIODIC_05][H,M,L] -int32_t SHT3x_MEASURE_DURATION[3] = {30,20,20}; // [High, Medium, Low] +const int32_t SHT3x_MEASURE_DURATION[3] = {3,2,2}; // tick counts [High, Medium, Low] #ifdef SHT3x_DEBUG #define debug(s, f, ...) printf("%s %s: " s "\n", "SHT3x", f, ## __VA_ARGS__) @@ -111,7 +111,7 @@ sht3x_sensor_t* sht3x_init_sensor(uint8_t bus, uint8_t addr) dev->mode = single_shot; dev->repeatability = high; dev->meas_started = false; - dev->meas_start_time = 0; + dev->meas_start_tick = 0; dev->active = true; @@ -149,10 +149,10 @@ int32_t sht3x_start_measurement (sht3x_sensor_t* dev, sht3x_mode_t mode) // start measurement according to selected mode and return an duration estimate if (sht3x_send_command(dev, SHT3x_MEASURE_CMD[dev->mode][dev->repeatability])) { - dev->meas_start_time = sdk_system_get_time (); + dev->meas_start_tick = xTaskGetTickCount (); dev->meas_started = true; dev->meas_first = true; - return SHT3x_MEASURE_DURATION[dev->repeatability]; // in ms + return SHT3x_MEASURE_DURATION[dev->repeatability]; // in RTOS ticks } dev->error_code |= SHT3x_SEND_MEAS_CMD_FAILED; @@ -181,7 +181,7 @@ int32_t sht3x_is_measuring (sht3x_sensor_t* dev) uint32_t elapsed_time; - elapsed_time = (sdk_system_get_time() - dev->meas_start_time) / 1000; // in ms + elapsed_time = (xTaskGetTickCount() - dev->meas_start_tick); // in RTOS ticks if (elapsed_time >= SHT3x_MEASURE_DURATION[dev->repeatability]) return 0; @@ -371,46 +371,24 @@ static bool sht3x_get_status (sht3x_sensor_t* dev, uint16_t* status) } - -static uint8_t crc8_table[256]; // lookup table with precomputed crc values -static bool crc8_first_time = true; // indicator whether table has still to be created - -static void generate_crc8_table() -{ - const uint8_t g_polynom = 0x31; - - for (int i=0; i < 256; i++) - { - uint8_t value = (uint8_t)i; - for (uint8_t bit = 0; bit < 8; bit++) - { - bool xor = value & 0x80; - value = value << 1; - value = xor ? value ^ g_polynom : value; - } - crc8_table[i] = value; - } -} - +const uint8_t g_polynom = 0x31; static uint8_t crc8 (uint8_t data[], int len) { - // generate crc lookup table first time it is called - if (crc8_first_time) - { - crc8_first_time = false; - generate_crc8_table (); - } - // initialization value uint8_t crc = 0xff; // iterate over all bytes for (int i=0; i < len; i++) { - uint8_t b = data[i]; - uint8_t data = (uint8_t)(b ^ crc); - crc = (uint8_t)(crc8_table[data]); + crc ^= data[i]; + + for (int i = 0; i < 8; i++) + { + bool xor = crc & 0x80; + crc = crc << 1; + crc = xor ? crc ^ g_polynom : crc; + } } return crc; diff --git a/extras/sht3x/sht3x.h b/extras/sht3x/sht3x.h index 8a6e94e..6fa622a 100644 --- a/extras/sht3x/sht3x.h +++ b/extras/sht3x/sht3x.h @@ -137,7 +137,7 @@ typedef struct { sht3x_repeat_t repeatability; // used repeatability bool meas_started; // indicates whether measurement started - uint32_t meas_start_time; // measurement start time in microseconds + TickType_t meas_start_tick; // measurement start time in RTOS ticks bool meas_first; // first measurement in periodic mode } sht3x_sensor_t; @@ -161,28 +161,31 @@ sht3x_sensor_t* sht3x_init_sensor (uint8_t bus, uint8_t addr); * @brief Start single shot or periodic measurements * * The function starts the measurement either in *single shot mode* - * (exactly one measurement) or *periodic mode* (periodic measurements). + * (exactly one measurement) or *periodic mode* (periodic measurements) and + * returns an estimated measurement duration given in RTOS ticks. * * In the *single shot mode*, this function has to be called for each * measurement. The measurement duration returned by the function has to be * waited every time before the results can be fetched. * - * In the *periodic mode*, this function has to be called only once. Also the - * measurement duration must be waited only once until the first results are - * available. After this first measurement, the sensor then automatically - * performs all subsequent measurements. The rate of periodic measurements can - * be 10, 4, 2, 1 or 0.5 measurements per second (mps). The user task can - * fetch the results with the half or less rate. The rate of the periodic - * measurements is defined by the parameter *mode*. + * In the *periodic mode*, this function has to be called only once. Also + * the measurement duration must be waited only once until the first + * results are available. After this first measurement, the sensor then + * automatically performs all subsequent measurements. The rate of periodic + * measurements can be 10, 4, 2, 1 or 0.5 measurements per second (mps). Due + * to inaccuracies in timing of the sensor, the user task should fetch the + * results at a lower rate. The rate of the periodic measurements is defined + * by the parameter *mode*. * - * On success, the function returns an estimated measurement duration. This - * defines the duration needed by the sensor before first results become - * available. The user task has to wait this time before it can fetch the - * results using function *sht3x_get_results* or *sht3x_get_raw_data*. + * On success, the function returns an estimated measurement duration given + * in RTOS ticks. This defines the duration needed by the sensor before + * first results become available. The user task has to wait this time + * before it can fetch the results using function *sht3x_get_results* or + * *sht3x_get_raw_data*. * - * @param dev pointer to sensor device data structure - * @param mode measurement mode, see type *sht3x_mode_t* - * @return true on success, false on error + * @param dev pointer to sensor device data structure + * @param mode measurement mode, see type *sht3x_mode_t* + * @return measurement duration in RTOS ticks or -1 on error */ int32_t sht3x_start_measurement (sht3x_sensor_t* dev, sht3x_mode_t mode); @@ -190,9 +193,9 @@ int32_t sht3x_start_measurement (sht3x_sensor_t* dev, sht3x_mode_t mode); /** * @brief Check whether measurement is still running * - * The function can be used to test whether a measurement has been started - * at all and how long it still takes before measurement results become - * available. The return value can be + * The function can be used to test whether a measurement has been + * started and how long it still takes before measurement results + * become available. The return value is given in RTOS ticks and can be * * >0 in case the measurement is is still running, * 0 in case the measurement has been already finished, or @@ -201,8 +204,8 @@ int32_t sht3x_start_measurement (sht3x_sensor_t* dev, sht3x_mode_t mode); * That is, a return value greater than 0 indicates that the measurement * results are still not available and the user task has to wait that time. * - * @param dev pointer to sensor device data structure - * @return remaining measurement duration or -1 on error + * @param dev pointer to sensor device data structure + * @return remaining measurement duration in RTOS ticks or -1 on error */ int32_t sht3x_is_measuring (sht3x_sensor_t* dev); From 344c8759f9d4f7c489d0c95d626d802ae8cabcd1 Mon Sep 17 00:00:00 2001 From: Gunar Schorcht Date: Fri, 13 Oct 2017 17:56:49 +0200 Subject: [PATCH 08/14] SHT3x driver - documentation changed --- extras/sht3x/sht3x.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extras/sht3x/sht3x.h b/extras/sht3x/sht3x.h index 6fa622a..f422d54 100644 --- a/extras/sht3x/sht3x.h +++ b/extras/sht3x/sht3x.h @@ -185,7 +185,7 @@ sht3x_sensor_t* sht3x_init_sensor (uint8_t bus, uint8_t addr); * * @param dev pointer to sensor device data structure * @param mode measurement mode, see type *sht3x_mode_t* - * @return measurement duration in RTOS ticks or -1 on error + * @return measurement duration given in RTOS ticks or -1 on error */ int32_t sht3x_start_measurement (sht3x_sensor_t* dev, sht3x_mode_t mode); From e8abd2db87f35823e8146aad5049d49636274552 Mon Sep 17 00:00:00 2001 From: Gunar Schorcht Date: Sat, 14 Oct 2017 18:30:12 +0200 Subject: [PATCH 09/14] SHT3x driver - minor correction - number of ticks for measurement duration takes now into account portTICK_PERIOD_MS --- extras/sht3x/sht3x.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/extras/sht3x/sht3x.c b/extras/sht3x/sht3x.c index 169c35f..f54ac78 100644 --- a/extras/sht3x/sht3x.c +++ b/extras/sht3x/sht3x.c @@ -67,8 +67,14 @@ const uint16_t SHT3x_MEASURE_CMD[6][3] = { {0x2c06,0x2c0d,0x2c10}, // [SINGLE {0x2236,0x2220,0x222b}, // [PERIODIC_05][H,M,L] {0x2234,0x2322,0x2329}, // [PERIODIC_05][H,M,L] {0x2737,0x2721,0x272a} }; // [PERIODIC_05][H,M,L] - -const int32_t SHT3x_MEASURE_DURATION[3] = {3,2,2}; // tick counts [High, Medium, Low] + +#define max(a,b) (a) > (b) ? a : b + +// tick counts [High, Medium, Low] +// minimum is one tick if portTICK_PERIOD_MS is greater than 20 or 30 ms +const int32_t SHT3x_MEASURE_DURATION[3] = { max(30/portTICK_PERIOD_MS,1), + max(20/portTICK_PERIOD_MS,1), + max(20/portTICK_PERIOD_MS,1) }; #ifdef SHT3x_DEBUG #define debug(s, f, ...) printf("%s %s: " s "\n", "SHT3x", f, ## __VA_ARGS__) @@ -100,6 +106,8 @@ bool sht3x_init_driver() sht3x_sensor_t* sht3x_init_sensor(uint8_t bus, uint8_t addr) { + printf("%d %d %d\n", SHT3x_MEASURE_DURATION[0], SHT3x_MEASURE_DURATION[1], SHT3x_MEASURE_DURATION[2]); + sht3x_sensor_t* dev; if ((dev = malloc (sizeof(sht3x_sensor_t))) == NULL) From 994d667a8cafd132af1a1b23088d101a0c593c57 Mon Sep 17 00:00:00 2001 From: Gunar Schorcht Date: Sat, 14 Oct 2017 18:35:51 +0200 Subject: [PATCH 10/14] SHT3x driver - minor correction - number of ticks for measurement duration takes now into account portTICK_PERIOD_MS --- extras/sht3x/sht3x.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/extras/sht3x/sht3x.c b/extras/sht3x/sht3x.c index f54ac78..632543f 100644 --- a/extras/sht3x/sht3x.c +++ b/extras/sht3x/sht3x.c @@ -106,8 +106,6 @@ bool sht3x_init_driver() sht3x_sensor_t* sht3x_init_sensor(uint8_t bus, uint8_t addr) { - printf("%d %d %d\n", SHT3x_MEASURE_DURATION[0], SHT3x_MEASURE_DURATION[1], SHT3x_MEASURE_DURATION[2]); - sht3x_sensor_t* dev; if ((dev = malloc (sizeof(sht3x_sensor_t))) == NULL) From 3649ab627040732ad7282bb9d8b5e4f924288f45 Mon Sep 17 00:00:00 2001 From: Gunar Schorcht Date: Sun, 15 Oct 2017 11:13:16 +0200 Subject: [PATCH 11/14] SHT3x driver - minor correction - number of ticks for measurement duration takes now into account portTICK_PERIOD_MS --- extras/sht3x/sht3x.c | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/extras/sht3x/sht3x.c b/extras/sht3x/sht3x.c index 632543f..76b6947 100644 --- a/extras/sht3x/sht3x.c +++ b/extras/sht3x/sht3x.c @@ -63,18 +63,16 @@ const uint16_t SHT3x_MEASURE_CMD[6][3] = { {0x2c06,0x2c0d,0x2c10}, // [SINGLE_SHOT][H,M,L] {0x2032,0x2024,0x202f}, // [PERIODIC_05][H,M,L] - {0x2130,0x2126,0x212d}, // [PERIODIC_05][H,M,L] - {0x2236,0x2220,0x222b}, // [PERIODIC_05][H,M,L] - {0x2234,0x2322,0x2329}, // [PERIODIC_05][H,M,L] - {0x2737,0x2721,0x272a} }; // [PERIODIC_05][H,M,L] - -#define max(a,b) (a) > (b) ? a : b + {0x2130,0x2126,0x212d}, // [PERIODIC_1 ][H,M,L] + {0x2236,0x2220,0x222b}, // [PERIODIC_2 ][H,M,L] + {0x2234,0x2322,0x2329}, // [PERIODIC_4 ][H,M,L] + {0x2737,0x2721,0x272a} }; // [PERIODIC_10][H,M,L] // tick counts [High, Medium, Low] // minimum is one tick if portTICK_PERIOD_MS is greater than 20 or 30 ms -const int32_t SHT3x_MEASURE_DURATION[3] = { max(30/portTICK_PERIOD_MS,1), - max(20/portTICK_PERIOD_MS,1), - max(20/portTICK_PERIOD_MS,1) }; +const int32_t SHT3x_MEASURE_DURATION[3] = { (30 + portTICK_PERIOD_MS-1)/portTICK_PERIOD_MS, + (20 + portTICK_PERIOD_MS-1)/portTICK_PERIOD_MS, + (20 + portTICK_PERIOD_MS-1)/portTICK_PERIOD_MS }; #ifdef SHT3x_DEBUG #define debug(s, f, ...) printf("%s %s: " s "\n", "SHT3x", f, ## __VA_ARGS__) @@ -107,7 +105,7 @@ bool sht3x_init_driver() sht3x_sensor_t* sht3x_init_sensor(uint8_t bus, uint8_t addr) { sht3x_sensor_t* dev; - + if ((dev = malloc (sizeof(sht3x_sensor_t))) == NULL) return NULL; From b499987dc84c763f0755e83ac66c8d2b60d940fe Mon Sep 17 00:00:00 2001 From: Gunar Schorcht Date: Sun, 15 Oct 2017 19:33:46 +0200 Subject: [PATCH 12/14] SHT3x driver - minor correction - number of ticks for measurement duration takes now into account portTICK_PERIOD_MS --- extras/sht3x/sht3x.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/extras/sht3x/sht3x.c b/extras/sht3x/sht3x.c index 76b6947..47739f6 100644 --- a/extras/sht3x/sht3x.c +++ b/extras/sht3x/sht3x.c @@ -68,11 +68,11 @@ const uint16_t SHT3x_MEASURE_CMD[6][3] = { {0x2c06,0x2c0d,0x2c10}, // [SINGLE {0x2234,0x2322,0x2329}, // [PERIODIC_4 ][H,M,L] {0x2737,0x2721,0x272a} }; // [PERIODIC_10][H,M,L] -// tick counts [High, Medium, Low] -// minimum is one tick if portTICK_PERIOD_MS is greater than 20 or 30 ms -const int32_t SHT3x_MEASURE_DURATION[3] = { (30 + portTICK_PERIOD_MS-1)/portTICK_PERIOD_MS, - (20 + portTICK_PERIOD_MS-1)/portTICK_PERIOD_MS, - (20 + portTICK_PERIOD_MS-1)/portTICK_PERIOD_MS }; +// +#define TIME_TO_TICKS(ms) (((ms) + portTICK_PERIOD_MS + portTICK_PERIOD_MS / 2) / portTICK_PERIOD_MS) +const int32_t SHT3x_MEASURE_DURATION[3] = { TIME_TO_TICKS(15), + TIME_TO_TICKS(6), + TIME_TO_TICKS(4) }; #ifdef SHT3x_DEBUG #define debug(s, f, ...) printf("%s %s: " s "\n", "SHT3x", f, ## __VA_ARGS__) From 12ce858a50437ab9b8ff2d63c8ba1681fd663c8f Mon Sep 17 00:00:00 2001 From: Gunar Schorcht Date: Mon, 16 Oct 2017 18:11:29 +0200 Subject: [PATCH 13/14] SHT3x driver - minor corrections --- extras/sht3x/README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/extras/sht3x/README.md b/extras/sht3x/README.md index bd3d154..e12da29 100644 --- a/extras/sht3x/README.md +++ b/extras/sht3x/README.md @@ -20,7 +20,7 @@ Due to the measurement duration of up to 30 ms, the measurement process is separ 2. Wait the measurement duration until the results are available using passive waiting with function **_vTaskDelay_** or busy waiting with function **_sht3x_is_measuring_**. -3. Fetch the results as floating point sensor values with function **sht3x_get_results_** or as raw data with function **sht3x_get_raw_data_**. +3. Fetch the results as floating point sensor values with function **_sht3x_get_results_** or as raw data with function **_sht3x_get_raw_data_**. In the *single shot mode*, the user task has to perform all steps every time new sensor values ​​are needed. When using the *single image mode*, however, a delay of up to 30 ms is generated for each measurement. @@ -32,11 +32,11 @@ In this mode, one issued measurement command yields a stream of data pairs. Each As in *single shot mode*, the measurement process is separated into the following steps: -1. Trigger the sensor with function **sht3x_start_measurement_** and the rate of periodic measurements to start periodic measurements. +1. Trigger the sensor with function **_sht3x_start_measurement_** and the rate of periodic measurements to start periodic measurements. 2. Wait the measurement duration until the results are available using passive waiting with function **_vTaskDelay_** or busy waiting with function **_sht3x_is_measuring_**. -3. Fetch the results as floating point sensor values with function **sht3x_get_results_** or as raw data with function **sht3x_get_raw_data_**. +3. Fetch the results as floating point sensor values with function **_sht3x_get_results_** or as raw data with function **_sht3x_get_raw_data_**. However, in contrast to the *single shot mode*, steps 1 and 2 have to be executed only once. Once the measurement is started, the user task hast can simply fetch data periodically. @@ -181,7 +181,7 @@ void user_task (void *pvParameters) In contrast to the *periodic mode*, the function **_sht3x_start_measurement_** is called inside the task loop to start exactly one measurement in each cycle. The task is then also delayed every time using function **_vTaskDelay_** before the results are fetched with function **_sht3x_get_results_** in each cycle. -The code could be extended by an error handling. In the event of an error, most driver functions use the **_error_code_** element of the data structure of the sensor device. This indicates which error has occurred. Error codes are a combination of I2C communication error codes and SHT3x sensor error codes. To test a particular error, the *error code* can be AND with one of the error masks **_SHT3x_I2C_ERROR_MASK_** or **_SHT3x_DRV_ERROR_MASK_**. +The code could be extended by an error handling. In the event of an error, most driver functions set member **_error_code_** of the data structure of the sensor device. This indicates which error has occurred. Error codes are a combination of I2C communication error codes and SHT3x sensor error codes. To test a particular error, the *error code* can be AND with one of the error masks **_SHT3x_I2C_ERROR_MASK_** or **_SHT3x_DRV_ERROR_MASK_**. For example, error handling for **_sht3x_get_results_** could look like: ``` From d29be26d4f0663921323b17a29bce130ad211552 Mon Sep 17 00:00:00 2001 From: Gunar Schorcht Date: Thu, 19 Oct 2017 07:20:04 +0200 Subject: [PATCH 14/14] SHT3x driver - minor corrections --- examples/sht3x/README.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/examples/sht3x/README.md b/examples/sht3x/README.md index 2abe606..648ffe5 100644 --- a/examples/sht3x/README.md +++ b/examples/sht3x/README.md @@ -1,8 +1,6 @@ # SHT3x Driver Examples -These examples references two addtional drivers [i2c](https://github.com/kanflo/esp-open-rtos-driver-i2c) and [sht3x](https://github.com/gschorcht/esp-open-rtos/extras/sht3x), which are provided in the `../../extras` folder. - -If you plan to use one or both of this drivers in your own projects, please check the main development pages for updated versions or reported issues. +These examples demonstrate the usage of the SHT3x driver with only one and multiple SHT3x sensors. ## Hardware setup