ESP32-S2 ULP cannot control GPIO output

timokett
Posts: 7
Joined: Thu Jun 17, 2021 11:19 am

ESP32-S2 ULP cannot control GPIO output

Postby timokett » Mon Jan 24, 2022 5:26 pm

I am trying to control GPIO output with RISCV ULP in deep sleep. I started with the only example I found, the espressif examples/system/ulp_riscv. It is a simple example that reads input and then wakes up the main processor. It works fine.
But when I try to control GPIO, I ran into problems. In short: the GPIO output works from ULP when main processor is running but stops when main processor goes to sleep.
The documentation about what can and cannot be done in ULP is non-existing. Have anyone tried to write GPIO in ULP code?
The ULP code below writes 0 for 10 seconds, 1 for 10 seconds and then again 0 for 10 seconds. Simple voltage meter can be used to check that it is working. If I delay the main processor going into sleep for 30 seconds, ULP code works fine. But If the main goes to sleep immediately, the output pin seems to be floating for whole 30 seconds.
Then I thought that I have to enable peripheral power with esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_ON); It actually seemed to work, couple of times. But the I started to get random ULP Traps, code 11.

Below is the main without headers, the headers are unmodified from riscv sample.
I changed he ULP timer to happen once a second.

Code: Select all

void app_main(void) {
  rtc_gpio_init(GPIO_NUM_2);
  rtc_gpio_set_direction(GPIO_NUM_2, RTC_GPIO_MODE_OUTPUT_ONLY);
  esp_sleep_wakeup_cause_t cause = esp_sleep_get_wakeup_cause();
  if (cause != ESP_SLEEP_WAKEUP_ULP) {
    printf("Not a ULP-RISC-V wakeup, cause = %d, initializing it! \n", cause);
    init_ulp_program();
    // Uncommenting following makes the ULP code work while the main processor is up
    // vTaskDelay(30000 / portTICK_PERIOD_MS);
  }
  if (cause == ESP_SLEEP_WAKEUP_ULP) {
    printf("ULP-RISC-V woke up the main CPU! \n");
  }
  printf("Entering in deep sleep\n\n");
  vTaskDelay(100);
  // Uncommenting following causes random ULP traps (cause == 11)
  // esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_ON);
  ESP_ERROR_CHECK(esp_sleep_enable_ulp_wakeup());
  esp_deep_sleep_start();
}

static void init_ulp_program(void) {
  ulp_riscv_load_binary(ulp_main_bin_start, (ulp_main_bin_end - ulp_main_bin_start));

  ulp_set_wakeup_period(0, 1000000); // one second !
  ulp_riscv_run();
}
The ULP code:

Code: Select all

#define pin GPIO_NUM_2

int main(void) {

  static int count = 0;

  if (count == 0) {
    // do nothing, main process is not yet in sleep
  } else if (count > 0 && count <= 10) {
    example_ulp_gpio_output_level(pin, 0);
  } else if (count > 10 && count <= 20) {
    example_ulp_gpio_output_level(pin, 1);
  } else if (count > 20 && count < 30) {
    example_ulp_gpio_output_level(pin, 0);
  } else if (count >= 30) {
    count = 0;
    ulp_riscv_wakeup_main_processor();
  }
  count++;
  return 0;
}
ESP32 S2 ULP experts, anyone?

timokett
Posts: 7
Joined: Thu Jun 17, 2021 11:19 am

Re: ESP32-S2 ULP cannot control GPIO output

Postby timokett » Thu Jan 27, 2022 5:53 pm

SOLVED!

It appears that for GPIO output the main processor gpio setup calls have no impact. Everything can be done on ULP side. Only thing that is needed is call esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_ON) on the main processor.
The traps were caused by trying to set output without enabling it. The gpio_init is needed only once but enabling output has to be done for every new call of the ULP main.
Below is modified version of app_main and ulp main code that works.

Code: Select all

void app_main(void) {

  esp_sleep_wakeup_cause_t cause = esp_sleep_get_wakeup_cause();
  if (cause != ESP_SLEEP_WAKEUP_ULP) {
    printf("Not a ULP-RISC-V wakeup, cause = %d, initializing it! \n", cause);
    init_ulp_program();
  }
  if (cause == ESP_SLEEP_WAKEUP_ULP) {
    printf("ULP-RISC-V woke up the main CPU! \n");
  }
  printf("Entering in deep sleep\n\n");
  vTaskDelay(100);

  esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_ON);
  ESP_ERROR_CHECK(esp_sleep_enable_ulp_wakeup());
  esp_deep_sleep_start();
}
ULP:

Code: Select all

#define pin GPIO_NUM_2

int main(void) {
  static int count = 0;

  if (count == 0) {
    example_ulp_gpio_init(pin);
    // do nothing, main process is not yet in sleep
  } else {
    example_ulp_gpio_output_enable(pin);
    if (count > 0 && count <= 10) {
      example_ulp_gpio_output_level(pin, 0);
    } else if (count > 10 && count <= 20) {
      example_ulp_gpio_output_level(pin, 1);
    } else if (count > 20 && count < 30) {
      example_ulp_gpio_output_level(pin, 0);
    } else if (count >= 30) {
      count = 0;
      ulp_riscv_wakeup_main_processor();
    }
  }
  count++;
  return 0;
}

Who is online

Users browsing this forum: No registered users and 80 guests