Closed 0x0fe closed 1 year ago
Hi @0x0fe, There are many ways to skin this cat. It's probably not worth an extra example but here are a few ways:
#define ADC_THRESHOLD_MIN 123 // Wake if >=
#define ADC_THRESHOLD_MAX 456 // Wake if <=
// 1
I_ANALOG_READ(R0, PIN_ADC), // R0 = ADC
M_BL(LBL_NOT_TRIGGERED, ADC_THRESHOLD_MIN), // goto NOT_TRIGGERED if R0 < MIN
M_BGE(LBL_NOT_TRIGGERED, ADC_THRESHOLD_MAX + 1), // goto NOT_TRIGGERED if R0 > MAX
// Triggered
// 2
I_ANALOG_READ(R0, PIN_ADC), // R0 = ADC
I_SUBI(R0, R0, ADC_THRESHOLD_MIN), // Cause values below threshold to overflow
M_BGE(LBL_NOT_TRIGGERED, (ADC_THRESHOLD_MAX - ADC_THRESHOLD_MIN) + 1), // Check if above threshold (compensating for previous subtraction)
// Triggered
// 3
I_ANALOG_READ(R1, PIN_ADC), // R1 = ADC
I_SUBI(R1, R1, ADC_THRESHOLD_MIN), // Set overflow flag if below threshold
M_BXF(LBL_NOT_TRIGGERED),
I_ADDI(R1, R1, 65535-(ADC_THRESHOLD_MAX-ADC_THRESHOLD_MIN)), // Set overflow flag if above threshold (compensating for previous subtraction)
M_BXF(LBL_NOT_TRIGGERED),
// Triggered
If you care about optimising for size/speed, R0 allows the most efficient (and easiest) instructions, and you can consider reversing the logic if that suits your program flow better.
@0x0fe Wow, nice, thank you very much, my pathetic attempt was failing miserably.
(compensating for previous subtraction)
Maybe the bit i missed.
// Subtract the threshold. If it overflows, the value must be < threshold so process the event.
I_SUBI(R0, R1, PIN3_WAKE_THRESHOLD_HIGH),
//branch to halt if no overflow (adc>high threshold)
M_BX(LBL_HALT),
I_SUBI(R0, R1, PIN3_WAKE_THRESHOLD_LOW),
//branch to label if no overflow (adc>low threashold)
M_BX(LBL_PIN3_WAKEUP_TRIGGERED),
//branch to halt if overflow (adc<low threashold)
M_BXF(LBL_HALT),
//M_BXF(LBL_PIN3_WAKEUP_TRIGGERED),
//M_BX(LBL_HALT),
and so i can confirm, it worked perfectly
void ulp_init(void){
enum {
LBL_PIN2_OVERSAMPLE_LOOP,
LBL_PIN3_WAKEUP_TRIGGERED,
LBL_HALT,
};
const ulp_insn_t program[] = {
// Set R3 to 0 for use with I_GET and I_PUT
I_MOVI(R3, 0),
I_ANALOG_READ(R1, ADKEY), // R1 = ADC
I_PUT(R1, R3, ulp_vars.pin3.debug),
I_GET(R0, R3, ulp_vars.pin3.armed), //Skip if the trigger isn't 'armed'
M_BL(LBL_HALT, 1),
I_SUBI(R1, R1, ADC_THRESHOLD_MIN), // Set overflow flag if below threshold
M_BXF(LBL_HALT),
I_ADDI(R1, R1, 65535-(ADC_THRESHOLD_MAX-ADC_THRESHOLD_MIN)), // Set overflow flag if above threshold (compensating for previous subtraction)
M_BXF(LBL_HALT),
I_PUT(R1, R3, ulp_vars.pin3.wakeup.reason), // Store the wakeup value for SOC access
I_GET(R0, R3, ulp_vars.pin3.wakeup.counter), // Increment the counter.
I_ADDI(R0, R0, 1),
I_PUT(R0, R3, ulp_vars.pin3.wakeup.counter),
I_PUT(R3, R3, ulp_vars.pin3.armed), // Clear 'armed'
M_WAKE_WHEN_READY(),
M_LABEL(LBL_HALT),
I_HALT(),
};
ESP_ERROR_CHECK(hulp_configure_analog_pin(ADKEY, ADC_ATTEN_DB_0, ADC_WIDTH_BIT_12));
ESP_ERROR_CHECK(hulp_ulp_load(program, sizeof(program), 1000UL*ULP_WAKEUP_INTERVAL_MS, 0));
ESP_ERROR_CHECK(hulp_ulp_run(0));
}
17:53:48.926 -> system init
17:53:54.500 -> adkey:592
17:53:57.070 -> adkey:758
17:53:57.680 -> adkey:436
17:53:59.317 -> adkey:1513
17:54:00.951 -> adkey:960 [this key triggers the deep sleep]
17:54:01.185 -> ULP start
17:54:01.185 -> going to deep sleep
17:54:07.883 -> [no key triggered the wakeup, except the one within the defined range]
17:54:08.211 -> waking from deep sleep
17:54:08.211 -> ULP stop
17:54:08.211 -> system init
So, in the ADC example, which by the way is very convenient and covers many cases, i try to compare the PiN3 against a range, rather than if it is below a certain threashold.
Because, when used with ADKEYS typically several keys are on the same GPIO and i want to wake up the system only if a certain key is pressed.
What is the best way to do this? I see where you compare wether it is below the threashold, but i am not sure how to compare if it is below the threshold and over another threshold.
I think updating the example with that function would be useful to others working with ADKEYs.
Thanks.