lancaster-university / codal-microbit-v2

CODAL target for the micro:bit v2.x series of devices
MIT License
43 stars 52 forks source link

Should uBit.logo work when switched to TouchMode::Resistive? #113

Closed martinwork closed 2 months ago

martinwork commented 3 years ago

Does uBit.logo work only in capacitative mode or does the code below use the wrong method to switch modes?

After pressing button A to select TouchMode::Resistive, the logo is always pressed.

This example is intended to match the MakeCode code in https://github.com/microsoft/pxt-microbit/issues/3724.

test-pintouch-v2.zip

#include "MicroBit.h"

MicroBit uBit;

void onButtonA(MicroBitEvent e)
{
    uBit.io.logo.isTouched( codal::TouchMode::Resistive);
}

void onButtonB(MicroBitEvent e)
{
    uBit.io.logo.isTouched( codal::TouchMode::Capacitative);
}

void display()
{
   while (true)
   {
     uBit.display.printChar( uBit.logo.isPressed() ? '1' : '0');
     uBit.sleep(100);
   }
}

int  main() {
    uBit.init();

    uBit.messageBus.listen( MICROBIT_ID_BUTTON_A,  MICROBIT_BUTTON_EVT_CLICK, onButtonA);
    uBit.messageBus.listen( MICROBIT_ID_BUTTON_B,  MICROBIT_BUTTON_EVT_CLICK, onButtonB);

    create_fiber( display);

    release_fiber();
}
microbit-carlos commented 2 years ago

I can confirm that In this example uBit.logo.isPressed() does not work as expected.

uBit.io.logo.isTouched() does work, even when called without setting a TouchMode argument (as it is already changed when button A or B are pressed).

The same can be replicated in MakeCode, as it uses uBit.logo.isPressed(): microbit-logo-touch-change.hex.zip

image
input.onButtonPressed(Button.A, function () {
    basic.showString("r")
    pins.touchSetMode(TouchTarget.LOGO, TouchTargetMode.Resistive)
})
input.onButtonPressed(Button.B, function () {
    basic.showString("c")
    pins.touchSetMode(TouchTarget.LOGO, TouchTargetMode.Capacitive)
})
basic.forever(function () {
    if (input.logoIsPressed()) {
        basic.showIcon(IconNames.Heart)
    } else {
        basic.showIcon(IconNames.Sad)
    }
})

MakeCode C++ code:

martinwork commented 1 year ago

MakeCode block "set logo to touch mode %mode" uses uBit.io.logo.isTouched(mode), but I don’t think uBit.logo supports changing the uBit.io.logo touch mode.

uBit.logo is a TouchButton, whose NRF52Pin (uBit.io.logo) is initially set as output and monitored via GPIOTE events in NRF52TouchSensor (uBit.touchSensor). uBit.logo is not aware of changes to uBit.io.logo via NRF52Pin.

Changing mode with uBit.io.logo.isTouched(Resistive) creates a Button, sets the pin to input, and sets its pull mode, which presumably clashes with the ongoing uBit.logo TouchButton and NRF52TouchSensor GPIOTE code.

Changing mode with uBit.io.logo.isTouched(Capacitive) adds a second TouchButton to uBit.touchSensor, and sets the pin as output again. After that, uBit.logo.isPressed() seems to start working again, though I think it no longer has the “empty timeslot for that channel to drain all its charge before sampling it again”, and MakeCode’s “on logo pressed” block sees double events.

Do we need resistive touch for the logo?

martinwork commented 1 year ago

The Python program below also doesn't work after changing to resistive mode, and the logo is_touched() state always seems less stable than MakeCode, I guess because microbit_hal_pin_is_touched uses uBit.logo.buttonActive(), which misses out on the isPressed() debounced state.

from microbit import *

while True:
    if pin_logo.is_touched():
        display.show(Image.HAPPY)
    else:
        display.show(Image.SAD)
    if button_a.was_pressed():
        pin_logo.set_touch_mode(pin_logo.RESISTIVE)
    if button_b.was_pressed():
        pin_logo.set_touch_mode(pin_logo.CAPACITIVE)
microbit-carlos commented 1 year ago

Thanks Martin, I can confirm that with the MicroPython example pin_logo when set to resistive is always triggered as "touched".

microbit-carlos commented 7 months ago

Quick summary:

microbit-carlos commented 6 months ago

Okay, a bit more detail:

  • uBit.logo default touch mode should be capacitive

This is correct right now, no action required.

  • uBit.io.logo default is not clear, might be either, although ideally it should be capacitive as well

uBit.io.logo default is resistive, and it should be capacitive:

  • Touch for pins default should be resistive (for V1 compatibility)

This is also correct right now and no action is required.

  • Changing the logo to resistive touch should work (the main problem described in this issue)

This is the topic for this issue.

Additionally

microbit-carlos commented 6 months ago

So the main reason that the code in this issue doesn't work is because TouchButton has been designed to be Capacitive only. So, when the touch mode is changed from MicroPython or MakeCode via uBit.io.logo.isTouched(TouchMode) this breaks uBit.logo (TouchButton type).

Three options to fix this issue:

microbit-carlos commented 6 months ago

Conclusion, we'll go for simplest fix:

microbit-carlos commented 6 months ago

Before we can complete this we need to ensure uBit.io.logois capacitive by default.

PR to set uBit.io.logo to capacitive by default:

MicroPython already uses this method.

Once the PR above is merged, we can submit this to MakeCode, I've tested this with pxt locally and works in resistive mode:

Issue to track in MakeCode:

microbit-carlos commented 2 months ago

Raised PR:

We can close this ticket now.