Skip to content

Commit 9f794e5

Browse files
committed
interrupts
1 parent df2ef8d commit 9f794e5

File tree

6 files changed

+190
-19
lines changed

6 files changed

+190
-19
lines changed

README.md

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,22 @@
11
# arduino-esp library for Sensirion SDP3x and SDP8xx series
22

3-
This repository is tailored specifically for ESP boards and achieves **3X** faster performance.
3+
ESP-IDF & Arduino friendly implementation of communication with Sensirion differential pressure sensors.
44

5-
To read the first three bytes (two for diff pressure and one CRC), it takes only 158 us compared to
6-
450 us of a general-purpose arduino library [SDP3x-Arduino](https://github.com/DataDrake/SDP3x-Arduino).
5+
Compared to a general-purpose arduino library [SDP3x-Arduino](https://github.com/DataDrake/SDP3x-Arduino), it's:
6+
7+
1. a bit faster (158 vs 170 us) because of the optimized `i2c_master_read_from_device` and `i2c_master_write_from_device` functions. Benchmarks are measured for the 400kHz I2C clock frequency (`Wire.setClock()`).
8+
2. it has support for interrupt handlers (available for SDP3x sensors only). With interrupts, you can achieve reliable sensor updates at ~2100 Hz frequency. See the [SDP3x\_Interrupts](./examples/SDP3x_Interrupts/SDP3x_Interrupts.ino) demo.
9+
2. ESP-IDF friendly: run this code either in Arduino or in your favourite ESP-IDF framework. For pure C implementation, refer to [`sdpsensor.c`](https://github.com/dizcza/esp32-sdpsensor/blob/master/main/sdpsensor.c).
10+
3. DataDrake's implementation has a bug in the reset function. It's fixed here.
11+
4. Each function returns a descriptive error code defined in [`esp_err.h`](https://github.com/espressif/esp-idf/blob/master/components/esp_common/include/esp_err.h). To check for success, call `if (err == ESP_OK) ...`.
12+
13+
## I2C address
14+
15+
Typical I2C sensor addresses:
16+
17+
* SDP31 & SDP32: `0x21`, `0x22`, `0x23`
18+
* SDP8x0: `0x25`
19+
* SDP8x1: `0x26`
720

821
## Usage
922

@@ -26,3 +39,8 @@ Serial output:
2639

2740
If the sensor was working in a continuous mode, prior to executing any I2C commands, it ought to be reset by calling either the `stopContinuous()` or `reset()` function. Note, however, that the `reset` commands are received by *all* I2C peripherals connected to the same I2C line (port), because it employs the `0x00` address, which is the I2C general call address.
2841

42+
43+
## Capillary filter
44+
45+
To operate as a differential pressure sensor it must have a mechanical capillary filter attached to one of the ports. A low-pass frequency filter adapts to slowly changing atmospheric pressure, allowing mid- & high-frequency bands of differential pressure to be read from the other open port. Without the filter attached, the difference in pressure will be negligible.
46+

examples/SDP3x/SDP3x.ino

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,18 @@
11
/**
22
* An example to use an SDP3x sensor with an ESP32 board.
33
*
4-
* Prior setup:
4+
* Software setup:
55
* 1) install the arduino-esp library
66
* 2) select your ESP board in "Tools" -> "Board"
77
* 3) select the right port in "Tools" -> "Port"
88
* 4) turn on the logs by setting "Tools" -> "Core Debug Level" -> "Info"
9+
* Hardware setup:
10+
* 1) connect GPIO SDA to pin 19
11+
* 2) connect GPIO SCL to pin 23
12+
* or change the code appropriately.
913
*/
1014
#include "sdpsensor.h"
15+
#include <Wire.h>
1116

1217

1318
/* An SDP sensor instance.
@@ -38,7 +43,8 @@ bool initSensorSingleTrial() {
3843
void setup() {
3944
Serial.begin(115200);
4045
delay(1000); // let serial console settle
41-
sdp.initI2C(19, 23); // same as Wire.begin(SDA, SCL)
46+
Wire.begin(19, 23); // sdp.initI2C() is also possible
47+
Wire.setClock(400000); // (optionally) set I2C frequency to high
4248

4349
// choose how you want to initialize the sensor
4450
bool success = initSensorSingleTrial();
@@ -60,11 +66,17 @@ void setup() {
6066

6167

6268
void loop() {
69+
char message[256];
6370
delay(1000);
6471
int16_t pressure;
6572
esp_err_t err = sdp.readDiffPressure(&pressure);
6673
if (err == ESP_OK) {
6774
// success; process the 'pressure' here
75+
float pressurePa = (float) pressure / sdp.getPressureScale();
76+
sprintf(message, "Pressure %d / %d = %.5f Pa", pressure, sdp.getPressureScale(), pressurePa);
77+
Serial.println(message);
78+
} else {
79+
Serial.print("FAILED: ");
80+
Serial.println(esp_err_to_name(err));
6881
}
69-
ESP_LOGI("main", "raw pressure: %d, err code: %s", pressure, esp_err_to_name(err));
7082
}
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
/**
2+
* An example to use SDP3x sensor interrupts.
3+
*
4+
* Software setup:
5+
* 1) install the arduino-esp library
6+
* 2) select your ESP board in "Tools" -> "Board"
7+
* 3) select the right port in "Tools" -> "Port"
8+
* 4) turn on the logs by setting "Tools" -> "Core Debug Level" -> "Info"
9+
* Hardware setup:
10+
* 1) connect GPIO SDA to pin 19
11+
* 2) connect GPIO SCL to pin 23
12+
* 3) connect GPIO IRQ to pin 4 (!)
13+
* or change the code appropriately.
14+
*/
15+
16+
#include <Wire.h>
17+
18+
#include "freertos/FreeRTOS.h"
19+
#include "freertos/task.h"
20+
21+
#include "sdpsensor.h"
22+
23+
#define GPIO_IRQ_PIN 4 // SDP3x IRQ pin connected to your board
24+
25+
static TaskHandle_t read_sensor_task_handle;
26+
27+
SDPSensor sdp(0x21);
28+
29+
30+
static void IRAM_ATTR sdpsensor_irq_handler() {
31+
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
32+
vTaskNotifyGiveFromISR(read_sensor_task_handle, &xHigherPriorityTaskWoken);
33+
34+
/* If xHigherPriorityTaskWoken is now set to pdTRUE then a context switch
35+
should be performed to ensure the interrupt returns directly to the highest
36+
priority task. The macro used for this purpose is dependent on the port in
37+
use and may be called portEND_SWITCHING_ISR(). */
38+
portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
39+
}
40+
41+
42+
static void sdptask_read_sensor() {
43+
esp_err_t err;
44+
int16_t diff_pressure;
45+
46+
while (1) {
47+
// wait for an interrupt
48+
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
49+
50+
err = sdp.readDiffPressure(&diff_pressure);
51+
52+
if (err == ESP_OK) {
53+
// send to a receiver here
54+
}
55+
56+
// Note that you should never print here any messages because
57+
// printing to serial is VERY slow. It's done for demonstration
58+
// purposes here.
59+
Serial.print("Raw diff pressure: ");
60+
Serial.println(diff_pressure);
61+
}
62+
}
63+
64+
65+
void setup() {
66+
Serial.begin(115200);
67+
delay(1000); // let serial console settle
68+
Wire.begin(19, 23);
69+
70+
// you should be already familiar with this
71+
while (sdp.stopContinuous() != ESP_OK);
72+
while (sdp.begin() != ESP_OK);
73+
while (sdp.startContinuous() != ESP_OK);
74+
75+
uint32_t modelNumber;
76+
sdp.getInfo(&modelNumber, NULL, NULL, NULL);
77+
if (!(modelNumber == 31 || modelNumber == 32)) {
78+
Serial.println("WARNING! Your SDP sensor does NOT support interrupts!");
79+
}
80+
81+
if (sdp.attachIRQHandler(GPIO_IRQ_PIN, sdpsensor_irq_handler) != ESP_OK) {
82+
Serial.println("Failed to hook an interrupt handler. Check the wiring.");
83+
return;
84+
}
85+
86+
// start a task on the second core with the priority '1'
87+
xTaskCreatePinnedToCore((TaskFunction_t) sdptask_read_sensor, "sdp_read", 4096, NULL, 1, &read_sensor_task_handle, APP_CPU_NUM);
88+
89+
// allow the sensor to run the first measurement
90+
xTaskNotifyGive(read_sensor_task_handle);
91+
}
92+
93+
94+
void loop() {
95+
// sdptask_read_sensor task is running
96+
}

examples/SDP3x_Watchdog/SDP3x_Watchdog.ino

Lines changed: 21 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,18 @@
33
* with a watchdog that barks each time three errors are
44
* encountered in a row.
55
*
6-
* Prior setup:
6+
* Software setup:
77
* 1) install the arduino-esp library
88
* 2) select your ESP board in "Tools" -> "Board"
99
* 3) select the right port in "Tools" -> "Port"
1010
* 4) turn on the logs by setting "Tools" -> "Core Debug Level" -> "Info"
11+
* Hardware setup:
12+
* 1) connect GPIO SDA to pin 19
13+
* 2) connect GPIO SCL to pin 23
14+
* or change the code appropriately.
1115
*/
16+
17+
#include <Wire.h>
1218
#include "sdpsensor.h"
1319

