Puts soil moisture reading into the BLE advertisement packet

This commit is contained in:
rbaron 2021-03-26 16:30:09 +01:00
parent 30162f4628
commit 6ec48b7188
6 changed files with 56 additions and 25 deletions

View file

@ -7,11 +7,12 @@
#define PRST_LED_PIN NRF_GPIO_PIN_MAP(0, 28)
// Deep sleep.
#define PRST_DEEP_SLEEP_IN_SECONDS 2
#define PRST_DEEP_SLEEP_IN_SECONDS 3
// Analog to digital converter (ADC).
// Prints out ADC debug info, such as the values read for battery and soil moisture.
#define PRST_ADC_DEBUG 1
// Prints out ADC debug info, such as the values read for battery and soil
// moisture.
#define PRST_ADC_DEBUG 0
// BLE.
#define PRST_BLE_ADV_NAME "prst"
@ -22,4 +23,7 @@
#define PRST_PWM_PIN NRF_GPIO_PIN_MAP(0, 5)
#define PRST_FAST_DISCH_PIN NRF_GPIO_PIN_MAP(1, 10)
// SHT3C temp/humidity sensor.
#define PRST_SHT3C_DEBUG 1
#endif // _PRST_CONFIG_H_

View file

@ -11343,7 +11343,7 @@
// <2=> BLOCK_IF_FIFO_FULL
#ifndef SEGGER_RTT_CONFIG_DEFAULT_MODE
#define SEGGER_RTT_CONFIG_DEFAULT_MODE 2
#define SEGGER_RTT_CONFIG_DEFAULT_MODE 0
#endif
// </h>

View file

