Problems with setWatch

Posted on
  • Hello, I'm having problems with Pico and magnetic reed switches.

    The idea is that on board LED indicate state of that switch i.e. green LED on when open, green LED off when closed. It all works well at first but when I quickly toggle the switch for a little while then LED gets "out of sync" with my switch, that is it lights green when closed.

    I'm having this issue both with pull-up and pull-down connections, tried with a different switch and debounce values. I must be missing something - but what? :)

    Example code:

    var door = new Pin(A8);
    var ledOpen = LED2;
    var ledHold = LED1;
    
    E.on("init", function () {
      door.mode("input");
    });
    
    function doorOpenedHandler() {
      ledOpen.set();
    }
    
    function doorHeldHandler() {
      ledHold.set();
    }
    
    function doorClosedHandler() {
      ledOpen.reset();
      ledHold.reset();
    }
    
    setWatch(function () {
      doorOpenedHandler();
    }, door, {repeat: true, edge: "falling", debounce: 0});
    
    setWatch(function () {
      doorHeldHandler();
    }, door, {repeat: true, edge: "falling", debounce: 2000});
    
    setWatch(function () {
      doorClosedHandler();
    }, door, {repeat: true, edge: "rising", debounce: 0});
    

  • Had similar issues that the event queue picked up more than sunchronously could be handled. Therefore, I used the setWatch-es non-repeated for trigger the read the status (delayed).

    Initially I built this [keypad module]() the same way and then changed it to overcome these out-of-sync issues... Only afterwards I became aware of the existing one which uses a similar approach SW and HW as yours... and most likely has the same issues.

    I use the two different edges in one-time setWatches and sufficient debounce... that will solve your issue... and for adding a separate layer of stability, you can place on switch change a timeout to change state again after may be 500...1000 ms.

  • What happens if you change:

    setWatch(function () {
    doorOpenedHandler();
    }, door, {repeat: true, edge: "falling", debounce: 0});
    
    setWatch(function () {
    doorClosedHandler();
    }, door, {repeat: true, edge: "rising", debounce: 0});
    

    into

    setWatch(function (e) {
    if (e.state) doorOpenedHandler();
    else doorClosedHandler();
    }, door, {repeat: true, edge: "both", debounce: 0});
    

    Not sure, but it would be interesting to see.

    I don't think the issue is that the queue is overflowing (you'd see with E.getErrorFlags() if it was). It's just that the signal is may be changing very quickly, so by the time there is an IRQ and Espruino reads the pin state, the pin state has changed (although that should mean that the last setWatch that happens is correct).

  • @allObjects thanks to your suggestions I have played with different timers and debounce values again and I think I'm getting somewhere.

    @Gordon it's even less reliable this way, it's difficult to describe LED's behavior now so I have changed the code to use console.log and it looks interesting.

    First try:

    var door = new Pin(A8); //pull-up
    
    E.on("init", function () {
      door.mode("input");
    });
    
    function doorOpenedHandler() {
      console.log("door opened");
    }
    
    function doorClosedHandler() {
      console.log("door closed");
    }
    
    setWatch(function () {
      doorOpenedHandler();
    }, door, {repeat: true, edge: "falling", debounce: 500});
    
    setWatch(function () {
      doorClosedHandler();
    }, door, {repeat: true, edge: "rising", debounce: 500});
    
     1v81 Copyright 2015 G.Williams
    >echo(0);
    =undefined
    >save()
    =undefined
    Erasing Flash.....
    Writing.....
    Compressed 81600 bytes to 2942
    Checking...
    Done!
    
    // I'm starting with closed switch
    door closed
    >door.read()
    =true
    
    // I'm opening the switch
    door opened
    >door.read()
    =false
    
    // I'm closing the switch
    door opened
    >door.read()
    =true
    // wait, what? wrong handler got called but the door value is correct
    

    Now let's try with e.state:

    ...
    setWatch(function (e) {
      if (e.state) {doorOpenedHandler();} else {doorClosedHandler();}
    }, door, {repeat: true, edge: "both", debounce: 500});
    
    // I'm starting with closed switch again, looks like the logic has changed
    door opened
    >door.read()
    =true
    
    // I'm opening the switch
    door closed
    >door.read()
    =false
    
    // I'm closing the switch
    door opened
    >door.read()
    =true
    
    // I'm opening the switch
    door closed
    
    // I'm closing the switch
    door closed
    // wrong handler again i.e. after seeing "door closed" the last time I would expect "door opened" now
    

    Any ideas, please? Is my wiring ok?

  • Strange... Your wiring looks ok, but I just had a thought:

    Is the pullup resistor you have actually connected and working? Maybe try pinMode(A8, "input_pullup") to use the STM32's internal pullup resistor just in case?

    Because it could be that when you close the reed switch, that's fine and you get a 0. But when you open it, the pullup isn't there and it just 'floats' - which would mean that you get all kinds of readings - and potentially setWatch with debounce would rarely actually register that the signal went high.

    One other thing to try is to put small (0.1uF?) capacitor across the reed switch. It shouldn't be needed, but it would stop the signal changing so frequently and causing problems.

  • Before implementing the keypad un-biased myself, I felt understanding how Espruino's event queue and setWatch()'s debouncing works... after all I implemented Resistive Touchscreen directly (no touch controller) and used it successfully in multiple applications, such as UI Module w/ Buttons, Checkboxes,... for Display w/ Touchscreen and Puzzle16+ Game on ILI9341 2.8" 262K Color TFT LCD w/ Resistive Touch Screen, and also the press-time detection in Software Buttons - Many buttons from just one hardware button.

    After implementing the keypad, I'm not so sure anymore about how they work - more precisely: how my code should interact with them properly - especially the way how I tested it: I just used a wire connected (firmly) to the driver side - output - (high/low - 3.3V/GND) and touching the - input - GPIO 'pin' (castellation / board pad, header pin). The moving wire may have just overstepped the working boundaries of the debounce, because I got a flurry of events (callback calls), no matter how I did set the debouncing.

    Therefore, I switched to the setup as outlined:

    1. set single-flank, single (non-repeated), substantially debounced setWatch to monitor the switch turning 'on' and trigger the
    2. check state (scan) of the switch(es)
    3. set single-(oposite) flank, single (non-repeated), substantially debounced setWatch to monitor the switch turning 'off' and to start over with step 1.

    If I do not see any 'on' in step 2 - check/scan state - I consider the trigger as an errant (button not pressed long enough), and return right away to step 1.

    Even though this setup made it work for me, there is still the possibility that step 3 - watchng the switch turning 'off' - will not trigger, because it's setup was too late and the switch had already returned to initial - 'off' - state. To make it more predictable, a timeout - 'safety net timer' - has to be setup at the same time as the setWatch is set to check the state... just in case... ;-). If the state shows (still) 'on', the setWatch will eventually fire. If the state is 'off', the watch has to be called off (clearWatch), and process has to return to step 1. If the watch fires before the 'safety net timer' expires, the timer has to be cleared when returning to step 1.

  • Post a reply
    • Bold
    • Italics
    • Link
    • Image
    • List
    • Quote
    • code
    • Preview
About

Problems with setWatch

Posted by Avatar for Rollo @Rollo

Actions