ULP_RISCV on ESP32S2 doesn't wake up after first run

scottsh
Posts: 12
Joined: Wed Dec 09, 2020 6:58 am

ULP_RISCV on ESP32S2 doesn't wake up after first run

Postby scottsh » Sun Dec 13, 2020 6:36 pm

Starting with the ULP_RISCV example, I am trying to get the ULP_RISCV to run more than once.

For reference, I am using ESP-IDF master at commit 178b122c145c19e94ac896197a3a4a9d379cd618.

My understanding of how this is supposed to work is that after the ulp main exits, start.S calls ulp_riscv_shutdown, which sets the power off delay then sets the two registers in order to shutdown and reset the ULP. After that timer expires, the ULP should start again and run main(). However, what I am seeing is that main() only runs once, and never wakes up again.

For reference, her is the trivial example I put together to demonstrate the problem:
Here's the main code for the main CPU:

Code: Select all

#include <stdio.h>
#include "soc/rtc_cntl_reg.h"
#include "esp32s2/ulp.h"
#include "esp32s2/ulp_riscv.h"
#include "ulp_main.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.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);

void app_main(void)
{
    init_ulp_program();

    while(1) {
        printf("ulp_testval=%d\n", ulp_testval);
        vTaskDelay(100 / portTICK_RATE_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);
}
And here's the code for the RISCV:

Code: Select all

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

int testval = 8;

int main (void)
{
    testval++;

    /* ulp_riscv_shutdown() is called automatically when main exits */
    return 0;
}
Here's the output when it runs:

Code: Select all

ESP-ROM:esp32s2-rc4-20191025
Build:Oct 25 2019
rst:0x1 (POWERON),boot:0x8 (SPI_FAST_FLASH_BOOT)
SPIWP:0xee
mode:DIO, clock div:1
load:0x3ffe6100,len:0x8
load:0x3ffe6108,len:0x12a8
load:0x4004c000,len:0x8c4
load:0x40050000,len:0x2c34
entry 0x4004c1a8
W (138) spi_flash: Detected size(4096k) larger than the size in the binary image header(2048k). Using the size in the binary image header.
ulp_testval=8
ulp_testval=9
ulp_testval=9
ulp_testval=9
ulp_testval=9
ulp_testval=9
ulp_testval=9
ulp_testval=9
ulp_testval=9
ulp_testval=9
ulp_testval=9
ulp_testval=9
ulp_testval=9
ulp_testval=9
ulp_testval=9
ulp_testval=9
What I expect is the value of ulp_testval to go up by ~5 every time it prints, since the ulp wake up is set to 20ms, and the delay between prints in the main cpu is 100ms. However, the code in the ULP runs once then never launches again.

When I decoded the value of RTC_CNTL_COCPU_CTRL_REG=0x24FC810 (I was printing it in the loop from the main CPU), I get the following:

Code: Select all

RTC_CNTL_COCPU_CLK_FO                   0
RTC_CNTL_COCPU_START_2_RESET_DIS        001000
RTC_CNTL_COCPU_START_2_INTR_EN          010000
RTC_CNTL_COCPU_SHUT                     0
RTC_CNTL_COCPU_SHUT_2_CLK_DIS           00111111    = 3F
RTC_CNTL_COCPU_SHUT_RESET_EN            1
RTC_CNTL_COCPU_SEL                      0           = RISCV
RTC_CNTL_COCPU_DONE_FORCE               0
RTC_CNTL_COCPU_DONE                     0
RTC_CNTL_COCPU_SW_INT_TRIGGER           1
RTC_CNTL_COCPU_CLKGATE_EN               0
Which shows the COCPU_2_CLK_DIS and and SHUT_RESET_EN values that are set in ulp_riscv_shutdown, but COCPU_DONE is 0, even though it was set to 1 in ulp_riscv_shutdown, and RTC_CNTL_COCPU_SW_INT_TRIGGER=1, which no one set, so I assume that means that the RISCV CPU saw a software interrupt of some sort, but I can't find any documentation that references that flag.

(I can send a zip of the whole repro example. I didn't see a way to attach the file.)

Any ideas? What am I doing wrong?

Thanks,

- Scott

scottsh
Posts: 12
Joined: Wed Dec 09, 2020 6:58 am

Re: ULP_RISCV on ESP32S2 doesn't wake up after first run

Postby scottsh » Sun Dec 13, 2020 8:56 pm

Found it...

Looks like there is a missing step in ulp_riscv_shutdown. I added the following to main

Code: Select all

    /* Setting the delay time after RISCV recv `DONE` signal, Ensure that action `RESET` can be executed in time. */
    REG_SET_FIELD(RTC_CNTL_COCPU_CTRL_REG, RTC_CNTL_COCPU_SHUT_2_CLK_DIS, 0x3F);

    SET_PERI_REG_MASK(RTC_CNTL_COCPU_CTRL_REG, RTC_CNTL_COCPU_DONE_FORCE);

    /* suspends the ulp operation*/
    SET_PERI_REG_MASK(RTC_CNTL_COCPU_CTRL_REG, RTC_CNTL_COCPU_DONE);

    /* Resets the processor */
    SET_PERI_REG_MASK(RTC_CNTL_COCPU_CTRL_REG, RTC_CNTL_COCPU_SHUT_RESET_EN);
It looks like you have to set the COCPU_DONE_FORCE bit to 1 to make the COCPU_DONE signal go to the RISCV instead of the ULP FSM.

I'll send a PR to add that line to ulp_riscv_shutdown.

Thanks,

- Scott

boarchuz
Posts: 566
Joined: Tue Aug 21, 2018 5:28 am

Re: ULP_RISCV on ESP32S2 doesn't wake up after first run

Postby boarchuz » Mon Dec 14, 2020 2:57 am

Related:
https://github.com/espressif/esp-idf/issues/6069

Maybe set this bit once (eg. in ulp_riscv_run)?

felmue
Posts: 69
Joined: Mon Nov 16, 2020 2:55 pm

Re: ULP_RISCV on ESP32S2 doesn't wake up after first run

Postby felmue » Mon Dec 14, 2020 8:59 pm

Hello Scott

nice find. Thank you for sharing this information. I appreciate it.

Thanks
Felix

Who is online

Users browsing this forum: Bing [Bot], Google [Bot] and 189 guests