Closed laguill closed 3 years ago
Isn't this a digital signal? Have a look at examples/Interrupt or use simple polling (I_GPIO_READ).
ulp_init;
-> ulp_init();
Thank you I'm not sure of how the pin is configure and I have some error in counting with some false trigger if it is to fast. How I can improve it ?
Here my code again
`#include "hulp_arduino.h"
int TIME_TO_SLEEP = 60; //Time EPS32 will go to sleep in seconds
RTC_DATA_ATTR ulp_var_t counter_pluv;
void ulp_init(){ enum { LBL_PIN_PLUV_TRIGGERED, //This labels are use as if function LBL_HALT, }; const ulp_insn_t program[] = { //ULP I_MOVI(R1,0), //Copy an immediate value into register: R1 I_GPIO_READ(PIN_PLUV), //If it's set, goto LAB_PIN_PLUV_TRIGGERED M_BGE(LBL_PIN_PLUV_TRIGGERED, 1), //Else HALT I_HALT(), //Halt the coprocessor but keeps ULP timer active // M_LABEL(LBL_PIN_PLUV_TRIGGERED), //increment counter if PIN_PLUV TRIGGERED I_GET(R0,R1, counter_pluv), //Load value from RTC memory into reg_dest register. I_ADDI(R0,R0,1), //R0++ I_PUT(R0,R1, counter_pluv), //Load value from reg_dest register to RTC memory. M_WAKE_WHEN_READY(), I_HALT(),
}; //Pin configuration hulp_peripherals_on(); hulp_configure_pin(PIN_PLUV, RTC_GPIO_MODE_INPUT_ONLY, GPIO_PULLUP_ONLY, 0); hulp_configure_pin_int(PIN_PLUV, GPIO_INTR_ANYEDGE); ESP_ERROR_CHECK(hulp_ulp_load(program, sizeof(program), 1000UL * ULP_WAKEUP_INTERVAL_MS, 0)); ESP_ERROR_CHECK(hulp_ulp_run(0));
}
void sleep (){ Serial.println("Going to sleep for "+ String(TIME_TO_SLEEP) + " seconds"); esp_sleep_enable_timer_wakeup(TIME_TO_SLEEP * 1000000UL); delay(100); Serial.flush(); esp_sleep_enable_ulp_wakeup(); //This is for debugging esp_deep_sleep_start(); } void setup() { // put your setup code here, to run once: Serial.begin(115200); Serial.println("Program is starting"); ulp_init();
Serial.println("Pluv counter = " + String(counter_pluv.val)); counter_pluv.val = 0; sleep();
}
void loop() { }`
The ULP is sleeping for 250ms. If you're releasing the switch within 250ms, it's possible to miss the activation (pin will be pulled down again by the time the ULP wakes and reads level).
You can decrease ULP sleep time, or have a look at examples/Interrupt to capture changes while the ULP is sleeping.
Thank you i followed you exemples and now there is no false trigger with a debounce time of 75ms However now I'm triing to share data with SoC following your exemple but I get the error 'union ulp_var_t' has no member named 'get'
Can you help ?
`#include "hulp_arduino.h"
int TIME_TO_SLEEP = 10; //Time EPS32 will go to sleep in seconds
RTC_DATA_ATTR ulp_var_t counter_pluv; float pluviometre = 0;
void ulp_init(){ enum { LBL_PIN_PLUV_TRIGGERED, //This labels are use as if function
}; const ulp_insn_t program[] = { //ULP I_MOVI(R1,0), //Copy an immediate value into register: R1 I_GPIO_READ(PIN_PLUV), //If it's set, goto LAB_PIN_PLUV_TRIGGERED M_BGE(LBL_PIN_PLUV_TRIGGERED, 1), //Else HALT I_HALT(), //Halt the coprocessor but keeps ULP timer active // M_LABEL(LBL_PIN_PLUV_TRIGGERED), //increment counter if PIN_PLUV TRIGGERED I_GET(R0,R1, counter_pluv), //Load value from RTC memory into reg_dest register. I_ADDI(R0,R0,1), //R0++ I_PUT(R0,R1, counter_pluv), //Load value from reg_dest register to RTC memory. M_WAKE_WHEN_READY(), I_HALT(),
}; //Pin configuration hulp_peripherals_on(); hulp_configure_pin(PIN_PLUV, RTC_GPIO_MODE_INPUT_ONLY, GPIO_PULLDOWN_ONLY, 0); ESP_ERROR_CHECK(hulp_configure_pin_int(PIN_PLUV, GPIO_INTR_ANYEDGE)); ESP_ERROR_CHECK(hulp_ulp_load(program, sizeof(program), 1000UL * ULP_WAKEUP_INTERVAL_MS, 0)); ESP_ERROR_CHECK(hulp_ulp_run(0));
}
void sleep (){ Serial.println("Going to sleep for "+ String(TIME_TO_SLEEP) + " seconds"); esp_sleep_enable_timer_wakeup(TIME_TO_SLEEP * 1000000UL); delay(100); Serial.flush(); //esp_sleep_enable_ulp_wakeup(); //This is for debugging esp_deep_sleep_start(); }
void Pluviometre(){ pluviometre = counter_pluv.get(); if(pluviometre != 0){ pluviometre = counter_pluv.val * 0.2794; counter_pluv.val = 0; } counter_pluv.val = 0;
}
void setup() { // put your setup code here, to run once: Serial.begin(115200); Serial.println("Program is starting"); ulp_init(); Serial.println("counter = " + String(counter_pluv.val)); Pluviometre(); Serial.println("Pluv counter = " + String(pluviometre) + " mm"); sleep();
}
void loop() { }`
get() and other member functions don't exist any more, sorry (I'm aware there are still some obsolete references to it).
ulp_var_t is a simple struct, you can access the value using counter_pluv.val
Thank you again it is working now.
I created a repo. I am new on github and I don't want to appropriate myself your work. Please feel free to tell me if something is wrong
Now I am triing to build an anemometer and I am looking at you ADC exemple because I need to make a LSR on the counter to divide it by two.
Can you tell me what are this two lines used for
I_STAGE_INC(1), M_BSLT(LBL_PIN2_OVERSAMPLE_LOOP, (1 << PIN2_OVERSAMPLE_SHIFT)),
I_STAGE_INC increases the 8-bit stage counter by the given value. M_BSLT = branch if stage is less than (just like M_BL but uses stage counter rather than R0).
These ones are standard instructions, you can read the IDF docs for more info.
Well thank you I cannot understand the difference between I_LD and I_GET ? can you tell me more about this ?
To build the anemometer I am following this diagram https://github.com/laguill/Weather-station-ulp-esp32/blob/main/Anemometer_Diagram.png but I don't understand how I can use time to trigger a Label how I can compare guts and counter_anemo and store it
int TIME_TO_SLEEP = 60; //Time EPS32 will go to sleep in seconds const float diametre = 0.07; //size of the anemometer
RTC_DATA_ATTR ulp_var_t counter_anemo; RTC_DATA_ATTR ulp_var_t windspd; RTC_DATA_ATTR ulp_var_t guts ; RTC_DATA_ATTR ulp_var_t nb_acq ;
void ulp_init(){ enum { LBL_BEGIN, //This labels are use as if function LBL_TRIGGERED, LBL_ACQUISITION, GUTS, };
const ulp_insn_t program[]{ //Reset R2 to counter_anemo = 0 M_LABEL(LBL_BEGIN), I_MOVI(R2,0), //Pin anemo triggered ? I_GPIO_READ(PIN_ANEMO), //If it's set, go to LBL_TRIGGERED M_BGE(LBL_TRIGGERED, 1),
M_LABEL(LBL_TRIGGERED),
//goto LBL_ACQUISITION
M_BX(LBL_ACQUISITION),
M_LABEL(ACQUISITION),
//increment counter nb_acq if PIN_PANEMO TRIGGERED
I_GET(R0,R3, nb_acq), //Load value from RTC memory into reg_dest register.
I_ADDI(R0,R0,1), //R0++
I_PUT(R0,R3, nb_acq), //Load value from reg_dest register to RTC memory.
//Add counter_anemo to windspd if PIN_ANEMO TRIGGERED
I_GET(R2,R2, counter_anemo), //Load value from RTC memory into reg_dest register.
I_GET(R1,R1, windspd), //Load value from RTC memory into reg_dest register.
I_ADDR(R0,R1,R2), //R0 = R1 + R2
I_PUT(R0,R1, windspd), //Store value from R0 into RTC memory in windspd variable
I_ADDI(R0,R0,1), //R0++
I_RSHR(R0,R0,1), //Logical Shift right of 1 to divide the value by two
I_PUT(R0,R2, counter_anemo), //Load value from reg_dest register to RTC memory.
M_BGE(GUTS,guts), //branch to GUTS if R0 is greater or equal than immediate value
M_LABEL(GUTS),
I_GET(R0,R2, counter_anemo), //Load counter_anemo in R0 register
I_PUT(R0,R1,guts), //guts = count_anemo
M_WAKE_WHEN_READY(),
I_HALT(),
}; //Pin configuration hulp_peripherals_on(); hulp_configure_pin(PIN_ANEMO, RTC_GPIO_MODE_INPUT_ONLY, GPIO_PULLDOWN_ONLY, 0); ESP_ERROR_CHECK(hulp_configure_pin_int(PIN_ANEMO, GPIO_INTR_ANYEDGE)); ESP_ERROR_CHECK(hulp_ulp_load(program, sizeof(program), 1000UL * ULP_WAKEUP_INTERVAL_MS, 0)); ESP_ERROR_CHECK(hulp_ulp_run(0)); }
void sleep(){
Serial.println("Going to sleep for "+ String(TIME_TO_SLEEP) + " seconds");
esp_sleep_enable_timer_wakeup(TIME_TO_SLEEP * 1000000UL);
delay(100);
Serial.flush();
//esp_sleep_enable_ulp_wakeup(); //This is for debugging
esp_deep_sleep_start();
}
void Anemometre()){ windspd.val = windspd.val / nb_acq.val; windspd.val = windspd.val M_PI diametre / (TIME_TO_SLEEP 3.6); guts.val = guts.val M_PI diametre / (TIME_TO_SLEEP 3.6); nb_acq.val = 0; }
void setup() {
Serial.begin(115200); Serial.println("Program is starting"); ulp_init(); Serial.println("counter = " + String(counter_anemo.val)); Serial.println("counter = " + String(guts.val)); Anemometre(); Serial.println("Wind speed = " + String(windspd.val) + " km/h"); Serial.println("Guts = " + String(guts.val) + " km/h"); sleep();
}
void loop() {
}
Here is my code and I have an error saying "cannot convert 'ulp_var_t' to 'uint32_t' {aka 'unsigned int'} in initialization"
Thank you again
I_LD takes the word offset in RTC memory from which to load the value.
I_GET is a hulp macro that is basically a I_LD that takes a ulp_var_t and calculates the offset for you. It's typically easier to use and much easier to maintain.
There's an error here:
M_BGE(GUTS,guts)
The compiler often won't be able to tell you where exactly your error is; generally you can isolate it by commenting parts of your ulp_insn_t array until the compiler stops complaining.
Hi sorry for the late answer. Thank you for help
In M_BGE I want to compare counter_anemo and guts to save the max value seen How can I do that ?
Is it possible to count the number of pulse during an amount of time And then save the value ?
You'll need to subtract them and check the result. There are many ways (most efficient depends on your program), here's one:
// Suppose you want to check if R2 > R1
I_SUBR(R3, R1, R2), // R3 = R1 - R2
M_BXF(LBL_GREATER), // Branch to label "LBL_GREATER" if previous operation overflowed (ie. R2 > R1)
// Else continue if no overflow occurred (ie. R1 >= R2)
There are macros for interacting with the RTC clock for timing, eg. M_IF_MS_ELAPSED. For example, here's a (untested) program that will count interrupts on a pin, and wake the SoC every 5 seconds.
const ulp_insn_t program[] = {
I_MOVI(R3, 0),
// Read the interrupt bit
I_GPIO_INT_RD(BUTTON_PIN),
// If it's not set, jump to LAB_CHECK_TIME
M_BL(LAB_CHECK_TIME, 1),
// Load and increment counter
I_GET(R1, R3, interrupt_counter),
I_ADDI(R1, R1, 1),
I_PUT(R1, R3, interrupt_counter),
I_GPIO_INT_CLR(BUTTON_PIN),
M_LABEL(LAB_CHECK_TIME),
M_UPDATE_TICKS(), // Update RTC time
M_IF_MS_ELAPSED(LBL_ELAPSED_CHECK, 5000 /* every 5 seconds */, LBL_HALT),
// Interval has elapsed
// Set previous counter and reset current counter
I_GET(R1, R3, interrupt_counter),
I_PUT(R1, R3, previous_counter),
I_PUT(R3, R3, interrupt_counter),
I_WAKE(),
M_LABEL(LBL_HALT),
I_HALT(),
};
If you know the wakeup interval, and your program has a consistent run time, then it might be easier to use a simple counter. Note that some macros like M_IF_MS_ELAPSED will mess with registers; have a look at the implementation in hulp_macros.h if you want to check or change.
Thank you Is it better to use I_GPIO_INT_RD(BUTTON_PIN) and I_GPIO_INT_CLR(BUTTON_PIN) than I_GPIO_READ(PIN_ANEMO) ?
I tried this code but something wrong the counter stay with 0 How is working when I go to label on condition ? after the code restart from where it left ?
I am a bit confuse right now
'#include` "hulp_arduino.h"
int TIME_TO_SLEEP = 10; //Time EPS32 will go to sleep in seconds const float diametre = 0.07; //size of the anemometer
RTC_DATA_ATTR ulp_var_t counter_anemo; RTC_DATA_ATTR ulp_var_t windspd; RTC_DATA_ATTR ulp_var_t guts ; RTC_DATA_ATTR ulp_var_t nb_acq ;
void ulp_init(){ enum { LBL_BEGIN, //This labels are use as if function LBL_TRIGGERED, LBL_ACQUISITION, LBL_GUTS, LBL_HALT, LBL_TIMER_ANEMO, };
const ulp_insn_t program[]{ //Reset R2 to counter_anemo = 0 M_LABEL(LBL_BEGIN), I_MOVI(R2,0), I_PUT(R2,R2, counter_anemo),
M_LABEL(LBL_TRIGGERED),
//Pin anemo triggered ?
I_GPIO_READ(PIN_ANEMO),
//If it's set, go to LBL_ACQUISITION
M_BGE(LBL_ACQUISITION, 1),
M_LABEL(LBL_ACQUISITION),
//increment counter nb_acq if PIN_ANEMO ACQUISITION
I_GET(R0,R3, nb_acq), //Load value from RTC memory into reg_dest register.
I_ADDI(R0,R0,1), //R0++
I_PUT(R0,R3, nb_acq), //Load value from reg_dest register to RTC memory.
//Add counter_anemo to windspd
I_GET(R2,R2, counter_anemo), //Load value from RTC memory into reg_dest register.
I_ADDI(R0,R0,1), //R0++
I_RSHR(R0,R0,1), //Logical Shift right of 1 to divide the value by two
I_PUT(R0,R2, counter_anemo), //Load value from reg_dest register to RTC memory.
//To check if counter_anemo > guts
I_GET(R2,R2, guts),
I_GET(R1,R1, counter_anemo),
I_SUBR(R0, R1, R2), // R3 = R1 - R2
M_BXF(LBL_GUTS), //branch to label "GUTS" if previous operation overflowed (ie. R2 > R1)
// Else continue if no overflow occurred (ie. R1 >= R2)
//Check timer anemo
M_UPDATE_TICKS(), // Update RTC time
M_IF_MS_ELAPSED(LBL_TIMER_ANEMO, TIME_ANEMO * 1000 /* every 3 seconds */, LBL_TRIGGERED), //M_IF_MS_ELAPSED(id_label, interval_ms, else_goto_label)
// Interval has elapsed
I_GET(R2,R2, counter_anemo), //Load value from RTC memory into reg_dest register.
I_GET(R1,R1, windspd), //Load value from RTC memory into reg_dest register.
I_ADDR(R0,R1,R2), //R0 = R1 + R2
I_PUT(R0,R1, windspd), //Store value from R0 into RTC memory in windspd variable
//reset counter,
M_BX(LBL_BEGIN),
M_LABEL(LBL_GUTS),
I_GET(R0,R1, counter_anemo), //Load counter_anemo in R0 register
I_PUT(R0,R1,guts), //guts = counter_anemo
M_LABEL(LBL_HALT),
I_HALT(),
}; //Pin configuration hulp_peripherals_on(); hulp_configure_pin(PIN_ANEMO, RTC_GPIO_MODE_INPUT_ONLY, GPIO_PULLDOWN_ONLY, 0); ESP_ERROR_CHECK(hulp_configure_pin_int(PIN_ANEMO, GPIO_INTR_ANYEDGE)); ESP_ERROR_CHECK(hulp_ulp_load(program, sizeof(program), 1000UL * ULP_WAKEUP_INTERVAL_MS, 0)); ESP_ERROR_CHECK(hulp_ulp_run(0)); }
void sleep(){
Serial.println("Going to sleep for "+ String(TIME_TO_SLEEP) + " seconds");
esp_sleep_enable_timer_wakeup(TIME_TO_SLEEP * 1000000UL);
delay(100);
Serial.flush();
//esp_sleep_enable_ulp_wakeup(); //This is for debugging
esp_deep_sleep_start();
}
void Anemometre(){ windspd.val = windspd.val / nb_acq.val; windspd.val = windspd.val M_PI diametre / (TIME_TO_SLEEP 3.6); guts.val = guts.val M_PI diametre / (TIME_TO_SLEEP 3.6);
nb_acq.val = 0;
}
void setup() {
Serial.begin(115200);
Serial.println("Program is starting");
ulp_init();
Serial.println("counter = " + String(counter_anemo.val));
Serial.println("counter = " + String(guts.val));
Anemometre();
Serial.println("Wind speed = " + String(windspd.val) + " km/h");
Serial.println("Guts = " + String(guts.val) + " km/h");
windspd.val = 0;
guts.val = 0;
sleep();
}
void loop() {
} '
I_GET and I_PUT expect the second register to have value 0.
Hi @boarchuz I'm trying to build a pulse counter. I tried using your ADC exemple but it is not working. I have a switch with a pulldown resistor on pin 34 Here is my code `#include "hulp_arduino.h"
define PIN_PLUV GPIO_NUM_34
define PIN_PLUV_WAKE_THRESHOLD (4090)
define ULP_WAKEUP_INTERVAL_MS (20) //Debouncers timer
int TIME_TO_SLEEP = 60; //Time EPS32 will go to sleep in seconds
RTC_DATA_ATTR ulp_var_t counter_pluv;
void ulp_init(){ enum { LBL_PIN_PLUV_HIGH, //This labels are use as if function LBL_HALT, }; const ulp_insn_t program[] = { //ULP I_MOVI(R1,0), //Copy an immediate value into register: R1 I_ANALOG_READ(R1, PIN_PLUV), I_SUBI(R0, R1, PIN_PLUV_WAKE_THRESHOLD), //Subtract register and an immediate value //// Subtract the threshold. If it overflows, the value must be < threshold so process the event. M_BXF(LBL_PIN_PLUV_HIGH), M_BX(LBL_HALT), // M_LABEL(LBL_PIN_PLUV_HIGH), //increment counter if PIN_PLUV == HIGH I_GET(R0,R1, counter_pluv), //Load value from RTC memory into reg_dest register. I_ADDI(R0,R0,1), //R0++ I_PUT(R0,R1, counter_pluv), //Load value from reg_dest register to RTC memory. M_WAKE_WHEN_READY(), // M_LABEL(LBL_HALT), I_HALT(), //Halt the coprocessor but keeps ULP timer active }; ESP_ERROR_CHECK(hulp_configure_analog_pin(PIN_PLUV)); ESP_ERROR_CHECK(hulp_ulp_load(program, sizeof(program), 1000UL * ULP_WAKEUP_INTERVAL_MS, 0)); ESP_ERROR_CHECK(hulp_ulp_run(0));
}
void sleep (){ Serial.println("Going to sleep for "+ String(TIME_TO_SLEEP) + " seconds"); esp_sleep_enable_timer_wakeup(TIME_TO_SLEEP * 1000000); delay(100); Serial.flush(); esp_sleep_enable_ulp_wakeup(); esp_deep_sleep_start(); } void setup() { // put your setup code here, to run once: Serial.begin(115200); Serial.println("Program is starting"); ulp_init;
Serial.println("Pluv counter = " + String(counter_pluv.val)); sleep();
}
void loop() { }`
Can you help on this ?
Thank you for your help