https://toitlang.org/ logo
GPIO Trigger container in artemis on low/high
# help
i
I have two container. One is triggered by 4 GPIO Pins if they are driven LOW. And one container which is triggered when one GPIO is driven HIGH. First of all: I think this is not possible at all. I can not have gpio high and low mixed as trigger. But besides that I receive a message in the log telling me:
[artemis.containers] INFO: triggered by pin {name: trigger, id: b9906bd7-9c7e-dce1-9a10-4ab91b230523, pin: 7, level: 0}
but if I check the
esp32.ext1-wakeup-status
and extract the pin which actually triggered this container to run I get 9 instead of 7. 9 is supposed to be the GPIO which starts a container when driven HIGH and it became LOW (thats why I assume it is not possible to have both setup). There is an option with "any high" or "any low" and I think it can only be that any of the GPIOs are low or any of the declared once are HIGH but not both. So - this is causing lots of chaos in my code now and I wonder if I can fix that somehow. Or if this is even fixable somehow anyway. I am using artemis right now with a container declaration like so:
Copy code
containers:
  trigger:
    entrypoint: "../src/trigger.toit"
    triggers:
      - gpio:
        - pin: 6
          level: "low"
        - pin: 7
          level: "low"
        - pin: 18
          level: "low"
        - pin: 21
          level: "low"
  ble:
    entrypoint: "../src/ble/ble.toit"
    triggers:
      - gpio:
        - pin: 9
          level: "high"
I think the only option I have here is to always only run one container which then checks the cause and the pin numbers and also checkts the Pins and then runs the dedicated containers on there own. Is this possible? Can I skip artemis from running the container and leave it to me, when to run them? (I assume not)
What happened was: when I started the device it was running the main app, initialising the sensors etc. and went to sleep. Once a sensor detects something it is pulling a gpio low (one of 6,7,18 and 21) which then caused the trigger container to run. Once I plugged in USB it triggered the BLE container to run as expected but when pulling it out it triggered the trigger container as well (which actually should not be the case, maybe there is a bug?)
btw: the function
ext1-wakeup-status
is missing a documentation. I don't really get why I have to pass a mask to it as well ๐Ÿค”
Copy code
ext1-wakeup-status pin-mask/int -> int:
  #primitive.esp32.ext1-wakeup-status
but for the case explained above I am passing a mask like
((1 << 6) | (1 << 7) | (1 << 18) | (1 << 21))
and the result is 512 which translates to GPIO 9
Copy code
[artemis.scheduler] INFO: job stopped {job: synchronize}
[artemis.scheduler] INFO: runlevel decreasing {runlevel: 0}
[artemis.containers] INFO: setting up external-wakeup trigger any high: 1000000000
[artemis.containers] WARN: pin triggers for low level are ignored
this lines also tell me that it disabled the low level detection which is the case. Only the USB-C detection does work then.
f
You are right: the ESP32 doesn't support low and high triggers at the same time. While the device is running, Artemis will look for both, but it can't do that while in deep-sleep.
On the ESP32 the low trigger only activates when all low triggers are low. On the ESP32S3 it's "any".
Yeah. That's a bit weird. We should improve that. The bitmask is used to
rtc_gpio_deinit()
the pad. See the warning at the end of the linked section: https://docs.espressif.com/projects/esp-idf/en/stable/esp32/api-reference/system/sleep_modes.html#external-wakeup-ext0
If you don't want to change your hardware (adding inverters), then you might get away with using the ULP chip. That one could detect low and high triggers at the same time. So far we don't have support for the ULP, but it doesn't sound too bad. Basically would require exposing a few functions. Writing ULP code is typically done in assembly. So definitely not as nice as writing Toit code.
i
๐Ÿค” I can change the polarity of the sensor programmatically for the triggering I think. but I also added an external pull-up so I could remove this and make it all trigger on HIGH. That could work.
f
And I still need to check why the pin is 9 and not 7. Feel free to remind me so I don't forget.
I might need to get back to you to construct a repro.
i
but this has nothing to do with the mask I am passing, right?
You get the result of calling
esp_sleep_get_ext1_wakeup_status
.
I'm not really sure whether we are doing the right thing there. If nobody checks for the pins, then they get stuck in rtc-mode? Shouldn't we just deinit all pins that triggered? Questions...
i
๐Ÿค”
can I deinit all pins somehow? so the status is not doing it, right? I didn't know avout this rtc pin feature and thought toit is taking care of it
f
I never noticed it either. So I'm not completely sure what it does. Artemis starts by taking the status, so it probably automatically resets it this way.
The status does it for you because of the mask.
i
I was in a train yesterday (embedded world) - so you do deinit the gpios in status. So it should be fine if I call it. But you mean you should just deinit ALL pins? Propably right.
f
I think so, but I have to read up. Not sure why we give users the option of passing in a mask, and not sure what happens if that call doesn't happen.
i
I swapped the interrupt from low to high and now it works for both. It is still not behaving perfectly but the interrupt of the sensors fires every time I am sending a command, so that is triggering every time as well
I think the issue is what you described: I think you should deinit all GPIOs. Still not 100% clear. The mask I am passing to the status function is used to deinit only the given GPIOs. I did not passed GPIO 9 which is used for the usb detect but the mask only contained the 4 other pins of the sensor interrupt. When I plugged in the usb the trigger container was started with the gpio 9 but it did not deinit this pin because it is not part of the mask. I added it to the mask and now it seems to run
but the other issue remains the same:
Copy code
[artemis.containers] INFO: triggered by pin {name: trigger, id: 4c3cf1a6-f3aa-af9f-f32f-588b2b888cdf, pin: 7, level: 1}
[artemis.containers.trigger] DEBUG: starting {reason: 1930, arguments: null}
[artemis.scheduler] INFO: job started {job: container:trigger}
[trigger] DEBUG: Wakeup cause: 3
[trigger] DEBUG: Wakeup status 512
[trigger] DEBUG: extracted Pins: [9]
[trigger] DEBUG: Error: Ignored trigger
[artemis.scheduler] INFO: job stopped {job: container:trigger}
artemis sais it triggered because of pin 7 but in the exraction it says pin 9
Copy code
extract_pins mask/int -> List:
  pins := []
  21.repeat:
    if mask & (1 << it) != 0:
      pins.add it
  return pins
