summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFlorian Baumann <derflob@derflob.de>2020-04-26 23:27:49 +0200
committerFlorian Baumann <derflob@derflob.de>2020-04-26 23:27:49 +0200
commit67561973c70ca5986db4af5c39baca5b4811d8ba (patch)
tree4ea729de225b76e639960ace09b0da138eb19d68
downloadULPSoilMonitor-67561973c70ca5986db4af5c39baca5b4811d8ba.tar.gz
ULPSoilMonitor-67561973c70ca5986db4af5c39baca5b4811d8ba.tar.bz2
ulp measures adc1 periodically and wakes esp32 on threshold
-rw-r--r--ULPSoilMonitor.ino93
-rw-r--r--ulp_soil.h10
-rw-r--r--ulp_soil.s382
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