PIN latch functionality for ESP32

C programming, build, interpreter/VM.
Target audience: MicroPython Developers.
PRosenb
Posts: 6
Joined: Sun Jul 05, 2020 1:18 pm

PIN latch functionality for ESP32

Post by PRosenb » Sun Jul 05, 2020 1:33 pm

Hi guys,
On `ESP32` PINs can keep their value in deep sleep with using the functions `rtc_gpio_hold_en()` and `rtc_gpio_hold_dis()`.
I had a look at the `MicroPython` code base and saw that it would be an option to add such a functionality in `modesp32.c`.
Would you guys welcome adding such a functionality?
Would that be a good spot there? What names for the two new functions could be used?
I saw that other similar functions like `wake_on_ext1()` don't exactly follow the naming in `esp-idf` but I didn't figure a rule how to convert function names in `esp-idf ` to function names in `MicroPython`.
Regards,
Pete

User avatar
Roberthh
Posts: 3667
Joined: Sat May 09, 2015 4:13 pm
Location: Rhineland, Europe

Re: PIN latch functionality for ESP32

Post by Roberthh » Sun Jul 05, 2020 1:57 pm

In the close related Pycom dialect this method is called hold() with the argument True and False. So pin.hold(True) enables it, pin.hold(False) disables it. For consistency, this name should be used.

Christian Walther
Posts: 169
Joined: Fri Aug 19, 2016 11:55 am

Re: PIN latch functionality for ESP32

Post by Christian Walther » Sun Jul 05, 2020 10:20 pm

Is this related to the Pin.PULL_HOLD flag (of which I’m not entirely sure what it does)?

User avatar
Roberthh
Posts: 3667
Joined: Sat May 09, 2015 4:13 pm
Location: Rhineland, Europe

Re: PIN latch functionality for ESP32

Post by Roberthh » Mon Jul 06, 2020 5:26 am

No, it is not. PULL_HOLD activates a function, which freezes the state of a PIN, such that it will not be modified any more by changing input value in input mode or by writing to the pin in output mode. I can imagine why that is useful input mode, but not for output mode.

PRosenb
Posts: 6
Joined: Sun Jul 05, 2020 1:18 pm

Re: PIN latch functionality for ESP32

Post by PRosenb » Mon Jul 06, 2020 5:36 am

@Roberthh are you considering extending the generic class `machine.Pin` for this functionality? I'm unsure if other CPUs than ESP32 support it too.

The two functions are described here:
https://docs.espressif.com/projects/esp ... gpio_num_t

In output mode it's useful for deep sleep. When these functions are not called, the PIN is switched off in deep sleep.

User avatar
Roberthh
Posts: 3667
Joined: Sat May 09, 2015 4:13 pm
Location: Rhineland, Europe

Re: PIN latch functionality for ESP32

Post by Roberthh » Mon Jul 06, 2020 5:53 am

It is not a problem if only the ESP32 supports it. There are many other examples of hardware-specific functions in MicroPython, which are not supported by every port. For instance WiFi. I understand why that is useful, so there are good reasons for implementing it. Whether I will implement it ... don't know.

User avatar
Roberthh
Posts: 3667
Joined: Sat May 09, 2015 4:13 pm
Location: Rhineland, Europe

Re: PIN latch functionality for ESP32

Post by Roberthh » Mon Jul 06, 2020 9:10 am

So I made a test implementation of pin.hold(). Not a lot of work for coding. Testing takes longer.

It works, but I see no difference to the pull=Pin.PULL_HOLD option of Pin.init(). In both cases, the value of the output is frozen and maintained during a machine.deepsleep() or machine.reset() call. A physical reset clears the setting. And opposed to the documentation, a pin input value with Pin.hold or pull=Pin.PULL_HOLD is not frozen. Even if set, the value read back is the actual value at the input. That's different to how I understand the espressif documentation.

I did not test (yet) with a battery attached.

Core code of the pin.hold function:

Code: Select all

// pin.hold(value)
STATIC mp_obj_t machine_pin_hold(mp_obj_t self_in, mp_obj_t arg) {
    machine_pin_obj_t *self = MP_OBJ_TO_PTR(self_in);
    esp_err_t rc;
    if (mp_obj_is_true(arg)) {
        rc = rtc_gpio_hold_en(self->id);
    } else {
        rc = rtc_gpio_hold_dis(self->id);
    }
    if (rc == ESP_OK) {
        return mp_const_none;
    } else {
        mp_raise_ValueError(MP_ERROR_TEXT("invalid pin for hold"));
    }
}
STATIC MP_DEFINE_CONST_FUN_OBJ_2(machine_pin_hold_obj, machine_pin_hold);
Additionally needed in the include section

Code: Select all

#include "driver/rtc_io.h"
and in the QSTR definitions:

Code: Select all

    { MP_ROM_QSTR(MP_QSTR_hold), MP_ROM_PTR(&machine_pin_hold_obj) },

User avatar
Roberthh
Posts: 3667
Joined: Sat May 09, 2015 4:13 pm
Location: Rhineland, Europe

Re: PIN latch functionality for ESP32

Post by Roberthh » Mon Jul 06, 2020 11:50 am

@ PRosenb: Finally using the option pull=Pin.PULL_HOLD with the existing firmware will offer you the in intended function of keeping the value of an output Pin during machine.deepsleep and machine.reset. It also prevents the redefinition of a PIN to input mode until the hold is released with pull=None. Still I could not see any effect on the input mode.

pull=Pin.PULL_HOLD causes gpio_hold_en to be called for that pin, and similar
pull=None causes gpio_hold_dis to be called.

PRosenb
Posts: 6
Joined: Sun Jul 05, 2020 1:18 pm

Re: PIN latch functionality for ESP32

Post by PRosenb » Mon Jul 06, 2020 3:50 pm

Many thanks @Roberthh for such a quick answer and even analysis.

For some reason it behaves differently on my ESP32. It is a "ESP32 DEVKITV1", silicon revision 1.
I tested
- self built MicroPython with current master (using ESP-IDF v3.3.2)
- esp32spiram-idf3-20191220-v1.12.bin (downloaded)

Then I execute the following code, the internal LED is not switched on. When I remove `Pin.PULL_HOLD`, the internal LED is switched on for 2 seconds and goes off afterwards while the CPU is in deep sleep.

It seams that on my chip it only works when using `rtc_gpio_hold_en()` instead of `gpio_hold_en()`.

Code: Select all

import utime
import machine
from machine import Pin

def test():
    led_pin = Pin(2, Pin.OUT, Pin.PULL_HOLD)
    # led_pin = Pin(2, Pin.OUT)
    print("led on")
    led_pin.on()
    print("wait 2 sec")
    utime.sleep(2)
    print("deep sleep 2 sec")
    machine.deepsleep(2 * 1000)

User avatar
Roberthh
Posts: 3667
Joined: Sat May 09, 2015 4:13 pm
Location: Rhineland, Europe

Re: PIN latch functionality for ESP32

Post by Roberthh » Mon Jul 06, 2020 3:59 pm

Once PULL_HOLD is called, the output does not change any more. So I used the sequence:

Code: Select all

led_pin = Pin(2, Pin.OUT)
led_pin.on()  # or led_pin(1)
led_pin.init(Pin.OUT, pull=Pin.PULL_HOLD)
Unfortunately, the ESP32 port does not have the single pin.pull() method.

Edit: I use a Wemos board, but the chips are expected to behave identical.

Post Reply