Read ADC in ULP (deep sleep) and read pushbutton
Posted: Fri May 13, 2022 5:34 am
Hi guys,
For a project, I want to wake the ESP32 from deep-sleep when an analog value reaches a specific threshold on the ADC. I also want to wake the main processor when I push a button.
Everything works except for one thing: when I wake the main processor with the pushbutton, then the next "round" the ADC-readings don't work anymore. That means that I can't wake the main processor with the analog /ADC port anymore.
I have this code in setup():
I also have a file "adc.s" with this code:
This is the assembly code that runs in ULP when the main processor is in deep-sleep.
Like I said: everything works independently of each other, but how is it possible that the ADC-reading don't work anymore after I wake the ESP32 with the push button?
I haven't been able to figure it out for days, so any help is highly desirable
Thanks in advance,
Atmoz
For a project, I want to wake the ESP32 from deep-sleep when an analog value reaches a specific threshold on the ADC. I also want to wake the main processor when I push a button.
Everything works except for one thing: when I wake the main processor with the pushbutton, then the next "round" the ADC-readings don't work anymore. That means that I can't wake the main processor with the analog /ADC port anymore.
I have this code in setup():
Code: Select all
if (EnableSleep){
esp_sleep_wakeup_cause_t WakkerMaakReden = esp_sleep_get_wakeup_cause();
if (WakkerMaakReden != ESP_SLEEP_WAKEUP_ULP){
SendUDP("Reden van wakker maken was niet ULP");
delay(1000);
init_ulp_program();
} else {
ulp_ADC_reading &= UINT16_MAX;
SendUDP("ulp_ADC_reading: " + String(ulp_ADC_reading));
delay(1000);
init_ulp_program();
}
SendUDP("Slaapstand starten");
delay(1000);
start_ulp_program();
ESP_ERROR_CHECK(esp_sleep_enable_ulp_wakeup());
esp_sleep_enable_ext1_wakeup(BUTTON_PIN_BITMASK,ESP_EXT1_WAKEUP_ALL_LOW); //wake with pushbutton (BUTTON_PIN_BITMASK is 0x4000)
esp_deep_sleep_start();
}
static void init_ulp_program()
{
esp_err_t err = ulp_load_binary(0, ulp_main_bin_start,
(ulp_main_bin_end - ulp_main_bin_start) / sizeof(uint32_t));
ESP_ERROR_CHECK(err);
digitalWrite(POWER, HIGH); //pcb power
digitalWrite(26, HIGH); //tcrt led power
gpio_hold_en(GPIO_NUM_13); //pcb power
gpio_hold_en(GPIO_NUM_26); //tcrt power
gpio_deep_sleep_hold_en();
adc1_config_channel_atten(ADC1_CHANNEL_4, ADC_ATTEN_DB_11);
adc1_config_width(ADC_WIDTH_BIT_12);
adc1_ulp_enable();
ulp_low_threshold = 4090;
ulp_high_threshold = 4096;
ulp_set_wakeup_period(0, 40 * 1000);
}
static void start_ulp_program()
{
esp_err_t err = ulp_run((&ulp_entry - RTC_SLOW_MEM) / sizeof(uint32_t));
ESP_ERROR_CHECK(err);
}
Code: Select all
#include "soc/rtc_cntl_reg.h"
#include "soc/rtc_io_reg.h"
#include "soc/soc_ulp.h"
/* ADC1 channel 6, GPIO34 */
.set adc_channel, 4
/* Configure the number of ADC samples to average on each measurement.
For convenience, make it a power of 2. */
.set adc_oversampling_factor_log, 1
.set adc_oversampling_factor, (1 << adc_oversampling_factor_log)
/* Define variables, which go into .bss section (zero-initialized data) */
.bss
/* Low threshold of ADC reading.
Set by the main program. */
.global low_threshold
low_threshold: .long 0
/* High threshold of ADC reading.
Set by the main program. */
.global high_threshold
high_threshold: .long 0
/* Counter of measurements done */
.global sample_counter
sample_counter:
.long 0
.global ADC_reading
ADC_reading:
.long 0
/* Code goes into .text section */
.text
.global entry
entry:
/* Disable hold of GPIO13 output */
//WRITE_RTC_REG(RTC_IO_TOUCH_PAD4_REG, RTC_IO_TOUCH_PAD4_HOLD_S, 1, 0)
/* Set the GPIO13 output HIGH */
//WRITE_RTC_REG(RTC_GPIO_OUT_W1TS_REG, RTC_GPIO_OUT_DATA_W1TS_S + 14, 1, 1)
/* increment sample counter */
move r3, sample_counter
ld R2, r3, 0
add R2, R2, 1
st R2, r3, 0
/* do measurements using ADC */
/* r0 will be used as accumulator */
move r0, 0
/* initialize the loop counter */
stage_rst
measure:
/* measure and add value to accumulator */
adc r1, 0, adc_channel + 1
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 ADC_reading */
move r3, ADC_reading
st r0, r3, 0
/* compare with low_threshold; wake up if value < low_threshold */
move r3, low_threshold
ld r3, r3, 0
sub r3, r0, r3
jump wake_up, ov
/* value within range, end the program */
.global exit
exit:
/* Set the GPIO13 output LOW (clear output) to signal that ULP is now going down */
//WRITE_RTC_REG(RTC_GPIO_OUT_W1TC_REG, RTC_GPIO_OUT_DATA_W1TC_S + 14, 1, 1)
/* Enable hold on GPIO13 output */
//WRITE_RTC_REG(RTC_IO_TOUCH_PAD4_REG, RTC_IO_TOUCH_PAD4_HOLD_S, 1, 1)
halt
.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)
jump exit
Like I said: everything works independently of each other, but how is it possible that the ADC-reading don't work anymore after I wake the ESP32 with the push button?
I haven't been able to figure it out for days, so any help is highly desirable
Thanks in advance,
Atmoz