Inconsistent ULP ISR while using WiFi
Posted: Sun Oct 10, 2021 6:01 am
I am having an issue wherein the main processor occasionally does not wakeup when a command is sent by ULP coprocessor while powersave mode and aspects of the WiFi protocol are active.I get the sense that the ULP ISR has a lower priority than some WiFi or is unable to perform its task on a different core.
In the image below is an oscilloscope capture. The yellow trace indicates the ULP code's wakeup (a pin is toggled high and then low for debugging purposes), and the purple trace is the ISR triggering and sending a pin high and then low. The red arrows are pointing locations where the ISR failed to respond but the ULP has issues a wakeup command: Main core:
ULP code:
I find that the problem occurs when both tcpip_adapter_init() and esp_pm_configure(&pm) are present. The issue is exacerbated by additional WiFi functionality being present. I would need the ULP ISR to trigger on every WAKE command. Has anyone encountered this or knows a way around this problem?
Thank you.
In the image below is an oscilloscope capture. The yellow trace indicates the ULP code's wakeup (a pin is toggled high and then low for debugging purposes), and the purple trace is the ISR triggering and sending a pin high and then low. The red arrows are pointing locations where the ISR failed to respond but the ULP has issues a wakeup command: Main core:
Code: Select all
/*** includes ***/
#include "driver/rtc_io.h"
#include "soc/rtc_cntl_reg.h"
#include "soc/rtc_io_reg.h"
#include "soc/sens_reg.h"
#include "soc/rtc_periph.h"
#include "soc/soc.h"
#include "esp32/ulp.h"
#include "ulp_main.h"
#include "driver/rtc_cntl.h"
#include "esp_sleep.h"
#include "nvs.h"
#include <rom/ets_sys.h> // needed for us delay
#include <string.h>
#include <sys/param.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/event_groups.h"
#include "esp_system.h"
#include "esp_wifi.h"
#include "esp_event_loop.h"
#include "nvs_flash.h"
#include "lwip/err.h"
#include "lwip/sockets.h"
#include "lwip/sys.h"
#include <lwip/netdb.h>
#include "esp_pm.h"
#include <stdio.h>
#include "driver/gpio.h"
#include "sdkconfig.h"
#include <math.h>
#include <sys/time.h>
#include <time.h>
#include "driver/uart.h"
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);
// Setup ULP pins
// yellow trace (ULP wakeup)
gpio_num_t gpio_TEST = 13; // test pin
rtc_gpio_init(gpio_TEST);
rtc_gpio_set_direction(gpio_TEST, RTC_GPIO_MODE_OUTPUT_ONLY);
gpio_set_level(gpio_TEST,0);
rtc_gpio_set_level(gpio_TEST, 0);
// purple trace (ISR response)
gpio_pad_select_gpio(15);
gpio_set_direction(15, GPIO_MODE_OUTPUT);
gpio_set_level(15,0);
esp_deep_sleep_disable_rom_logging(); // suppress boot messages
esp_sleep_enable_ulp_wakeup(); // this is needed to permit the ISR to work when powersave mode is active.
ESP_ERROR_CHECK( ulp_run((&ulp_entry - RTC_SLOW_MEM) / sizeof(uint32_t)));
}
static void IRAM_ATTR ulp_isr_handler(void *args)
{
gpio_set_level(15, 1); // turn on pin 15 so the oscillosocpe can capture it
// this delay is necessary without it the isr handler (interrupt) ends too fast and the ulp processor hasn't cleared the wait command in time thereby retriggering the isr
ets_delay_us(50);
gpio_set_level(15, 0); // turn on pin 15 so the oscillosocpe can capture it
}
static void ulp_isr_install()
{
ESP_ERROR_CHECK( rtc_isr_register(&ulp_isr_handler, NULL, RTC_CNTL_SAR_INT_ST_M) );
REG_SET_BIT(RTC_CNTL_INT_ENA_REG, RTC_CNTL_ULP_CP_INT_ENA_M);
}
void app_main()
{
nvs_flash_init(); //initialize nvs flash
printf("start\n");
ulp_isr_install();
init_ulp_program();
tcpip_adapter_init();
esp_pm_config_esp32_t pm =
{
.max_freq_mhz=80,
.min_freq_mhz=10,
.light_sleep_enable=true
};
esp_pm_configure(&pm); //Initialize powersave mode, set frequency range, enable sleep
}
Code: Select all
#include "soc/rtc_cntl_reg.h"
#include "soc/rtc_io_reg.h"
#include "soc/soc_ulp.h"
/* Pin Macros */
.macro TEST_P_HI // pin set high
WRITE_RTC_REG(RTC_GPIO_OUT_REG, RTC_GPIO_OUT_DATA_S+14,1,1)
.endm
.macro TEST_P_LO // pin set low
WRITE_RTC_REG(RTC_GPIO_OUT_REG, RTC_GPIO_OUT_DATA_S+14,1,0)
.endm
/* Code goes into .text section */
.text
.global entry
entry:
STAGE_RST
WAIT_LOOP:
WAIT 500
WAIT 500
WAIT 500
WAIT 500
WAIT 500
WAIT 500
WAIT 500
WAIT 500
WAIT 500
WAIT 500
WAIT 500
WAIT 500
WAIT 500
WAIT 500
WAIT 500
WAIT 500
STAGE_INC 1
JUMPS WAKE_CODE, 250, GE
JUMP WAIT_LOOP
WAKE_CODE:
TEST_P_HI // set pin hi (yellow trace on oscilloscope)
// this should trigger the ISR
wake
//WRITE_RTC_FIELD(RTC_CNTL_STATE0_REG, RTC_CNTL_ULP_CP_SLP_TIMER_EN, 0)
// wait commands to create a visible pulse
WAIT 500 // 0
WAIT 500 // 1
WAIT 500 // 2
WAIT 500 // 3
WAIT 500 // 4
WAIT 500 // 5
WAIT 500 // 6
WAIT 500 // 7
WAIT 500 // 8
WAIT 500 // 9
WAIT 500 // 10
WAIT 500 // 11
WAIT 500 // 12
WAIT 500 // 13
WAIT 500 // 14
WAIT 500 // 15
TEST_P_LO // set pin low (yellow trace on oscilloscope)
jump entry
Thank you.