Skip to content

Adding delay for third-party nunchuks #34

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
May 10, 2023
Merged

Conversation

BlitzCityDIY
Copy link
Contributor

hihi- @djecken was using this library with the nunchuk that we sell in the shop and kept getting an error that no device was on 0x52 despite the I2C scan test showing the device. we switched to an official nunchuk and didn't get this error. i ran into this when working on the wii_classic library. third-party controllers seem to take longer to initialize for some reason. i added the same try/except loop here and that has fixed the issue with the nunchuk in the shop.

@BlitzCityDIY BlitzCityDIY requested a review from caternuson May 5, 2023 13:43
@caternuson
Copy link
Collaborator

I have one of those nunchuk's also. What's the complete hardware setup being used? Will try and recreate this.

Wondering if _I2C_INIT_DELAY and/or i2c_read_delay could be used to help with this.

@BlitzCityDIY
Copy link
Contributor Author

it's the nunchuk breakout connected via a STEMMA QT cable to the STEMMA QT port on the Feather RP2040 RFM69. i had tried increasing the init delay previously and added a time.sleep all the way up to 10 at the top of code.py but it didn't seem to do the trick

@caternuson
Copy link
Collaborator

Don't have the RFM Feather, but looks like can recreate the same general issue with a basic Feather RP2040:

Adafruit CircuitPython 8.0.5 on 2023-03-31; Adafruit Feather RP2040 with rp2040
>>> import board
>>> from adafruit_bus_device.i2c_device import I2CDevice
>>> i2cdev = I2CDevice(board.I2C(), 82)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: No I2C device at address: 0x52
>>> i2cdev = I2CDevice(board.I2C(), 82)
>>>

Fails on first attempts. Succeeds on second. It's failing in the probe for device:

Adafruit CircuitPython 8.0.5 on 2023-03-31; Adafruit Feather RP2040 with rp2040
>>> import board
>>> i2c = board.I2C()
>>> i2c.try_lock()
True
>>> i2c.writeto(82, b"")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
OSError: [Errno 19] No such device
>>>  

The same thing works on a Feather M4:

Adafruit CircuitPython 8.0.5 on 2023-03-31; Adafruit Feather M4 Express with samd51j19
>>> import board
>>> i2c = board.I2C()
>>> i2c.try_lock()
True
>>> i2c.writeto(82, b"")
>>> 

So something RP2040 specific. Maybe with the empty write? Going to scope this to investigate further.

@caternuson
Copy link
Collaborator

Another interesting point - it works on the RP2040 with an official Wii Nunchuk:

Adafruit CircuitPython 8.0.5 on 2023-03-31; Adafruit Feather RP2040 with rp2040
>>> import board
>>> i2c = board.I2C()
>>> i2c.try_lock()
True
>>> i2c.writeto(82, b"")
>>>

So it's the combo of RP2040 + 3rd party nunchuk.

@caternuson
Copy link
Collaborator

Looks like a scan can be used to "wake it up" also. This is back with the 3rd party nunchuk:

Adafruit CircuitPython 8.0.5 on 2023-03-31; Adafruit Feather RP2040 with rp2040
>>> import board
>>> i2c = board.I2C()
>>> i2c.try_lock()
True
>>> _ = i2c.scan() ; i2c.writeto(82, b"")
>>> 

@BlitzCityDIY
Copy link
Contributor Author

yes that's been my finding too- official works fine with library as-is, third-party has the problem

@caternuson
Copy link
Collaborator

This is something specific to the RP2040 and the 3rd party Nunchuck. The behavior of the zero byte write done in I2CDevice._probe_for_device() with a Feather RP2040 and PID 342 controller is:
image

The behavior with an official Wii Nunchuck is:
image

The large gap between the start and write is odd and something RP2040 specific. The 3rd party controller ends up NAKing the write while the Wii one ACKs.

@caternuson
Copy link
Collaborator

@BlitzCityDIY An I2C scan seems to also work. What do you think of something like this?

    def __init__(
        self, i2c: I2C, address: int = 0x52, i2c_read_delay: float = 0.002
    ) -> None:
        self.buffer = bytearray(8)
        #-| HACK |---------------------------------------------------
        # fixes quirk with RP2040 + 3rd party controllers
        while not i2c.try_lock():
            pass
        _ = i2c.scan()
        i2c.unlock()
        #------------------------------------------------------------
        self.i2c_device = I2CDevice(i2c, address)
        self._i2c_read_delay = i2c_read_delay
        time.sleep(_I2C_INIT_DELAY)
        with self.i2c_device as i2c_dev:
            # turn off encrypted data
            # http://wiibrew.org/wiki/Wiimote/Extension_Controllers
            i2c_dev.write(b"\xF0\x55")
            time.sleep(_I2C_INIT_DELAY)
            i2c_dev.write(b"\xFB\x00")

@BlitzCityDIY
Copy link
Contributor Author

@caternuson cool yeah i think that's good

@caternuson
Copy link
Collaborator

OK. esp. want to have some very prominent comments about this being a hack to deal with a quirk. It's possible the behavior seen above in the scope traces could get changed (fixed?) via an update to the RP2040 code in the CP core. And then maybe the 3rd party controllers will be OK? (maybe??). But AFAIK, there's currently nothing else being affected by that RP2040 behavior. So shouldn't wait/hope for those core changes to happen to fix the issue here. Thus - a hack is needed :(

