diff options
author | Florian Baumann <derflob@derflob.de> | 2020-04-26 23:27:49 +0200 |
---|---|---|
committer | Florian Baumann <derflob@derflob.de> | 2020-04-26 23:27:49 +0200 |
commit | 67561973c70ca5986db4af5c39baca5b4811d8ba (patch) | |
tree | 4ea729de225b76e639960ace09b0da138eb19d68 | |
download | ULPSoilMonitor-67561973c70ca5986db4af5c39baca5b4811d8ba.tar.gz ULPSoilMonitor-67561973c70ca5986db4af5c39baca5b4811d8ba.tar.bz2 |
ulp measures adc1 periodically and wakes esp32 on threshold
-rw-r--r-- | ULPSoilMonitor.ino | 93 | ||||
-rw-r--r-- | ulp_soil.h | 10 | ||||
-rw-r--r-- | ulp_soil.s | 382 |
3 files changed, 485 insertions, 0 deletions
diff --git a/ULPSoilMonitor.ino b/ULPSoilMonitor.ino new file mode 100644 index 0000000..d8ebfc7 --- /dev/null +++ b/ULPSoilMonitor.ino @@ -0,0 +1,93 @@ +/* + * Must allocate more memory for the ulp in + * esp32/tools/sdk/include/sdkconfig.h + * -> #define CONFIG_ULP_COPROC_RESERVE_MEM + * for this sketch to compile. 2048b seems + * good. + */ +#include "esp_sleep.h" +#include "driver/rtc_io.h" +#include "driver/adc.h" +#include "esp32/ulp.h" +#include "ulp_soil.h" +#include "ulptool.h" + +extern const uint8_t ulp_main_bin_start[] asm("_binary_ulp_main_bin_start"); +extern const uint8_t ulp_main_bin_end[] asm("_binary_ulp_main_bin_end"); + +/* This function is called once after power-on reset, to load ULP program into + RTC memory and configure the ADC. +*/ +static void init_ulp_program(); + +/* This function is called every time before going into deep sleep. + It starts the ULP program and resets measurement counter. +*/ +static void start_ulp_program(); + +void setup() { + Serial.begin(115200); + delay(100); + esp_sleep_wakeup_cause_t cause = esp_sleep_get_wakeup_cause(); + if (cause != ESP_SLEEP_WAKEUP_ULP) { + Serial.printf("Not ULP wakeup\n"); + init_ulp_program(); + } else { + Serial.printf("Deep sleep wakeup\n"); + /* Count temperature form -5 ℃ , so ulp_temperature minus 5 */ + Serial.printf("max_diff:%d\n", (uint16_t)ulp_max_diff); + Serial.printf("Soil0:%d\n", (uint16_t)ulp_soil0); + Serial.printf("Soil1:%d\n", (uint16_t)ulp_soil1); + Serial.printf("Soil2:%d\n", (uint16_t)ulp_soil2); + Serial.printf("Soil3:%d\n", (uint16_t)ulp_soil3); + Serial.printf("Soil4:%d\n", (uint16_t)ulp_soil4); + Serial.printf("Soil5:%d\n", (uint16_t)ulp_soil5); + } + Serial.printf("Entering deep sleep\n\n"); + start_ulp_program(); + ESP_ERROR_CHECK( esp_sleep_enable_ulp_wakeup() ); + esp_deep_sleep_start(); +} + +void loop() { + +} + +static void init_ulp_program() +{ + esp_err_t err = ulptool_load_binary(0, ulp_main_bin_start, + (ulp_main_bin_end - ulp_main_bin_start) / sizeof(uint32_t)); + ESP_ERROR_CHECK(err); + + /* Configure ADC channel */ + adc1_config_channel_atten(ADC1_CHANNEL_7, ADC_ATTEN_DB_0); + adc1_config_channel_atten(ADC1_CHANNEL_4, ADC_ATTEN_DB_0); + adc1_config_channel_atten(ADC1_CHANNEL_5, ADC_ATTEN_DB_0); + adc1_config_channel_atten(ADC1_CHANNEL_6, ADC_ATTEN_DB_0); + adc1_config_channel_atten(ADC1_CHANNEL_3, ADC_ATTEN_DB_0); + adc1_config_channel_atten(ADC1_CHANNEL_0, ADC_ATTEN_DB_0); + adc1_config_width(ADC_WIDTH_BIT_12); + adc1_ulp_enable(); + + /* + adc2_config_channel_atten(ADC2_CHANNEL_9, ADC_ATTEN_DB_0); + adc2_config_width(ADC_WIDTH_BIT_12); + adc2_ulp_enable() + */ + + /* Set ULP wake up period to 1000ms */ + ulp_set_wakeup_period(0, 10000 * 1000); + + /* Disable pullup on GPIO15, in case it is connected to ground to suppress + boot messages. + */ + rtc_gpio_pullup_dis(GPIO_NUM_15); + rtc_gpio_hold_en(GPIO_NUM_15); +} + +static void start_ulp_program() +{ + /* Start the program */ + esp_err_t err = ulp_run((&ulp_entry - RTC_SLOW_MEM) / sizeof(uint32_t)); + ESP_ERROR_CHECK(err); +} diff --git a/ulp_soil.h b/ulp_soil.h new file mode 100644 index 0000000..70e069e --- /dev/null +++ b/ulp_soil.h @@ -0,0 +1,10 @@ +#include "Arduino.h" + +extern uint32_t ulp_entry; +extern uint32_t ulp_max_diff; +extern uint32_t ulp_soil0; +extern uint32_t ulp_soil1; +extern uint32_t ulp_soil2; +extern uint32_t ulp_soil3; +extern uint32_t ulp_soil4; +extern uint32_t ulp_soil5; diff --git a/ulp_soil.s b/ulp_soil.s new file mode 100644 index 0000000..f571a01 --- /dev/null +++ b/ulp_soil.s @@ -0,0 +1,382 @@ +/* ULP Example: using ADC in deep sleep + + This example code is in the Public Domain (or CC0 licensed, at your option.) + + Unless required by applicable law or agreed to in writing, this + software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + CONDITIONS OF ANY KIND, either express or implied. + + This file contains assembly code which runs on the ULP. + + ULP wakes up to run this code at a certain period, determined by the values + in SENS_ULP_CP_SLEEP_CYCx_REG registers. On each wake up, the program + measures input voltage on the given ADC channel 'adc_oversampling_factor' + times. Measurements are accumulated and average value is calculated. + Average value is compared to the two thresholds: 'low_thr' and 'high_thr'. + If the value is less than 'low_thr' or more than 'high_thr', ULP wakes up + the chip from deep sleep. +*/ + +/* ULP assembly files are passed through C preprocessor first, so include directives + and C macros may be used in these files + */ +#include "soc/rtc_cntl_reg.h" +#include "soc/soc_ulp.h" + + /* Configure the number of ADC samples to average on each measurement. + For convenience, make it a power of 2. */ + .set adc_oversampling_factor_log, 2 + .set adc_oversampling_factor, (1 << adc_oversampling_factor_log) + + .set soil_threshold, 300 + + .data /* .data section */ + + /* Define variables, which go into .bss section (zero-initialized data) */ + .bss + + .global max_diff +max_diff: + .long 0 + + .global soil0 +soil0: + .long 0 + +soil0_shadow: + .long 0 + + .global soil1 +soil1: + .long 0 + +soil1_shadow: + .long 0 + + .global soil2 +soil2: + .long 0 + +soil2_shadow: + .long 0 + + .global soil3 +soil3: + .long 0 + +soil3_shadow: + .long 0 + + .global soil4 +soil4: + .long 0 + +soil4_shadow: + .long 0 + + .global soil5 +soil5: + .long 0 + +soil5_shadow: + .long 0 + + /* Code goes into .text section */ + .text + .global entry +entry: + /* do measurements using ADC */ + /* r0 will be used as accumulator */ + /* initialize the loop counter */ + +measure_soil0: + move r2, adc_soil0 + move r3, save_soil0 + jump start_measurement + + .global save_soil0 +save_soil0: + move r2, soil0_shadow + st r0, r2, 0 + +measure_soil1: + move r2, adc_soil1 + move r3, save_soil1 + jump start_measurement + + .global save_soil1 +save_soil1: + move r2, soil1_shadow + st r0, r2, 0 + +measure_soil2: + move r2, adc_soil2 + move r3, save_soil2 + jump start_measurement + + .global save_soil2 +save_soil2: + move r2, soil2_shadow + st r0, r2, 0 + +measure_soil3: + move r2, adc_soil3 + move r3, save_soil3 + jump start_measurement + + .global save_soil3 +save_soil3: + move r2, soil3_shadow + st r0, r2, 0 + +measure_soil4: + move r2, adc_soil4 + move r3, save_soil4 + jump start_measurement + + .global save_soil4 +save_soil4: + move r2, soil4_shadow + st r0, r2, 0 + +measure_soil5: + move r2, adc_soil5 + move r3, save_soil5 + jump start_measurement + + .global save_soil5 +save_soil5: + move r2, soil5_shadow + st r0, r2, 0 + +calc_max_diff: +// -- get maximum change in soil value since last wake -- + move r0, max_diff + move r1, 0 + st r1, r0, 0 + move r0, 0 + +// -- soil 0 +soil0_diff: + move r1, soil0 + move r2, soil0_shadow + move r3, soil0_compare_diff + + ld r1, r1, 0 + ld r2, r2, 0 + + sub r0, r1, r2 + jump absolute_diff, OV + +soil0_compare_diff: + move r2, max_diff + ld r1, r2, 0 + + sub r3, r0, r1 + jump soil1_diff, OV + + st r0, r2, 0 + +// -- soil 1 +soil1_diff: + move r1, soil1 + move r2, soil1_shadow + move r3, soil1_compare_diff + + ld r1, r1, 0 + ld r2, r2, 0 + + sub r0, r1, r2 + jump absolute_diff, OV + +soil1_compare_diff: + move r2, max_diff + ld r1, r2, 0 + + sub r3, r0, r1 + jump soil2_diff, OV + + st r0, r2, 0 + +// -- soil 2 +soil2_diff: + move r1, soil2 + move r2, soil2_shadow + move r3, soil2_compare_diff + + ld r1, r1, 0 + ld r2, r2, 0 + + sub r0, r1, r2 + jump absolute_diff, OV + +soil2_compare_diff: + move r2, max_diff + ld r1, r2, 0 + + sub r3, r0, r1 + jump soil3_diff, OV + + st r0, r2, 0 + +// -- soil 3 +soil3_diff: + move r1, soil3 + move r2, soil3_shadow + move r3, soil3_compare_diff + + ld r1, r1, 0 + ld r2, r2, 0 + + sub r0, r1, r2 + jump absolute_diff, OV + +soil3_compare_diff: + move r2, max_diff + ld r1, r2, 0 + + sub r3, r0, r1 + jump soil4_diff, OV + + st r0, r2, 0 + +// -- soil 4 +soil4_diff: + move r1, soil4 + move r2, soil4_shadow + move r3, soil4_compare_diff + + ld r1, r1, 0 + ld r2, r2, 0 + + sub r0, r1, r2 + jump absolute_diff, OV + +soil4_compare_diff: + move r2, max_diff + ld r1, r2, 0 + + sub r3, r0, r1 + jump soil5_diff, OV + + st r0, r2, 0 + +// -- soil 5 +soil5_diff: + move r1, soil5 + move r2, soil5_shadow + move r3, soil5_compare_diff + + ld r1, r1, 0 + ld r2, r2, 0 + + sub r0, r1, r2 + jump absolute_diff, OV + +soil5_compare_diff: + move r2, max_diff + ld r1, r2, 0 + + sub r3, r0, r1 + jump try_wake, OV + + st r0, r2, 0 + +// -- wake in case max_diff >= soil_threshold, copy shadow values to output values +try_wake: + move r0, max_diff + ld r0, r0, 0 + + jumpr copy_and_wake, soil_threshold, GE + + .global exit +exit: + halt + +start_measurement: + move r0, 0 + stage_rst + +measure: + /* measure and add value to accumulator */ + jump r2 + +accumulate_measurement: + add r0, r0, r1 + /* increment loop counter and check exit condition */ + stage_inc 1 + jumps measure, adc_oversampling_factor, lt + + /* divide accumulator by adc_oversampling_factor. + Since it is chosen as a power of two, use right shift */ + rsh r0, r0, adc_oversampling_factor_log + /* averaged value is now in r0; store it into last_result */ + + jump r3 + +absolute_diff: + sub r0, r2, r1 + jump r3 + +adc_soil0: + adc r1, 0, 8 + jump accumulate_measurement + +adc_soil1: + adc r1, 0, 5 + jump accumulate_measurement + +adc_soil2: + adc r1, 0, 6 + jump accumulate_measurement + +adc_soil3: + adc r1, 0, 7 + jump accumulate_measurement + +adc_soil4: + adc r1, 0, 4 + jump accumulate_measurement + +adc_soil5: + adc r1, 0, 1 + jump accumulate_measurement + +copy_and_wake: + move r0, soil0_shadow + move r1, soil0 + ld r0, r0, 0 + st r0, r1, 0 + move r0, soil1_shadow + move r1, soil1 + ld r0, r0, 0 + st r0, r1, 0 + move r0, soil2_shadow + move r1, soil2 + ld r0, r0, 0 + st r0, r1, 0 + move r0, soil3_shadow + move r1, soil3 + ld r0, r0, 0 + st r0, r1, 0 + move r0, soil4_shadow + move r1, soil4 + ld r0, r0, 0 + st r0, r1, 0 + move r0, soil5_shadow + move r1, soil5 + ld r0, r0, 0 + st r0, r1, 0 + + .global wake_up +wake_up: + /* Check if the system can be woken up */ + READ_RTC_FIELD(RTC_CNTL_LOW_POWER_ST_REG, RTC_CNTL_RDY_FOR_WAKEUP) + + and r0, r0, 1 + jump exit, eq + + /* Wake up the SoC, end program */ + wake + WRITE_RTC_FIELD(RTC_CNTL_STATE0_REG, RTC_CNTL_ULP_CP_SLP_TIMER_EN, 0) + halt |