ULP pulse counting problem
Posted: 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:
The enum for locations is:
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.
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
}
Code: Select all
enum {
WIND_COUNT,
RAIN_COUNT,
WIND_LAST,
RAIN_LAST,
SLOW_PROG_ADDR // Program start address
};
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.