ESP32-S3 ULP strange behaviour

ULP_User
Posts: 2
Joined: Thu Jun 13, 2024 8:04 am

ESP32-S3 ULP strange behaviour

Postby ULP_User » Thu Jun 13, 2024 9:03 am

Hi,

I made a very simple ULP (RISC-V) test program for an ESP32-S3 module (ESP32-S3-WROOM-1) on a lilygo T7-S3 board.
I'm using the latest ESP-IDF 5.2.2. My test program is based on the "examples\system\ulp\ulp_riscv\gpio"-example, so take the configuration from there.
The problem is that the function ulp_riscv_delay_cycles() does not work reliable. Most of the time it works, but sometimes it seems not to delay at all.
In my simple test program the ESP32 Cycles and the ULP Cycles should stay in sync all the time. But this does not happen, have a look at this log:

I (237815) ULP-I2C: ESP32 Cycles: 241 ULP Cycles: 241
I (238815) ULP-I2C: ESP32 Cycles: 242 ULP Cycles: 242
I (239815) ULP-I2C: ESP32 Cycles: 243 ULP Cycles: 243
I (240815) ULP-I2C: ESP32 Cycles: 244 ULP Cycles: 244
I (241715) ULP-I2C: ESP32 Cycles: 245 ULP Cycles: 245
I (242715) ULP-I2C: ESP32 Cycles: 246 ULP Cycles: 2950
I (242815) ULP-I2C: ESP32 Cycles: 247 ULP Cycles: 19586
I (242915) ULP-I2C: ESP32 Cycles: 248 ULP Cycles: 36222
I (243015) ULP-I2C: ESP32 Cycles: 249 ULP Cycles: 52857
I (243115) ULP-I2C: ESP32 Cycles: 250 ULP Cycles: 69492
I (243215) ULP-I2C: ESP32 Cycles: 251 ULP Cycles: 70173
I (244115) ULP-I2C: ESP32 Cycles: 252 ULP Cycles: 70174
I (245115) ULP-I2C: ESP32 Cycles: 253 ULP Cycles: 70175
I (246115) ULP-I2C: ESP32 Cycles: 254 ULP Cycles: 70176

So this simple test should not fail at all. Sometimes the ULP gets totally stuck and the board LED does not blink anymore. I can't see any reason in this simple test why this should happen. Any suggestions?

And another oddness is the start of the ULP program: When started from vscode ("Monitor device" or "Build, Flash and Monitor") the ULP does not start at all (no error code in ulp_riscv_run()). But a hardware reset or power cycle does start the ULP as expected.

ESP32-Program code:

Code: Select all

#include <stdio.h>
#include "esp_sleep.h"
#include "soc/rtc_cntl_reg.h"
#include "soc/sens_reg.h"
#include "soc/rtc_periph.h"
#include "driver/gpio.h"
#include "driver/rtc_io.h"
#include "ulp_riscv.h"
#include "ulp_main.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_log.h"

extern const uint8_t ulp_main_bin_start[] asm("_binary_ulp_main_bin_start");
extern const uint8_t ulp_main_bin_end[] asm("_binary_ulp_main_bin_end");

static void init_ulp_program(void);

#define TAG "ULP-Test"

void app_main(void)
{
  ESP_LOGI(TAG, "Starting ESP32-S3 ULP test");

    ESP_LOGI(TAG, "Starting ULP program...");
    init_ulp_program();

  ESP_LOGI(TAG, "Waiting for ULP data...");
  uint32_t Cycles=0;
  for (;;)
  {
    if (ulp_DataReady)
    {
      Cycles++;
      ulp_DataReady = 0;
      ESP_LOGI(TAG, "ESP32 Cycles: %lu ULP Cycles: %lu", Cycles, ulp_Cycles);
    }
    vTaskDelay(100 / portTICK_PERIOD_MS);
  }
}