@BlitzCityDIY
Copy link
Contributor Author

totally yeah it seems that we've stumbled upon a deep edge case 🙂

@caternuson
Copy link
Collaborator

Yep. I believe the fancy tech term for this is "feature".

Wanna test that change on your setup to double check it works there also and then update PR?

@BlitzCityDIY
Copy link
Contributor Author

@caternuson yes just tested with the RFM feather and nunchuk from the shop and that fix is working consistantly. will update meow

@github-actions
Copy link

github-actions bot commented May 9, 2023

👋 Thanks for this pull request! Unfortunately, it looks like the automated continuous integration (CI) test(s) failed. These can be tricky to fix so we've written a guide on how to fix them locally. It has pages about running pre-commit locally and another about building the docs locally with sphinx. Thanks for contributing to CircuitPython! If you have more questions, feel free to join the Adafruit Discord and post in #circuitpython-dev.

@caternuson
Copy link
Collaborator

cool. thanks. LGTM.

one other idea to toss here just to document, could add a check for RP2040 and only run hack on that:

Adafruit CircuitPython 8.0.5 on 2023-03-31; Adafruit Feather RP2040 with rp2040
>>> import sys
>>> sys.platform
'RP2040'
>>>  

but i think OK to keep it simple for now and just run the hack for all. we'll see how this work when released into the wild.

@BlitzCityDIY BlitzCityDIY merged commit 34cd9a2 into main May 10, 2023
@BlitzCityDIY BlitzCityDIY deleted the thirdparty_nunchuk branch May 10, 2023 18:36
adafruit-adabot added a commit to adafruit/Adafruit_CircuitPython_Bundle that referenced this pull request Jun 27, 2023
Updating https://github.com/adafruit/Adafruit_CircuitPython_BNO055 to 5.4.10 from 5.4.9:
  > Reformatted per pre-commit
  > Update .pylintrc, fix jQuery for docs
  > Update pre-commit hooks

Updating https://github.com/adafruit/Adafruit_CircuitPython_INA260 to 1.3.13 from 1.3.12:
  > Merge pull request adafruit/Adafruit_CircuitPython_INA260#26 from adafruit/dev/fix-pylint-jquery
  > Merge pull request adafruit/Adafruit_CircuitPython_INA260#25 from tekktrik/dev/fix-pylint
  > Update pre-commit hooks
  > Add upload url to release action
  > Add .venv to .gitignore

Updating https://github.com/adafruit/Adafruit_CircuitPython_Nunchuk to 1.1.8 from 1.1.7:
  > Update .pylintrc, fix jQuery for docs
  > Run pre-commit
  > Update pre-commit hooks
  > Merge pull request adafruit/Adafruit_CircuitPython_Nunchuk#34 from adafruit/thirdparty_nunchuk
  > Add upload url to release action

Updating https://github.com/adafruit/Adafruit_CircuitPython_PCA9685 to 3.4.10 from 3.4.9:
  > Merge pull request adafruit/Adafruit_CircuitPython_PCA9685#56 from adafruit/dev/fix-plyint-jquery
  > Merge pull request adafruit/Adafruit_CircuitPython_PCA9685#53 from DrRob/fix-duty-cycle

Updating https://github.com/adafruit/Adafruit_CircuitPython_Seesaw to 1.13.0 from 1.12.1:
  > Merge pull request adafruit/Adafruit_CircuitPython_seesaw#117 from kattni/add-gamepad-qt
  > Update .pylintrc, fix jQuery for docs
  > Merge pull request adafruit/Adafruit_CircuitPython_seesaw#115 from adafruit/ano_rotary_examples

Updating https://github.com/adafruit/Adafruit_CircuitPython_SSD1306 to 2.12.14 from 2.12.13:
  > Update .pylintrc, fix jQuery for docs
  > Merge pull request adafruit/Adafruit_CircuitPython_SSD1306#80 from DJDevon3/WorkingBranch

Updating https://github.com/adafruit/Adafruit_CircuitPython_Debouncer to 2.0.6 from 2.0.5:
  > Merge pull request adafruit/Adafruit_CircuitPython_Debouncer#42 from tekktrik/dev/move-hw-unittest
  > Update .pylintrc, fix jQuery for docs
  > Update pre-commit hooks
  > Add upload url to release action
  > Add .venv to .gitignore
  > Update .pylintrc for v2.15.5
  > Fix release CI files
  > Update pylint to 2.15.5
  > Updated pylint version to 2.13.0
  > Switching to composite actions

Updating https://github.com/adafruit/Adafruit_CircuitPython_MacroPad to 2.2.1 from 2.2.0:
  > Update .pylintrc, fix jQuery for docs
  > Run pre-commit
  > Update pre-commit hooks
  > Merge pull request adafruit/Adafruit_CircuitPython_MacroPad#46 from kalehmann/fix-45/wake-display-during-init

Updating https://github.com/adafruit/Adafruit_CircuitPython_Bundle/circuitpython_library_list.md to NA from NA:
  > Updated download stats for the libraries
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants