Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit ebc8a15

Browse filesBrowse files
Add new ULP example for ESP32 (espressif#7221)
Co-authored-by: Jan Procházka <90197375+P-R-O-C-H-Y@users.noreply.github.com>
1 parent 74964e1 commit ebc8a15
Copy full SHA for ebc8a15

File tree

4 files changed

+165
-0
lines changed
Filter options

4 files changed

+165
-0
lines changed

‎libraries/ESP32/examples/DeepSleep/SmoothBlink_ULP_Code/.skip.esp32c3

Copy file name to clipboardExpand all lines: libraries/ESP32/examples/DeepSleep/SmoothBlink_ULP_Code/.skip.esp32c3
Whitespace-only changes.

‎libraries/ESP32/examples/DeepSleep/SmoothBlink_ULP_Code/.skip.esp32s2

Copy file name to clipboardExpand all lines: libraries/ESP32/examples/DeepSleep/SmoothBlink_ULP_Code/.skip.esp32s2
Whitespace-only changes.

‎libraries/ESP32/examples/DeepSleep/SmoothBlink_ULP_Code/.skip.esp32s3

Copy file name to clipboardExpand all lines: libraries/ESP32/examples/DeepSleep/SmoothBlink_ULP_Code/.skip.esp32s3
Whitespace-only changes.
+165Lines changed: 165 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,165 @@
1+
/*
2+
This example smothly blinks GPIO_2 using different frequencies changed after Deep Sleep Time
3+
The PWM and control of blink frequency is done by ULP exclusively
4+
This is an example about how to program the ULP using Arduino
5+
It also demonstrates use of RTM MEMORY to persist data and states
6+
*/
7+
8+
#include <Arduino.h>
9+
#include "esp32/ulp.h"
10+
#include "driver/rtc_io.h"
11+
12+
// RTC Memory used for ULP internal variable and Sketch interfacing
13+
#define RTC_dutyMeter 0
14+
#define RTC_dir 4
15+
#define RTC_fadeDelay 12
16+
// *fadeCycleDelay is used to pass values to ULP and change its behaviour
17+
uint32_t *fadeCycleDelay = &RTC_SLOW_MEM[RTC_fadeDelay];
18+
#define ULP_START_OFFSET 32
19+
20+
// For ESP32 Arduino, it is usually at offeset 512, defined in sdkconfig
21+
RTC_DATA_ATTR uint32_t ULP_Started = 0; // 0 or 1
22+
23+
//Time-to-Sleep
24+
#define uS_TO_S_FACTOR 1000000ULL /* Conversion factor for micro seconds to seconds */
25+
#define TIME_TO_SLEEP 5 /* Time ESP32 will go to sleep (in microseconds); multiplied by above conversion to achieve seconds*/
26+
27+
28+
void ulp_setup() {
29+
if (ULP_Started) {
30+
return;
31+
}
32+
*fadeCycleDelay = 5; // 5..200 works fine for a full Fade In + Out cycle
33+
ULP_Started = 1;
34+
35+
// GPIO2 initialization (set to output and initial value is 0)
36+
const gpio_num_t MeterPWMPin = GPIO_NUM_2;
37+
rtc_gpio_init(MeterPWMPin);
38+
rtc_gpio_set_direction(MeterPWMPin, RTC_GPIO_MODE_OUTPUT_ONLY);
39+
rtc_gpio_set_level(MeterPWMPin, 0);
40+
41+
// if LED is connected to GPIO2 (specify by +RTC_GPIO_OUT_DATA_S : ESP32 is 14, S2/S3 is 10)
42+
const uint32_t MeterPWMBit = rtc_io_number_get(MeterPWMPin) + RTC_GPIO_OUT_DATA_S;
43+
44+
enum labels {
45+
INIFINITE_LOOP,
46+
RUN_PWM,
47+
NEXT_PWM_CYCLE,
48+
PWM_ON,
49+
PWM_OFF,
50+
END_PWM_CYCLE,
51+
POSITIVE_DIR,
52+
DEC_DUTY,
53+
INC_DUTY,
54+
};
55+
56+
// Define ULP program
57+
const ulp_insn_t ulp_prog[] = {
58+
// Initial Value setup
59+
I_MOVI(R0, 0), // R0 = 0
60+
I_ST(R0, R0, RTC_dutyMeter), // RTC_SLOW_MEM[RTC_dutyMeter] = 0
61+
I_MOVI(R1, 1), // R1 = 1
62+
I_ST(R1, R0, RTC_dir), // RTC_SLOW_MEM[RTC_dir] = 1
63+
64+
M_LABEL(INIFINITE_LOOP), // while(1) {
65+
66+
// run certain PWM Duty for about (RTC_fadeDelay x 100) microseconds
67+
I_MOVI(R3, 0), // R3 = 0
68+
I_LD(R3, R3, RTC_fadeDelay), // R3 = RTC_SLOW_MEM[RTC_fadeDelay]
69+
M_LABEL(RUN_PWM), // do { // repeat RTC_fadeDelay times:
70+
71+
// execute about 10KHz PWM on GPIO2 using as duty cycle = RTC_SLOW_MEM[RTC_dutyMeter]
72+
I_MOVI(R0, 0), // R0 = 0
73+
I_LD(R0, R0, RTC_dutyMeter), // R0 = RTC_SLOW_MEM[RTC_dutyMeter]
74+
M_BL(NEXT_PWM_CYCLE, 1), // if (R0 > 0) turn on LED
75+
I_WR_REG(RTC_GPIO_OUT_W1TS_REG, MeterPWMBit, MeterPWMBit, 1), // W1TS set bit to clear GPIO - GPIO2 on
76+
M_LABEL(PWM_ON), // while (R0 > 0) // repeat RTC_dutyMeter times:
77+
M_BL(NEXT_PWM_CYCLE, 1), // {
78+
//I_DELAY(8), // // 8 is about 1 microsecond based on 8MHz
79+
I_SUBI(R0, R0, 1), // R0 = R0 - 1
80+
M_BX(PWM_ON), // }
81+
M_LABEL(NEXT_PWM_CYCLE), // // toggle GPIO_2
82+
I_MOVI(R0, 0), // R0 = 0
83+
I_LD(R0, R0, RTC_dutyMeter), // R0 = RTC_SLOW_MEM[RTC_dutyMeter]
84+
I_MOVI(R1, 100), // R1 = 100
85+
I_SUBR(R0, R1, R0), // R0 = 100 - dutyMeter
86+
M_BL(END_PWM_CYCLE, 1), // if (R0 > 0) turn off LED
87+
I_WR_REG(RTC_GPIO_OUT_W1TC_REG, MeterPWMBit, MeterPWMBit, 1), // W1TC set bit to clear GPIO - GPIO2 off
88+
M_LABEL(PWM_OFF), // while (R0 > 0) // repeat (100 - RTC_dutyMeter) times:
89+
M_BL(END_PWM_CYCLE, 1), // {
90+
//I_DELAY(8), // // 8 is about 1us: ULP fetch+execution time
91+
I_SUBI(R0, R0, 1), // R0 = R0 - 1
92+
M_BX(PWM_OFF), // }
93+
M_LABEL(END_PWM_CYCLE), //
94+
95+
I_SUBI(R3, R3, 1), // R3 = R3 - 1 // RTC_fadeDelay
96+
I_MOVR(R0, R3), // R0 = R3 // only R0 can be used to compare and branch
97+
M_BGE(RUN_PWM, 1), // } while (R3 > 0) // ESP32 repeatinf RTC_fadeDelay times
98+
99+
// increase/decrease DutyMeter to apply Fade In/Out loop
100+
I_MOVI(R1, 0), // R1 = 0
101+
I_LD(R1, R1, RTC_dutyMeter), // R1 = RTC_SLOW_MEM[RTC_dutyMeter]
102+
I_MOVI(R0, 0), // R0 = 0
103+
I_LD(R0, R0, RTC_dir), // R0 = RTC_SLOW_MEM[RTC_dir]
104+
105+
M_BGE(POSITIVE_DIR, 1), // if(dir == 0) { // decrease duty by 2
106+
// Dir is 0, means decrease Duty by 2
107+
I_MOVR(R0, R1), // R0 = Duty
108+
M_BGE(DEC_DUTY, 1), // if (duty == 0) { // change direction and increase duty
109+
I_MOVI(R3, 0), // R3 = 0
110+
I_MOVI(R2, 1), // R2 = 1
111+
I_ST(R2, R3, RTC_dir), // RTC_SLOW_MEM[RTC_dir] = 1 // increasing direction
112+
M_BX(INC_DUTY), // goto "increase Duty"
113+
M_LABEL(DEC_DUTY), // } "decrease Duty":
114+
I_SUBI(R0, R0, 2), // Duty -= 2
115+
I_MOVI(R2, 0), // R2 = 0
116+
I_ST(R0, R2, RTC_dutyMeter), // RTC_SLOW_MEM[RTC_dutyMeter] += 2
117+
M_BX(INIFINITE_LOOP), // }
118+
119+
M_LABEL(POSITIVE_DIR), // else { // dir == 1 // increase duty by 2
120+
// Dir is 1, means increase Duty by 2
121+
I_MOVR(R0, R1), // R0 = Duty
122+
M_BL(INC_DUTY, 100), // if (duty == 100) { // change direction and decrease duty
123+
I_MOVI(R2, 0), // R2 = 0
124+
I_ST(R2, R2, RTC_dir), // RTC_SLOW_MEM[RTC_dir] = 0 // decreasing direction
125+
M_BX(DEC_DUTY), // goto "decrease Duty"
126+
M_LABEL(INC_DUTY), // } "increase Duty":
127+
I_ADDI(R0, R0, 2), // Duty += 2
128+
I_MOVI(R2, 0), // R2 = 0
129+
I_ST(R0, R2, RTC_dutyMeter), // RTC_SLOW_MEM[RTC_dutyMeter] -= 2
130+
// } // if (dir == 0)
131+
M_BX(INIFINITE_LOOP), // } // while(1)
132+
};
133+
// Run ULP program
134+
size_t size = sizeof(ulp_prog) / sizeof(ulp_insn_t);
135+
ulp_process_macros_and_load(ULP_START_OFFSET, ulp_prog, &size);
136+
esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_ON);
137+
ulp_run(ULP_START_OFFSET);
138+
}
139+
140+
141+
void setup() {
142+
Serial.begin(115200);
143+
while (!Serial) {} // wait for Serial to start
144+
145+
ulp_setup(); // it really only runs on the first ESP32 boot
146+
Serial.printf("\nStarted smooth blink with delay %d\n", *fadeCycleDelay);
147+
148+
// *fadeCycleDelay resides in RTC_SLOW_MEM and persists along deep sleep waking up
149+
// it is used as a delay time parameter for smooth blinking, in the ULP processing code
150+
if (*fadeCycleDelay < 195) {
151+
*fadeCycleDelay += 10;
152+
} else {
153+
*fadeCycleDelay = 5; // 5..200 works fine for a full Fade In + Out cycle
154+
}
155+
Serial.println("Entering in Deep Sleep");
156+
esp_sleep_enable_timer_wakeup(TIME_TO_SLEEP * uS_TO_S_FACTOR /*/ 4*/); // time set with variable above
157+
esp_deep_sleep_start();
158+
// From this point on, no code is executed in DEEP SLEEP mode
159+
}
160+
161+
162+
void loop() {
163+
// It never reaches this code because it enters in Deep Sleep mode at the end of setup()
164+
}
165+

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.