static void init_ulp_program(void)
{
  esp_err_t err = ulp_riscv_load_binary(ulp_main_bin_start, (ulp_main_bin_end - ulp_main_bin_start));
  ESP_ERROR_CHECK(err);

  /* The first argument is the period index, which is not used by the ULP-RISC-V timer
   * The second argument is the period in microseconds, which gives a wakeup time period of: 20ms
   */
  ulp_set_wakeup_period(0, 20000);

  /* Start the program */
  err = ulp_riscv_run();
  ESP_ERROR_CHECK(err);
}
ULP-code:

Code: Select all

#include <stdio.h>
#include <stdint.h>
#include <stdbool.h>
#include "ulp_riscv.h"
#include "ulp_riscv_utils.h"
#include "ulp_riscv_gpio.h"
#include "esp_err.h"

#define BOARD_LED GPIO_NUM_17

/* this variable will be exported as a public symbol, visible from main CPU: */

uint32_t DataReady = 0;
uint32_t Cycles = 0;

int main(void)
{
  DataReady=false;
  ulp_riscv_gpio_init(BOARD_LED);
  ulp_riscv_gpio_output_enable(BOARD_LED);
  ulp_riscv_gpio_set_output_mode(BOARD_LED, RTCIO_MODE_OUTPUT);

  int flag = 0;
  for (;;)
  {
    flag = 1 - flag;
    ulp_riscv_gpio_output_level(GPIO_NUM_17, flag);
    Cycles++;
    DataReady = 1;
    ulp_riscv_delay_cycles(1000000 * ULP_RISCV_CYCLES_PER_US); // 1s Pause
  }
  /* ulp_riscv_halt() is called automatically when main exits */
  return 0;
}

ULP_User
Posts: 2
Joined: Thu Jun 13, 2024 8:04 am

Re: ESP32-S3 ULP strange behaviour

Postby ULP_User » Fri Jun 14, 2024 6:12 am

So, I'll answer this question by myself:

The problem is the ulp_riscv_delay_cycles function:

Code: Select all

void static inline ulp_riscv_delay_cycles(uint32_t cycles)
{
    uint32_t start = ULP_RISCV_GET_CCOUNT();
	/* Off with an estimate of cycles in this function to improve accuracy */
    uint32_t end = start + cycles - 20;

    while (ULP_RISCV_GET_CCOUNT()  < end) {
        /* Wait */
    }
}
It doesn't pay attention to uint32_t underflow and overflow conditions. The system counter runs with 17.5 MHz and will overflow every 245 s (look at my log, the 1-s-counter starts to run wild at 245). As a consequence, the delay function fails every time the counter overflows. And even worse, if the term "start + cycles - 20" gets negative, the function may wait up to 245 s instead of a few cycles (this is what I've seen two times. The ULP does not stop at all, it waits 245 s in this busy loop.
Maybe this kind of failure is hard to see because the ULP does not run that long and so it doesn't overflow, but the function should be fixed.
In the meantime, readers should use this header:

Code: Select all

#pragma once

#ifdef __cplusplus
extern "C" {
#endif

#include "sdkconfig.h"
#include <stdint.h>
#include "ulp_riscv_utils.h"

void static inline delay(uint32_t cycles)
{
  uint32_t mark = ULP_RISCV_GET_CCOUNT();
  uint32_t interval;
  do
  {
    interval = ULP_RISCV_GET_CCOUNT() - mark; // underflow is well defined
  } while (interval < cycles);
}

#ifdef __cplusplus
}
#endif

Even without subtracting the 20 cycles it is pretty precise and it will always work.

But it would be nice, if someone had an idea why the ULP is not starting when using the monitor command in vscode.

Bye,
Oliver

MicroController
Posts: 1701
Joined: Mon Oct 17, 2022 7:38 pm
Location: Europe, Germany

Re: ESP32-S3 ULP strange behaviour

Postby MicroController » Sun Jun 16, 2024 6:40 pm

ULP_User wrote:
Fri Jun 14, 2024 6:12 am
The problem is the ulp_riscv_delay_cycles function:
...
Thanks for sharing that info.
Additionally, you could create an issue and report this bug so that it can be fixed in the IDF.

Who is online

Users browsing this forum: No registered users and 134 guests