@ -58,31 +58,22 @@ static void power_manage(void) {
// Here we need to be extra careful with what operations we do. This callback
// has to return fast-ish, otherwise we hit some hard exceptions.
static void rtc_callback() {
NRF_LOG_INFO("Batt raw ");
NRF_LOG_FLUSH();
nrf_gpio_pin_set(PRST_LED_PIN);
prst_shtc3_read_t temp_humi = prst_shtc3_read();
nrf_gpio_pin_set(PRST_FAST_DISCH_PIN);
prst_pwm_init();
prst_pwm_start();
prst_adc_batt_read_t batt_read = prst_adc_batt_read();
int16_t soil_read = prst_adc_soil_read();
prst_adc_soil_moisture_t soil_read = prst_adc_soil_read();
prst_pwm_stop();
nrf_gpio_pin_clear(PRST_FAST_DISCH_PIN);
NRF_LOG_INFO("Read soil: %d", soil_read);
prst_ble_update_adv_data(batt_read.millivolts, temp_humi.temp_millicelcius, temp_humi.humidity, 0);
prst_ble_update_adv_data(batt_read.millivolts, temp_humi.temp_millicelcius,
temp_humi.humidity, soil_read.relative);
NRF_LOG_FLUSH();
prst_adv_start();
nrf_delay_ms(200);
prst_adv_stop();
nrf_gpio_pin_clear(PRST_LED_PIN);
UNUSED_VARIABLE(batt_read);
// NRF_LOG_INFO("Read batt: " NRF_LOG_FLOAT_MARKER " V (%d), %u mV",
// NRF_LOG_FLOAT(batt_read.voltage), batt_read.raw, batt_read.millivolts);
// NRF_LOG_INFO("Read temp: " NRF_LOG_FLOAT_MARKER " oC",
// NRF_LOG_FLOAT((float) temp_humi.temp_millicelcius / 1000.0));
// NRF_LOG_INFO("Read humi: " NRF_LOG_FLOAT_MARKER " %%",
// NRF_LOG_FLOAT(100.0 * temp_humi.humidity / (1 << 16)));
NRF_LOG_FLUSH();
}
@ -94,11 +85,18 @@ int main(void) {
prst_ble_init();
prst_adc_init();
prst_shtc3_init();
// Set up RTC. It will call our custom callback at a regular interval, defined
// by PRST_DEEP_SLEEP_IN_SECONDS.
prst_rtc_set_callback(rtc_callback);
prst_rtc_init();
nrf_delay_ms(100);
// In addition to scheduling it, let's immediatelly call it - it makes
// debugging less tedious.
rtc_callback();
// Here we go into a low energy mode. The datasheet calls this mode "System
// ON", and in my tests it consumes around 2.7uA.
for (;;) {
power_manage();
}

View file

@ -27,6 +27,11 @@ static nrf_saadc_value_t sample_adc_channel(uint8_t channel) {
return result;
}
// Caps the argument to the [0, 1] range.
static inline double cap_value(double value) {
return value > 1.0 ? 1.0 : (value < 0.0 ? 0.0 : value);
}
// Unused, since we'll call the SAADC synchronously for now.
void saadc_callback(nrf_drv_saadc_evt_t const* p_event) {
if (p_event->type == NRF_DRV_SAADC_EVT_DONE) {
@ -69,16 +74,23 @@ prst_adc_batt_read_t prst_adc_batt_read() {
ret.voltage = (3.6 * result) / (1 << PRST_ADC_RESOLUTION);
ret.millivolts = ret.voltage * 1000;
#if PRST_ADC_DEBUG
NRF_LOG_INFO("[adc] Read battery voltage: %d (raw); %d mV; ", ret.raw, ret.millivolts,
ret.voltage);
NRF_LOG_INFO("[adc] Read battery voltage: %d (raw); %d mV; ", ret.raw,
ret.millivolts, ret.voltage);
#endif
return ret;
}
int16_t prst_adc_soil_read() {
prst_adc_soil_moisture_t prst_adc_soil_read() {
nrf_saadc_value_t result = sample_adc_channel(PRST_ADC_SOIL_CHANNEL);
double percentage = cap_value(((double)result - PRST_SOIL_DRY) /
(PRST_SOIL_WET - PRST_SOIL_DRY));
prst_adc_soil_moisture_t ret;
ret.raw = result;
ret.relative = percentage * (1 << 16);
#if PRST_ADC_DEBUG
NRF_LOG_INFO("[adc] Read soil moisture: %d", result);
NRF_LOG_INFO("[adc] Read soil moisture: %d (raw); " NRF_LOG_FLOAT_MARKER
" %% (percentage); %u (relative)",
ret.raw, NRF_LOG_FLOAT(percentage * 100), ret.relative);
#endif
return result;
return ret;
}

View file

@ -3,16 +3,29 @@
#include <stdint.h>
// ADC values. Assumes 10 bits resolution.
// TODO(rbaron) this values drift a little bit as the battery discharges.
// I previously did a hacky linear regression to estimate them, but I'm
// not super sure how useful that is.
#define PRST_SOIL_WET 200
#define PRST_SOIL_DRY 500
typedef struct prst_adc_batt_val {
int16_t raw;
uint16_t millivolts;
double voltage;
} prst_adc_batt_read_t;
typedef struct prst_adc_soil_moisture {
int16_t raw;
// A value from 0 (cmopletely dry) to 2^10 (completely wet).
uint16_t relative;
} prst_adc_soil_moisture_t;
void prst_adc_init();
prst_adc_batt_read_t prst_adc_batt_read();
int16_t prst_adc_soil_read();
prst_adc_soil_moisture_t prst_adc_soil_read();
#endif // _PRST_ADC_H_

View file

@ -47,12 +47,16 @@ prst_shtc3_read_t prst_shtc3_read() {
// TODO(rbaron): verify the CRC of the measurements. The function is described
// in the datasheet.
NRF_LOG_INFO("Computing...");
double temp_c = -45 + 175 * ((double)((buff[0] << 8) | buff[1])) / (1 << 16);
// double humi = ((double)((buff[3] << 8) | buff[4])) / ((1 << 16) - 1);
uint16_t humi = (buff[3] << 8) | buff[4];
prst_shtc3_read_t ret = {.temp_millicelcius = temp_c * 1000,
.humidity = humi};
#if PRST_SHT3C_DEBUG
NRF_LOG_INFO("[sht3c] Read temp: " NRF_LOG_FLOAT_MARKER " oC",
NRF_LOG_FLOAT((float)temp_humi.temp_millicelcius / 1000.0));
NRF_LOG_INFO("[sht3c] Read humi: " NRF_LOG_FLOAT_MARKER " %%",
NRF_LOG_FLOAT(100.0 * temp_humi.humidity / (1 << 16)));
#endif
return ret;
}