ULP pulse counting problem

Sanazzy
Posts: 2
Joined: Wed Oct 23, 2024 4:06 pm

ULP pulse counting problem

Postby Sanazzy » Wed Oct 23, 2024 4:38 pm

I've some kind of problem in my C macro ULP program for pulse counting where seemingly I'm not counting pulses. It's entirely possible that I'm reading / writing to wrong registers or RCT memory, or perhaps something else. Every time I read the RTC memory, both counters (and last-state) are zero.

It looks like this:

Code: Select all

const ulp_insn_t ulp_program[] = {
  I_MOVI(R1, 0),  // R1 <- 0 (previous state, assume LOW initially)
  I_MOVI(R2, 0),  // R2 <- 0 (previous state, assume LOW initially)
  I_MOVI(R3, 0),  // R3 <- 0 (reset the transition counter)
  
  // Main loop
  M_LABEL(1),
  
  // Read previous state
  I_MOVI(R1, WIND_LAST),  // Set R1 to address
  I_LD(R2, R1, 0 ),       // Read previous state from RTC_SLOW_MEM into R2

  // Read wind pulse sensor
  I_RD_REG(RTC_GPIO_IN_REG, rtc_io_number_get(WIND_PIN) + RTC_GPIO_IN_NEXT_S, rtc_io_number_get(WIND_PIN) + RTC_GPIO_IN_NEXT_S),

  // Save the current state in a temporary register (R1)
  I_MOVR(R1, R0),       // R1 <- R0 (store current GPIO state temporarily)

  // Compare current state (R1) with previous state (R2)
  I_SUBR(R0, R1, R2),     // R0 = current state (R1) - previous state (R2)
  I_BL(8, 1),             // If R0 == 0 (no state change), skip instructions
  I_MOVI(R1, WIND_COUNT), // Set R1 to address for wind counter RTC_SLOW_MEM
  I_LD(R3, R1, 0 ),       // Read last counter into R3
  I_ADDI(R3, R3, 1),      // Increment R3 by 1 (transition detected)

  // Store the transition counter
  I_MOVI(R1, WIND_COUNT),   // Set R1 to address RTC_SLOW_MEM
  I_ST(R3, R1, 0 ),         // Store counter in RTC_SLOW_MEM

  // Store current state
  I_MOVI(R1, WIND_LAST),   // Set R1 to address RTC_SLOW_MEM
  I_ST(R0, R1, 0 ),         // Store last state in RTC_SLOW_MEM

  // Read previous rain state
  I_MOVI(R1, RAIN_LAST),  // Set R1 to address
  I_LD(R2, R1, 0 ),       // Read previous state from RTC_SLOW_MEM into R2

  // Read rain sensor
  I_RD_REG(RTC_GPIO_IN_REG, rtc_io_number_get(RAIN_PIN) + RTC_GPIO_IN_NEXT_S, rtc_io_number_get(RAIN_PIN) + RTC_GPIO_IN_NEXT_S),

  // Save the current state in a temporary register (R1)
  I_MOVR(R1, R0),  // R1 <- R0 (store current GPIO state temporarily)

  // Compare current state (R1) with previous state (R2)
  I_SUBR(R0, R1, R2),     // R0 = current state (R1) - previous state (R2)
  I_BL(8, 1),             // If R0 == 0 (no state change), skip instructions
  I_MOVI(R1, RAIN_COUNT), // Set R1 to address for rain counter RTC_SLOW_MEM
  I_ADDI(R3, R3, 1),      // Increment R3 by 1 (transition detected)
  I_MOVR(R2, R1),         // R2 <- R1 (store the current state for the next iteration)

  // Store the transition counter
  I_MOVI(R1, RAIN_COUNT),  // Set R1 to address RTC_SLOW_MEM
  I_ST(R3, R1, 0),         // Store it in RTC_SLOW_MEM

  // Store current state
  I_MOVI(R1, RAIN_LAST),   // Set R1 to address RTC_SLOW_MEM
  I_ST(R0, R1, 0 ),         // Store it in RTC_SLOW_MEM

  // RTC clock on the ESP32-S3 is 17.5MHz, delay 0xFFFF = 3.74 ms
  I_DELAY(0xFFFF),  // debounce

  M_BX(1),  // Loop back to label 1
};

void init_ulp_program() {
  memset(RTC_SLOW_MEM, 0, CONFIG_ULP_COPROC_RESERVE_MEM);  // set to zeros, optional

  // Check size while loading program
  size_t size = sizeof(ulp_program) / sizeof(ulp_insn_t);
  esp_err_t err = ulp_process_macros_and_load(SLOW_PROG_ADDR, ulp_program, &size);  // offset by PROG_ADDR

  if (err == ESP_OK) {
    Serial.println("ULP program loaded successfully.");
  } 
  else if (err == ESP_ERR_NO_MEM) {
    Serial.println("Error: Not enough memory to load ULP program.");
  } 
  else {
    Serial.printf("Error: ULP program load returned unexpected error %d\n", err);
  }

  // init GPIO for ULP to monitor
  rtc_gpio_init( WIND_PIN );
  rtc_gpio_init( RAIN_PIN );
  rtc_gpio_set_direction( WIND_PIN, RTC_GPIO_MODE_INPUT_ONLY );
  rtc_gpio_set_direction( RAIN_PIN, RTC_GPIO_MODE_INPUT_ONLY );
  rtc_gpio_pullup_dis( WIND_PIN );     // disable the pull-up resistor
  rtc_gpio_pullup_dis( RAIN_PIN );     // disable the pull-up resistor
  rtc_gpio_pulldown_dis( WIND_PIN );  // disable the pull-down resistor
  rtc_gpio_pulldown_dis( RAIN_PIN );  // disable the pull-down resistor
  rtc_gpio_hold_dis( WIND_PIN );       // required to maintain pull-up
  rtc_gpio_hold_dis( RAIN_PIN );       // required to maintain pull-up
}
The enum for locations is:

Code: Select all

enum {
  WIND_COUNT,
  RAIN_COUNT,
  WIND_LAST,
  RAIN_LAST,
  SLOW_PROG_ADDR  // Program start address
};
The example this is based on is only pulse counting a single input, and writing to a single memory location. While I understand basic operations, understanding of the RTC memory locations and RTC GPIOs elude me. I can see the program appears to load and run, but beyond that I'm unsure.

Using the NodeMCU ESP32S board, I'm reading from GPIOs 25 and 26. I note that the pinout diagram for this board shows different RTC GPIO numbers for pins GPIO25 and GPIO26, though I assume rtc_io_number_get() returns the correct values.

Reading these same inputs outside of the ULP program in a loop works as expected.

Any pointers would really be appreciated. Can provide the rest of the code as needed.

Who is online

Users browsing this forum: Google [Bot] and 69 guests