thats the function to extract the pin
I hardcoded 21 for the ESP32-S3 for now because it only can be those
f
This is, how we do it:
Copy code
triggered-pins := esp32.ext1-wakeup-status external-mask
      touch-wakeup-pin := esp32.touchpad-wakeup-status  // -1 if not triggered by touch.

      job-was-triggered := false
      // If the high_mask isn't 0, then it wins over the low mask.
      jobs.do: | job/ContainerJob |
        job.do --trigger-gpio-levels: | pin level/int |
          pin-mask := 1 << pin
          if (triggered-pins & pin-mask) != 0:
            is-triggered := false
            if level == 1:
              // Level 1 wins over level 0.
              is-triggered = true
            else if high-mask == 0:
              // Level 0 is only triggered if there is no level 1.
              is-triggered = true
            if is-triggered:
              job-was-triggered = true
              job.trigger (Trigger.encode-pin pin --level=level)
              tags := job.tags.copy
              tags["pin"] = pin
              tags["level"] = level
              logger_.info "triggered by pin" --tags=tags
i
@floitsch if I initialise a pin with
gpio.Pin.out
it says the default value is 0 - does it set this pin actively to be 0? The Pin has an external pull-up and it should stay on or at least not set the level to be 0 when I initialise it.
When the device wakesup from the deep-sleep I initialise the gpio that way and I think it is setting it to 0
f
gpio.Pin --out
(equivalent to
gpio.Pin.out
) actively sets the pin to 0. Yes.
i
this will reset my sensor
damn
f
If you don't want to output anything, then you shouldn't use
--out
.
Alternatively, you can use
--open-drain
I'm not sure you can set
open-drain
and immediately go to 1, though.
So there might be a tiny glitch.
Nvm.
--open-drain
actually goes to 1 by default.
https://libs.toit.io/gpio/class-Pin#configure(5%2C0%2C0%2Cinput%2Copen-drain%2Coutput%2Cpull-down%2Cpull-up)
i
hm.. the pin in always an output in my case I just don't want to change its state. maybe open-drain will work
f
Typically, when you say "the pin is now output", you have to say how (1 or 0). If you don't want to change it's value, then it's not really "output". You have 3 options: - keep the pin as non-output as long as you don't need to change the value. You can always use
configure
to change it. - make it
--open-drain
. Then the output is only "effective" if you go to 0. - only allocate the pin when you need to change the value.
i
thanks , thats what I do now. I kind of have to initialise it. But I go with open-drain now and I do change its config once I have to use it.
boot time to trigger camera: 521394ยตs == 521ms I am counting the days until you got an improvement here ๐Ÿ˜„
thats the time until the camera is actually triggered
f
You don't need to change the config with open-drain. That should just work.
A few smaller ones should make it into the next release. Nothing drastic yet. That would require rewriting the scheduler.
i
somehow the wakeup seems to be unreliable - at least it does not react for two of the 4 sensors. but this could be something different. I have no pull-down resistors on those pins now which could be a problem
f
Do they work if you don't go to deep-sleep?