I built a minimal ESP32 program that involved the ULP so that I could test by experiment a number of features that are not clearly documented in the ESP docs.
One question that has arisen the clock frequency with which the ULP timer clock is driven. The docs claim that the ULP timer is driven by a 150 kHz clock, and that clock source appears to be changeable in sdkconfig via make menuconfig. An app I’m developing will need to use long ULP delays, so I did some testing. I built minimal TestBed.c and TestBed.S programs to do the testing, which appear below. These programs build without error (I’m using GNU make at this time). When the C program invokes
ulp_set_wakeup_period( 0, 15000000 ); (15,000,000). If the ULP timer RTC_SLOW clock is driving the ULP timer clock at 150 kHz, I would expect to get a delay of about 100 seconds. Instead I get a delay of approximately 15 seconds. (Timings are between seeing “Yooo Hooo” printed on the terminal – see TestBed.c below.) Either of these delays are so long compared to other sources of “friction” that that “friction” is negligible. It seems that the clock driving the timer can’t possibly be 150 kHz. My calculations indicate that it’s closer to 1 MHz.
Am I misinterpreting this? I’ve supplied my .c and .S programs so you can see how I’m measuring. The programs are pretty minimal, stripping as much “friction” out of the processing as possible, leaving only essential stuff that should account for well less than a second. The code builds without error in a conventional GNU make directory structure within the ESP IDF, with the .S program in a ulp directory below the main directory. The makefile and component makefiles are vanilla. I invite you to verify.
What am I missing? Is there another clock driving the ULP timer? I’d like to understand so that I can set up sleep times more-or-less formulaically and dynamically in my final app.
- // TestBed.c
- #include <stdio.h>
- #include <freertos/FreeRTOS.h>
- #include <freertos/portmacro.h>
- #include <esp32/ulp.h>
- #include "esp_sleep.h"
- #include "ulp_main.h"
- extern const uint8_t bin_start[] asm("_binary_ulp_main_bin_start");
- extern const uint8_t bin_end[] asm("_binary_ulp_main_bin_end");
- void InitializeULP()
- {
- // Set ULP RTC_SLOW_CLOCK tick count for ULP sleep. Set SENS_UOP_CP_CYC0_REG...
- // to 15,000,000, which should yield a sleep time of ~100 seconds if the clock...
- // driving the sleep timer is 150 kHz.
- ulp_set_wakeup_period( 0, 15000000 ); //Set ULP wake up for ~100 seconds
- ulp_load_binary(0, bin_start, (bin_end - bin_start) / sizeof(uint32_t));
- }
- void app_main()
- {
- if (esp_sleep_get_wakeup_cause() != ESP_SLEEP_WAKEUP_ULP)
- InitializeULP();
- else
- printf("Yooo Hooo\n\n\n");
- // Start ULP and go to sleep
- ulp_run((&ulp_entry - RTC_SLOW_MEM) / sizeof(uint32_t));
- esp_sleep_enable_ulp_wakeup();
- esp_deep_sleep_start();
- }
- // TestBed.S
- // These includes define stuff in ULP macros and rtc_gpio
- //#include "soc/rtc_cntl_reg.h"
- //#include "soc/rtc_io_reg.h"
- //#include "soc/sens_reg.h"
- //#include "soc/soc_ulp.h"
- .bss
- .text
- .global entry
- entry:
- sleep 0 // use SENS_ULP_CP_CYC1_REG to set sleep time
- .global exitULP
- exitULP:
- wake
- // disable the timer (effectively preventing the ULP program from running again),
- // clear the RTC_CNTL_ULP_CP_SLP_TIMER_EN bit in the RTC_CNTL_STATE0_REG register.
- // This can be done both from ULP code and from the main program.
- // WRITE_RTC_FIELD(RTC_CNTL_STATE0_REG, RTC_CNTL_ULP_CP_SLP_TIMER_EN, 0)
- Halt
And as long as I’m here, is there any way to eliminate or at least shorten all the info that comes out on the terminal every time the main processors reboots on reset when awakened by the ULP?
Thanks.