From ebc8a15e0e1724965b9883bacbe8d0b039c6f2e5 Mon Sep 17 00:00:00 2001 From: Rodrigo Garcia Date: Wed, 14 Sep 2022 05:44:12 -0300 Subject: [PATCH] Add new ULP example for ESP32 (#7221) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Jan Procházka <90197375+P-R-O-C-H-Y@users.noreply.github.com> --- .../SmoothBlink_ULP_Code/.skip.esp32c3 | 0 .../SmoothBlink_ULP_Code/.skip.esp32s2 | 0 .../SmoothBlink_ULP_Code/.skip.esp32s3 | 0 .../SmoothBlink_ULP_Code.ino | 165 ++++++++++++++++++ 4 files changed, 165 insertions(+) create mode 100644 libraries/ESP32/examples/DeepSleep/SmoothBlink_ULP_Code/.skip.esp32c3 create mode 100644 libraries/ESP32/examples/DeepSleep/SmoothBlink_ULP_Code/.skip.esp32s2 create mode 100644 libraries/ESP32/examples/DeepSleep/SmoothBlink_ULP_Code/.skip.esp32s3 create mode 100644 libraries/ESP32/examples/DeepSleep/SmoothBlink_ULP_Code/SmoothBlink_ULP_Code.ino diff --git a/libraries/ESP32/examples/DeepSleep/SmoothBlink_ULP_Code/.skip.esp32c3 b/libraries/ESP32/examples/DeepSleep/SmoothBlink_ULP_Code/.skip.esp32c3 new file mode 100644 index 000000000..e69de29bb diff --git a/libraries/ESP32/examples/DeepSleep/SmoothBlink_ULP_Code/.skip.esp32s2 b/libraries/ESP32/examples/DeepSleep/SmoothBlink_ULP_Code/.skip.esp32s2 new file mode 100644 index 000000000..e69de29bb diff --git a/libraries/ESP32/examples/DeepSleep/SmoothBlink_ULP_Code/.skip.esp32s3 b/libraries/ESP32/examples/DeepSleep/SmoothBlink_ULP_Code/.skip.esp32s3 new file mode 100644 index 000000000..e69de29bb diff --git a/libraries/ESP32/examples/DeepSleep/SmoothBlink_ULP_Code/SmoothBlink_ULP_Code.ino b/libraries/ESP32/examples/DeepSleep/SmoothBlink_ULP_Code/SmoothBlink_ULP_Code.ino new file mode 100644 index 000000000..77a886209 --- /dev/null +++ b/libraries/ESP32/examples/DeepSleep/SmoothBlink_ULP_Code/SmoothBlink_ULP_Code.ino @@ -0,0 +1,165 @@ +/* + This example smothly blinks GPIO_2 using different frequencies changed after Deep Sleep Time + The PWM and control of blink frequency is done by ULP exclusively + This is an example about how to program the ULP using Arduino + It also demonstrates use of RTM MEMORY to persist data and states +*/ + +#include +#include "esp32/ulp.h" +#include "driver/rtc_io.h" + +// RTC Memory used for ULP internal variable and Sketch interfacing +#define RTC_dutyMeter 0 +#define RTC_dir 4 +#define RTC_fadeDelay 12 +// *fadeCycleDelay is used to pass values to ULP and change its behaviour +uint32_t *fadeCycleDelay = &RTC_SLOW_MEM[RTC_fadeDelay]; +#define ULP_START_OFFSET 32 + +// For ESP32 Arduino, it is usually at offeset 512, defined in sdkconfig +RTC_DATA_ATTR uint32_t ULP_Started = 0; // 0 or 1 + +//Time-to-Sleep +#define uS_TO_S_FACTOR 1000000ULL /* Conversion factor for micro seconds to seconds */ +#define TIME_TO_SLEEP 5 /* Time ESP32 will go to sleep (in microseconds); multiplied by above conversion to achieve seconds*/ + + +void ulp_setup() { + if (ULP_Started) { + return; + } + *fadeCycleDelay = 5; // 5..200 works fine for a full Fade In + Out cycle + ULP_Started = 1; + + // GPIO2 initialization (set to output and initial value is 0) + const gpio_num_t MeterPWMPin = GPIO_NUM_2; + rtc_gpio_init(MeterPWMPin); + rtc_gpio_set_direction(MeterPWMPin, RTC_GPIO_MODE_OUTPUT_ONLY); + rtc_gpio_set_level(MeterPWMPin, 0); + + // if LED is connected to GPIO2 (specify by +RTC_GPIO_OUT_DATA_S : ESP32 is 14, S2/S3 is 10) + const uint32_t MeterPWMBit = rtc_io_number_get(MeterPWMPin) + RTC_GPIO_OUT_DATA_S; + + enum labels { + INIFINITE_LOOP, + RUN_PWM, + NEXT_PWM_CYCLE, + PWM_ON, + PWM_OFF, + END_PWM_CYCLE, + POSITIVE_DIR, + DEC_DUTY, + INC_DUTY, + }; + + // Define ULP program + const ulp_insn_t ulp_prog[] = { + // Initial Value setup + I_MOVI(R0, 0), // R0 = 0 + I_ST(R0, R0, RTC_dutyMeter), // RTC_SLOW_MEM[RTC_dutyMeter] = 0 + I_MOVI(R1, 1), // R1 = 1 + I_ST(R1, R0, RTC_dir), // RTC_SLOW_MEM[RTC_dir] = 1 + + M_LABEL(INIFINITE_LOOP), // while(1) { + + // run certain PWM Duty for about (RTC_fadeDelay x 100) microseconds + I_MOVI(R3, 0), // R3 = 0 + I_LD(R3, R3, RTC_fadeDelay), // R3 = RTC_SLOW_MEM[RTC_fadeDelay] + M_LABEL(RUN_PWM), // do { // repeat RTC_fadeDelay times: + + // execute about 10KHz PWM on GPIO2 using as duty cycle = RTC_SLOW_MEM[RTC_dutyMeter] + I_MOVI(R0, 0), // R0 = 0 + I_LD(R0, R0, RTC_dutyMeter), // R0 = RTC_SLOW_MEM[RTC_dutyMeter] + M_BL(NEXT_PWM_CYCLE, 1), // if (R0 > 0) turn on LED + I_WR_REG(RTC_GPIO_OUT_W1TS_REG, MeterPWMBit, MeterPWMBit, 1), // W1TS set bit to clear GPIO - GPIO2 on + M_LABEL(PWM_ON), // while (R0 > 0) // repeat RTC_dutyMeter times: + M_BL(NEXT_PWM_CYCLE, 1), // { + //I_DELAY(8), // // 8 is about 1 microsecond based on 8MHz + I_SUBI(R0, R0, 1), // R0 = R0 - 1 + M_BX(PWM_ON), // } + M_LABEL(NEXT_PWM_CYCLE), // // toggle GPIO_2 + I_MOVI(R0, 0), // R0 = 0 + I_LD(R0, R0, RTC_dutyMeter), // R0 = RTC_SLOW_MEM[RTC_dutyMeter] + I_MOVI(R1, 100), // R1 = 100 + I_SUBR(R0, R1, R0), // R0 = 100 - dutyMeter + M_BL(END_PWM_CYCLE, 1), // if (R0 > 0) turn off LED + I_WR_REG(RTC_GPIO_OUT_W1TC_REG, MeterPWMBit, MeterPWMBit, 1), // W1TC set bit to clear GPIO - GPIO2 off + M_LABEL(PWM_OFF), // while (R0 > 0) // repeat (100 - RTC_dutyMeter) times: + M_BL(END_PWM_CYCLE, 1), // { + //I_DELAY(8), // // 8 is about 1us: ULP fetch+execution time + I_SUBI(R0, R0, 1), // R0 = R0 - 1 + M_BX(PWM_OFF), // } + M_LABEL(END_PWM_CYCLE), // + + I_SUBI(R3, R3, 1), // R3 = R3 - 1 // RTC_fadeDelay + I_MOVR(R0, R3), // R0 = R3 // only R0 can be used to compare and branch + M_BGE(RUN_PWM, 1), // } while (R3 > 0) // ESP32 repeatinf RTC_fadeDelay times + + // increase/decrease DutyMeter to apply Fade In/Out loop + I_MOVI(R1, 0), // R1 = 0 + I_LD(R1, R1, RTC_dutyMeter), // R1 = RTC_SLOW_MEM[RTC_dutyMeter] + I_MOVI(R0, 0), // R0 = 0 + I_LD(R0, R0, RTC_dir), // R0 = RTC_SLOW_MEM[RTC_dir] + + M_BGE(POSITIVE_DIR, 1), // if(dir == 0) { // decrease duty by 2 + // Dir is 0, means decrease Duty by 2 + I_MOVR(R0, R1), // R0 = Duty + M_BGE(DEC_DUTY, 1), // if (duty == 0) { // change direction and increase duty + I_MOVI(R3, 0), // R3 = 0 + I_MOVI(R2, 1), // R2 = 1 + I_ST(R2, R3, RTC_dir), // RTC_SLOW_MEM[RTC_dir] = 1 // increasing direction + M_BX(INC_DUTY), // goto "increase Duty" + M_LABEL(DEC_DUTY), // } "decrease Duty": + I_SUBI(R0, R0, 2), // Duty -= 2 + I_MOVI(R2, 0), // R2 = 0 + I_ST(R0, R2, RTC_dutyMeter), // RTC_SLOW_MEM[RTC_dutyMeter] += 2 + M_BX(INIFINITE_LOOP), // } + + M_LABEL(POSITIVE_DIR), // else { // dir == 1 // increase duty by 2 + // Dir is 1, means increase Duty by 2 + I_MOVR(R0, R1), // R0 = Duty + M_BL(INC_DUTY, 100), // if (duty == 100) { // change direction and decrease duty + I_MOVI(R2, 0), // R2 = 0 + I_ST(R2, R2, RTC_dir), // RTC_SLOW_MEM[RTC_dir] = 0 // decreasing direction + M_BX(DEC_DUTY), // goto "decrease Duty" + M_LABEL(INC_DUTY), // } "increase Duty": + I_ADDI(R0, R0, 2), // Duty += 2 + I_MOVI(R2, 0), // R2 = 0 + I_ST(R0, R2, RTC_dutyMeter), // RTC_SLOW_MEM[RTC_dutyMeter] -= 2 + // } // if (dir == 0) + M_BX(INIFINITE_LOOP), // } // while(1) + }; + // Run ULP program + size_t size = sizeof(ulp_prog) / sizeof(ulp_insn_t); + ulp_process_macros_and_load(ULP_START_OFFSET, ulp_prog, &size); + esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_ON); + ulp_run(ULP_START_OFFSET); +} + + +void setup() { + Serial.begin(115200); + while (!Serial) {} // wait for Serial to start + + ulp_setup(); // it really only runs on the first ESP32 boot + Serial.printf("\nStarted smooth blink with delay %d\n", *fadeCycleDelay); + + // *fadeCycleDelay resides in RTC_SLOW_MEM and persists along deep sleep waking up + // it is used as a delay time parameter for smooth blinking, in the ULP processing code + if (*fadeCycleDelay < 195) { + *fadeCycleDelay += 10; + } else { + *fadeCycleDelay = 5; // 5..200 works fine for a full Fade In + Out cycle + } + Serial.println("Entering in Deep Sleep"); + esp_sleep_enable_timer_wakeup(TIME_TO_SLEEP * uS_TO_S_FACTOR /*/ 4*/); // time set with variable above + esp_deep_sleep_start(); + // From this point on, no code is executed in DEEP SLEEP mode +} + + +void loop() { + // It never reaches this code because it enters in Deep Sleep mode at the end of setup() +} + -- GitLab