ADC1 incorrectly returns 4095 from ULP coproc during TIMER-triggered wake up
Posted: Sat Nov 28, 2020 7:34 pm
Hi,
I noticed that ADC1 sometimes erroneously returns 0xFFF during wake up from deep sleep, when the cause is a timeout.
To demonstrate the problem, I downloaded the latest esp-idf, and slightly modified example ulp_adc.
See diff to main .c and to .S files below.
Basically, the mods consist in :
- have the ULP coproc keep track of the highest ADC reading in a variable
- in main.c, printf the last value read along with the highest value seen since last wakeup
- using deepsleep along with a timeout (whereas in the sample only the ULP coproc wakes up the CPU)
- resetting highest value to 0 just before going to sleep.
On the test circuit, pin 34 is hooked on a pot's wiper to keep it at a constant tension of my choosing.
I set the pot so pin 34 is just under the low threshold set in the code.
At this stage, the console shows that the CPU gets woken up after a few coproc runs.
I then increase voltage to just above low threshold.
This causes the coproc to stop waking up the CPU, and lets it get out of deep sleep due to the timeout.
And then, even if the pin never really got above ~1750, the max value read from ADC shows 4095.
Note that it seems to happen on the *first* WAKEUP_TIMER after a WAKEUP_ULP, not on following timeouts.
See console output below.
This is consistent with what is reported on viewtopic.php?f=2&t=7105
In short, it seems that the wake up process itself (== some step inside of it) causes ADC1 to incorrectly return 4095 when read from ULP coproc.
Could you advise on how to fix this ?
Or maybe how to tell, from ULP coprocessor, whether a wake up is in progress ?
Thanks
David
Below the modifications I made on the ESP-IDF example.
Below a excerpt of the console
I noticed that ADC1 sometimes erroneously returns 0xFFF during wake up from deep sleep, when the cause is a timeout.
To demonstrate the problem, I downloaded the latest esp-idf, and slightly modified example ulp_adc.
See diff to main .c and to .S files below.
Basically, the mods consist in :
- have the ULP coproc keep track of the highest ADC reading in a variable
- in main.c, printf the last value read along with the highest value seen since last wakeup
- using deepsleep along with a timeout (whereas in the sample only the ULP coproc wakes up the CPU)
- resetting highest value to 0 just before going to sleep.
On the test circuit, pin 34 is hooked on a pot's wiper to keep it at a constant tension of my choosing.
I set the pot so pin 34 is just under the low threshold set in the code.
At this stage, the console shows that the CPU gets woken up after a few coproc runs.
I then increase voltage to just above low threshold.
This causes the coproc to stop waking up the CPU, and lets it get out of deep sleep due to the timeout.
And then, even if the pin never really got above ~1750, the max value read from ADC shows 4095.
Note that it seems to happen on the *first* WAKEUP_TIMER after a WAKEUP_ULP, not on following timeouts.
See console output below.
This is consistent with what is reported on viewtopic.php?f=2&t=7105
In short, it seems that the wake up process itself (== some step inside of it) causes ADC1 to incorrectly return 4095 when read from ULP coproc.
Could you advise on how to fix this ?
Or maybe how to tell, from ULP coprocessor, whether a wake up is in progress ?
Thanks
David
Below the modifications I made on the ESP-IDF example.
- $ diff main/ulp/adc.S ../../examples/system/ulp_adc/main/ulp/adc.S
- 58,63d57
- < /*===mod*/
- < .global highest_result
- < highest_result:
- < .long 0
- < /*===mod*/
- <
- 93,102d86
- <
- < /*===mod*/
- < move r3, highest_result
- < ld r2, r3, 0
- < sub r2, r0, r2
- < jump thr_test, ov
- < st r0, r3, 0
- <
- < thr_test:
- < /*===mod*/
- $ diff main/ulp_adc_example_main.c ../../examples/system/ulp_adc/main/ulp_adc_example_main.c
- 42,46d41
- < /*===mod*/
- < printf("ULP did %d measurements since last reset\n", ulp_sample_counter & UINT16_MAX);
- < printf("Last result=%d\n", (ulp_last_result & 0xfff));
- < printf("High result=%d\n", (ulp_highest_result & 0xfff));
- < /*===mod*/
- 55,57d49
- < /*===mod*/
- < printf("High result=%d\n", (ulp_highest_result & 0xfff));
- < /*===mod*/
- 62,65c54
- < /*===mod*/
- < /*esp_deep_sleep_start();*/
- < esp_deep_sleep(5 * 1000000);
- < /*===mod*/
- ---
- > esp_deep_sleep_start();
- 107,110d95
- <
- < /*===mod*/
- < ulp_highest_result = 0;
- < /*===mod*/
Below a excerpt of the console
- ... board running with pot set so that value remains within the limits ...
- Not ULP wakeup
- ULP did 252 measurements since last reset
- Last result=1613
- High result=1647
- Entering deep sleep
- >>> turning the pot to go below low threshold
- Deep sleep wakeup
- ULP did 24 measurements since last reset
- Thresholds: low=1500 high=2000
- Value=1488 was below threshold
- High result=1645
- Entering deep sleep
- Deep sleep wakeup
- ULP did 2 measurements since last reset
- Thresholds: low=1500 high=2000
- Value=1413 was below threshold
- High result=1428
- Entering deep sleep
- ... more output like these ...
- Deep sleep wakeup
- ULP did 2 measurements since last reset
- Thresholds: low=1500 high=2000
- Value=1497 was below threshold
- High result=1497
- Entering deep sleep
- >>> get the pot back to a spot where tension is back in range
- >>> but taking care not to go above the high threshold
- Not ULP wakeup
- ULP did 252 measurements since last reset
- Last result=1706
- High result=4095 <<<< 4095 was returned incorrectly at least once
- Entering deep sleep
- Not ULP wakeup
- ULP did 252 measurements since last reset
- Last result=1705
- High result=1719 <<< following WAKEUP_TIMER don't exhibit the problem
- Entering deep sleep
- ...