Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Limit reads & cache values #2

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

Closed
caternuson opened this issue Jul 22, 2019 · 4 comments
Closed

Limit reads & cache values #2

caternuson opened this issue Jul 22, 2019 · 4 comments
Labels
enhancement New feature or request

Comments

@caternuson
Copy link
Collaborator

NOTE This issue by @ATMakersBill transferred from original repo.

It looks like there's code to read the i2c bus and keep the results for future calls to joystick, acceleration, and buttons. However, the button code doesn't seem to update the buffer.

It looks like it would be possible to make fewer reads and improve performance. Here's my suggestion....

  1. Add an optional parameter to the init() that takes a maxAge parameter (default to .1sec?).
  2. In __read_data() keep track of whether it's been over maxAge since the last read. If not use the current buffer. If you do a read, update the last read time
  3. If maxAge is set to zero, then it would always fetch on every read.
  4. If maxAge is set to -1 then the data read calls would never call read_data: the user would need to call a public method (read_data()?) to fetch the data.

I think that would give full control to the clients of the library.

@kattni kattni added the enhancement New feature or request label May 4, 2020
@caternuson
Copy link
Collaborator Author

This would simply report back the previous state unless maxAge is exceeded? So button presses could be missed, or continue to be reported as pressed, during maxAge amount of time? Say maxAge is set to 5 seconds for example. You'd have 5 seconds where button pressed would not be read?

@caternuson
Copy link
Collaborator Author

caternuson commented Jan 23, 2021

I'm going to use this issue thread to document some sniffing of I2C traffic between a Wiimote and a Nunchuk. This information may prove useful for "tuning" the i2C specifics for this driver.

This issue thread relates to the general slowness of the current read implemented in the driver. This is caused by the injection of hardwired sleeps. A single read takes 10's of ms as a result. Those delays were taken from existing Arduino libraries which did the same, and just generally accepted as necessary at the time of the initial writing of this driver. Blind attempts to reduce / remove them resulted in mixed success. So more information was needed.

How does the original hardware, the Wiimote-Nunchuk combo, talk to each other? Let's find out...

Hardware Setup

setup

Basic idea is to use a Pi 4 as a host and connect the Wiimote to it via Bluetooth. The Nunchuk cable was cut and a Nunchucky breakout was added to allow access to the pins. A Saleae was connected there.

Software Setup

Used this python3-wiimote library, built locally on Pi. Connect to the Wiimote from the Pi. Ran things interactively:

$ python3
Python 3.7.3 (default, Dec 20 2019, 18:57:59) 
[GCC 8.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import cwiid
>>> wiimote = cwiid.Wiimote()  
>>> wiimote.rpt_mode = cwiid.RPT_BTN | cwiid.RPT_EXT
>>> wiimote.state
{'rpt_mode': 242, 'led': 1, 'rumble': 0, 'battery': 102, 'ext_type': 1, 'error': 0, 'buttons': 0, 'nunchuk': {'stick': (128, 129), 'acc': (73, 134, 142), 'buttons': 0}}
>>> wiimote.state['nunchuk']['stick']
(128, 129)
>>> 

etc.

Results

Here's a 1 second sample of the resulting traffic:
image
Looks like the Wiimote is constantly polling the Nunchuk.

Zooming in:
image
There's an approximately 9.5ms delay between each read.

Zooming in on an individual read:
image
There's an initial write to setup the read request with an approximately 0.20ms delay between the write and read. The entire read takes about 0.65ms.

Here's the write request:
image
which is nothing fancy. Just your basic write setup to address 0x52 and "register" address 0x00 followed by a stop.

Here's the read:
image
Note that 8 bytes are clocked out.

Zooming in on the last read:
image
It ends with a NAK, which is the master saying "i'm done". Also note that the SCL frequency is 375kHz.

Here's the trace file for future ref:
wiimote_nunchuk_i2c.zip

@caternuson
Copy link
Collaborator Author

The 9.5ms delay between reads is possibly the Wiimote's polling rate and not any kind of rate limit of the Nunchuk itself. The start-to-start time on reads is pretty much 10ms, which is a nice happy little round number for a polling IRQ running on the Wiimote.

With the base read modified to be (_I2C_READ_DELAY = 0.001):

    def _read_data(self):
        with self.i2c_device as i2c:
            i2c.write(b"\x00")
            time.sleep(_I2C_READ_DELAY)
            i2c.readinto(self.buffer)

and running this spam read example on an Itsy M4:

import board
import busio
import adafruit_nunchuk

i2c = busio.I2C(board.SCL, board.SDA, frequency=375000)

nc = adafruit_nunchuk.Nunchuk(i2c)

while True:
    x, y = nc.joystick

it seems to read just fine.

This seems to indicate that there's no need for any extra delay between reads, from the Nunchuk's point of view.

@caternuson caternuson mentioned this issue Jan 24, 2021
@caternuson
Copy link
Collaborator Author

Closing this for now. I'm hoping the improvements from #20 make this no longer necessary.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

2 participants