1420

@@ -23,7 +29,7 @@ SDPSensor sdp(0x21);
2329
uint32_t failsCount = 0;
2430

2531
/* Max SDP successive failed reads before a SW reset */
26-
const uint32_t maxSuccessiveFailsCount = 3;
32+
const uint32_t maxSuccessiveFailsCount = 1;
2733

2834
/**
2935
* Check the error code status of the last read measurement.
@@ -35,31 +41,33 @@ const uint32_t maxSuccessiveFailsCount = 3;
3541
*
3642
* @param status - the error code of the last measurement
3743
*/
38-
void watchdogCheck(esp_err_t status) {
44+
bool watchdogCheck(esp_err_t status) {
3945
if (status == ESP_OK) {
4046
failsCount = 0;
4147
} else {
4248
failsCount++;
4349
}
4450

4551
if (failsCount >= maxSuccessiveFailsCount) {
46-
ESP_LOGW("watchdog", "SDPWatchdog barked. Resetting...");
52+
Serial.println("SDPWatchdog barked. Resetting...");
4753
esp_err_t err = ESP_FAIL;
4854
do {
4955
err = sdp.reset(); // sdp.stopContinuous() is a safer version
5056
if (err == ESP_OK) {
5157
err = sdp.startContinuous();
5258
}
5359
} while (err != ESP_OK);
60+
return true;
5461
}
5562

63+
return false;
5664
}
5765

5866

5967
void setup() {
6068
Serial.begin(115200);
6169
delay(1000); // let serial console settle
62-
sdp.initI2C(19, 23); // same as Wire.begin(SDA, SCL)
70+
Wire.begin(19, 23);
6371

6472
// try until succeeds
6573
while (sdp.stopContinuous() != ESP_OK); // sdp.reset() is also possible
@@ -69,14 +77,14 @@ void setup() {
6977

7078

7179
void loop() {
72-
delay(1000);
7380
int16_t pressure;
74-
esp_err_t err = sdp.readDiffPressure(&pressure);
75-
ESP_LOGI("sdp", "raw pressure: %d, err code: %s", pressure, esp_err_to_name(err));
81+
esp_err_t err;
82+
83+
do {
84+
// read the sensor without delay until the watchdog starts barking ...
85+
err = sdp.readDiffPressure(&pressure);
86+
} while (!watchdogCheck(err));
7687

77-
/*
78-
* Optionally, check the last result code.
79-
* If enough errors occur, a software reset is issued.
80-
*/
81-
watchdogCheck(err);
88+
// wait & repeat
89+
delay(3000);
8290
}

sdpsensor.cpp

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -261,6 +261,33 @@ esp_err_t SDPSensor::reset() {
261261
}
262262

263263

264+
esp_err_t SDPSensor::attachIRQHandler(int irqGPIO, void (*irqHandler)() ) {
265+
gpio_config_t irq_io_conf = {
266+
.pin_bit_mask = 1ULL << irqGPIO, // IRQ pin
267+
.mode = GPIO_MODE_INPUT, // input mode
268+
.pull_up_en = GPIO_PULLUP_ENABLE, // enable pull-up
269+
.pull_down_en = GPIO_PULLDOWN_DISABLE, // disable pull-down
270+
.intr_type = GPIO_INTR_NEGEDGE // falling edge interrupt
271+
};
272+
esp_err_t err;
273+
err = gpio_config(&irq_io_conf);
274+
if (err != ESP_OK) {
275+
return err;
276+
}
277+
// install the GPIO ISR service
278+
err = gpio_install_isr_service(0);
279+
if (err != ESP_OK) {
280+
return err;
281+
}
282+
// hook an ISR handler for the specific GPIO pin
283+
err = gpio_isr_handler_add((gpio_num_t) irqGPIO, (gpio_isr_t) irqHandler, NULL);
284+
if (err == ESP_OK) {
285+
ESP_LOGI(TAG_SDPSENSOR, "Attached an IRQ handler to GPIO pin %d", irqGPIO);
286+
}
287+
return err;
288+
}
289+
290+
264291
esp_err_t SDPSensor::readDiffPressure(int16_t *diffPressureRaw) {
265292
if (!initialized) return ESP_ERR_INVALID_STATE;
266293

sdpsensor.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
#ifndef SDPSENSOR_H_
99
#define SDPSENSOR_H_
1010

11+
#include "esp_err.h"
1112
#include "driver/i2c.h"
1213

1314

@@ -105,6 +106,15 @@ class SDPSensor {
105106
*/
106107
esp_err_t reset();
107108

109+
/**
110+
* Attach the IRQ handler callback to a dedicated GPIO sensor pin.
111+
* Only the SDP3x sensor series have an IRQ pin.
112+
*
113+
* @param irqGPIO - GPIO interrupt pin number
114+
* @param irqHandler - interrupt handler callback function
115+
* @returns the error code (defined in esp_err.h)
116+
*/
117+
esp_err_t attachIRQHandler(int irqGPIO, void (*irqHandler)() );
108118

109119
/**
110120
* Read the raw (unnormalized) differential pressure value and

0 commit comments

Comments
 (0)