boarchuz / HULP

ESP32 ULP Coprocessor Helper
MIT License
185 stars 20 forks source link

Variable gets a value as if the shift command had not been executed #18

Closed freetoair closed 2 years ago

freetoair commented 2 years ago

This is my simple program in the infinite loop that only measures the voltage from the mains and saves the value in the variable ulp_vars.pin2.val. The problem is that at some undefined intervals but certainly under one second this variable gets a value as if the shift command had not been executed. This is a simplified example from the HULP library, and in that original example, I didn't notice anything like this happening. Does anyone have any idea why this is happening?



#define PIN_ADC_PIN2    GPIO_NUM_34

#define PIN2_OVERSAMPLE_SHIFT 3

RTC_DATA_ATTR struct {
  ulp_var_t pin2;
} ulp_vars;

void ulp_init()
{
  enum {
    LBL_PIN2_OVERSAMPLE_LOOP,
    LBL_LOOP,
  };

  const ulp_insn_t program[] = {

    M_LABEL(LBL_LOOP),
    I_STAGE_RST(),//
    I_MOVI(R0, 0),//These are just attempts to solve the problem.
    I_MOVI(R1, 0),//
    I_MOVI(R2, 0),//
    I_MOVI(R3, 0),
    M_LABEL(LBL_PIN2_OVERSAMPLE_LOOP),
    I_ANALOG_READ(R1, PIN_ADC_PIN2),
    I_ADDR(R0, R0, R1),
    I_STAGE_INC(1),
    M_BSLT(LBL_PIN2_OVERSAMPLE_LOOP, (1 << PIN2_OVERSAMPLE_SHIFT)),
    I_RSHI(R0, R0, PIN2_OVERSAMPLE_SHIFT),
    I_MOVI(R3, 0),
    I_PUT(R0, R3, ulp_vars.pin2),
    I_GPIO_SET(GPIO_NUM_14, 1),//This produces 1.43 uS pulse
    I_GPIO_SET(GPIO_NUM_14, 0),// for test, nothing else !
    I_DELAY(10),
    I_BXI(LBL_LOOP),

  };
  ESP_ERROR_CHECK(hulp_configure_pin(GPIO_NUM_14, RTC_GPIO_MODE_OUTPUT_ONLY, GPIO_FLOATING, 1));
  ESP_ERROR_CHECK(hulp_configure_analog_pin(PIN_ADC_PIN2, ADC_ATTEN_DB_11, ADC_WIDTH_BIT_12));
  //ESP_ERROR_CHECK(hulp_ulp_load(program, sizeof(program), 1000UL * ULP_WAKEUP_INTERVAL_MS, 0));
  size_t size = sizeof(program) / sizeof(ulp_insn_t);
  ESP_ERROR_CHECK(ulp_process_macros_and_load(0, program, &size));
  ESP_ERROR_CHECK(hulp_ulp_run(0));
}

void setup()
{
  Serial.begin(115200);
  if (hulp_is_deep_sleep_wakeup())
  {
    Serial.print("Wakeup !");
  }
  else
  {
    ulp_init();
  }
}

void loop() {
  Serial.println(ulp_vars.pin2.val);
}```
freetoair commented 2 years ago

Solved. If you need an infinite loop in the ULP program at the beginning of the program add: I_WR_REG_BIT (RTC_CNTL_STATE0_REG, RTC_CNTL_ULP_CP_SLP_TIMER_EN, 0)

and so you forbade the influence of the start timer on the flow of the program!

boarchuz commented 2 years ago

Hi @freetoair, The problem might be here: I_BXI(LBL_LOOP) That inadvertently means jump to PC 1, causing I_STAGE_RST() to be skipped. Use M_BX with labels: M_BX(LBL_LOOP)

I_WR_REG_BIT (RTC_CNTL_STATE0_REG, RTC_CNTL_ULP_CP_SLP_TIMER_EN, 0)

This doesn't look right, the macro expects the shift (RTC_CNTL_ULP_CP_SLP_TIMER_EN_S), not a mask. In practice, RTC_CNTL_ULP_CP_SLP_TIMER_EN == BIT(24) which is probably going to be truncated to 0, so the instruction means to clear bit 0. I suggest using I_END() instead, although the ULP sleep timer is irrelevant in an infinite loop.

freetoair commented 2 years ago

It's okay now, thanks for the analysis. When I replaced I_BXI with M_BX it works normally and without I_END. The sampling frequency is a maximum 12.75 kHz which is more than enough.

regards.

freetoair commented 2 years ago

Hi @boarchuz, I forgot to congratulate you on a great job with this library. I would have one suggestion if it is possible to add a macro that would simulate PUSH and POP commands for any form of stack work. I know that in this case it would not be the right PUSH and POP commands in terms of speed, but it would help make the program easier to follow and understand.

regards.