boarchuz / HULP

ESP32 ULP Coprocessor Helper
MIT License
180 stars 18 forks source link

Issue with Sleep of ULP #4

Closed Ankith-A-Muralidhar closed 3 years ago

Ankith-A-Muralidhar commented 3 years ago

I came across this issue where the ULP does not go to sleep for the requested time. I used the M_SET_WAKEUP_PERIOD instruction to set the register index 1 to one minute( in micro seconds). And then selected the sleep cycle using I_SLEEP_CYCLE_SEL(1). But the ULP does not sleep for 1 min after the I_HALT and before rerunning the code. Here is the Code:

const ulp_insn_t program[] = { M_SET_WAKEUP_PERIOD (1, 60000000), I_SLEEP_CYCLE_SEL(1), I_I2C_READ(0, SLAVE_SUBADDR), // Reading a data from a slave I_MOVI(R2,0), I_PUT(R0, R2, data), };

Any help would be appreciated!

sagar448 commented 3 years ago

I am also facing this issue @boarchuz Thanks for the help

Jigar3690 commented 3 years ago

I am also facing this issue. I hope someone will have some way to look at it. Thank you.

boarchuz commented 3 years ago

Try calling hulp_peripherals_on() any time before entering sleep. Also ensure your program ends with a halt instruction.

Ankith-A-Muralidhar commented 3 years ago

Try calling hulp_peripherals_on() any time before entering sleep. Also ensure your program ends with a halt instruction.

I tried it. still the issue persisits.

boarchuz commented 3 years ago

Hi @Ankith-A-Muralidhar , This is working as expected for me:

#include "esp_sleep.h"

#include "hulp.h"

#define PIN_LED GPIO_NUM_25

void init_ulp()
{
    enum {
        LBL_SET_1MIN,
        LBL_SET_1SEC,
    };

    const ulp_insn_t program[] = {
        M_GPIO_TOGGLE(PIN_LED),
        M_BGE(LBL_SET_1SEC, 1),

        M_LABEL(LBL_SET_1MIN),
            M_SET_WAKEUP_PERIOD(1, 60000000),
            I_SLEEP_CYCLE_SEL(1),
            I_HALT(),

        M_LABEL(LBL_SET_1SEC),
            M_SET_WAKEUP_PERIOD(1,  5000000),
            I_SLEEP_CYCLE_SEL(1),
            I_HALT(),
    };

    hulp_configure_pin(PIN_LED, RTC_GPIO_MODE_OUTPUT_ONLY, GPIO_FLOATING, 0);

    hulp_ulp_load(program, sizeof(program), 12345678); // The time value here doesn't matter, ULP will set its own

    hulp_ulp_run();
}

extern "C" void app_main()
{
    init_ulp();
    hulp_peripherals_on();
    esp_deep_sleep_start();
}

The likely culprit at this point is that I2C transaction. If the bus is misconfigured or in an error-state (eg. slave holding a pin low) then the ULP can and will lock up on that instruction.

Ankith-A-Muralidhar commented 3 years ago

So this is what is happening. If I send the esp to deep sleep, it doesn't wake up even after calling I_WAKE() in the ulp program. Else the same issue, doesn't wait for the timer, just keeps running. So if you have any insights to this problem, please let me know. Thank you for your help!

boarchuz commented 3 years ago

With my code above? Or some other program?

Can you share your code here?

Ankith-A-Muralidhar commented 3 years ago

The program I am running. Here is the program

include "sdkconfig.h"

include "freertos/FreeRTOS.h"

include "freertos/task.h"

include "driver/rtc_io.h"

include "driver/gpio.h"

include "soc/rtc.h"

include "hulp.h"

include <sys/time.h>

include

include "esp_sleep.h"

//adc for the new esp32

include "driver/adc.h"

define ULP_WAKEUP_INTERVAL_MS 1000

//SCL = 2 or 4

define SCL_PIN GPIO_NUM_4

//SDA = 0 or 15

define SDA_PIN GPIO_NUM_15

define SLAVE1_ADDR 0x76

define SLAVE1_SUBADDR1 0x1D

define SLAVE1_SUBADDR5 0x74

RTC_DATA_ATTR ulp_var_t Check;

void init_ulp() { const ulp_insn_t program[] = { I_WAKE(), I_MOVI(R2, 0), I_I2C_WRITE(0, SLAVE1_SUBADDR5, 0x14), I_I2C_READ(0, SLAVE1_SUBADDR1), I_MOVR(R1, R0), I_PUT(R1,R2,check), M_SET_WAKEUP_PERIOD (1, 60000000), I_SLEEP_CYCLE_SEL(1), I_HALT(), }; hulp_register_i2c_slave(0, SLAVE1_ADDR); hulp_configure_i2c_pins(SCL_PIN, SDA_PIN); hulp_configure_i2c_controller(); vTaskDelay(1000 / portTICK_PERIOD_MS); hulp_ulp_load(program, sizeof(program), ULP_WAKEUP_INTERVAL_MS * 1000); hulp_ulp_run(); } extern "C" void app_main() { init_ulp(); hulp_peripherals_on(); printf("Check data: %u\n", Check.val); vTaskDelay(1000 / portTICK_PERIOD_MS); esp_deep_sleep_start(); }

The few header files are extra because I need them to do the next parts. I also tried I_WAKE(), before the I_HALT(). I also put the printf statement in the for loop. If I put it inside the for loop and no deepsleep, then it keeps running but if I add the deepsleep, then it runs once and doesn't wake up. same when it is outside the for loop as well.

boarchuz commented 3 years ago

Don't forget to enable ULP wakeup: esp_sleep_enable_ulp_wakeup()

Ankith-A-Muralidhar commented 3 years ago

I had done that too, same result as before.

boarchuz commented 3 years ago

I've had a look at this today and the issue seems to be with hulp_configure_i2c_pins, especially in open-drain configuration (with push-pull configuration I can see the ESP32 transmission on my oscilloscope, but there's nothing in open-drain).

You might consider using HULP's I2C bitbanging stuff (which I highly recommend). Note that if there is ever an issue with hardware I2C in the field (eg. slave fault causes SDA or SCL to be low), it can and most likely will lock up your ULP just like this.

I'll try find a fix later this week.

boarchuz commented 3 years ago

@Ankith-A-Muralidhar I just pushed a change to the pin init which will hopefully be more reliable. ULP I2C works fine for me now.