Skip to content

make TCA work for slaves with same address or even in general #38

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
wants to merge 1 commit into from

Conversation

ingenerd
Copy link

@ingenerd ingenerd commented Jun 5, 2022

In order to route an i2c request to a connected slave, the tca itself has to make sure that the right path to the slave is set. There was no such thing in the code. If I am right, then without my code change, only one or no slave could be addressed... the reported bug one year ago sounds like suffering from this lack, too.
I added this one line: "self.tca.i2c.writeto(self.tca.address, self.channel_switch)" before all requests (readfrom_into, writeto, and write_then_readfrom). With this, the TCA register will be set with the desired channel_switch. I do not know, whether this is thread safe. It might not... but without it, the TCA will not work at all. If so, please add it to the main branch. If am totally misunderstanding, then please just forget about this. In any case: Thank you for your time.

In order to route an i2c request to a connected slave, the tca itself has to make sure that the right path to the slave is set. There was no such thing in the code. If I am right, then without my code change, only one or no slave could be addressed... the reported bug one year ago sounds like suffering from this lack, too. 
I added this one line: "self.tca.i2c.writeto(self.tca.address, self.channel_switch)" before all requests (readfrom_into, writeto, and write_then_readfrom). With this, the TCA register will be set with the desired channel_switch. I do not know, whether this is thread safe. It might not... but without it, the TCA will not work at all. If so, please add it to the main branch. If am totally misunderstanding, then please just forget about this. In any case: Thank you for your time.
@ladyada ladyada requested a review from caternuson June 5, 2022 21:13
@ladyada
Copy link
Member

ladyada commented Jun 5, 2022

pretty sure thats what the lock/unlock part is doing - did you try the examples?

@caternuson
Copy link
Contributor

Yep, it's taken care of with lock/unlock. Example should work. The current library sort of works automagically. The plumbing is not super obvious by just looking at the code. Here's the specific line that does the muxing:

self.tca.i2c.writeto(self.tca.address, self.channel_switch)

But it requires the library code be written to use it.

This general manual muxing need keeps coming up. Opened a related issue for this a while back:
#28
Looks like it got lost in some discussion. This PR looks to be essentially what is suggested there, except for the check if still on current channel and don't mux if not needed.

@ingenerd What are you using the TCA with?

@ingenerd
Copy link
Author

ingenerd commented Jun 6, 2022

Ahhhh, I see. Okay - I created the problem;-)
To explain, why I came up with the pull request:
I use a couple of deprecated BMP180 sensors for pressure and temperature. Since those are out of scope only the successor sensor BMP is integrated in the new CircuitPython libraries. The old library for the BMP180 is called BMP085.
So I took the code of the BMP085 library and rewrote it to work with CircuitPython... let's better say I tried.;-) I uploaded this code on my github account here: https://github.com/ingenerd/BMP180
I tried to orientate myself with the code of the TSL2591 sensor, because this sensor is in your examples for the TCA9548a. My solution only works, when the BMP180 is directly connected to the i2c channels. For the TCA it did not work - so I dove into that code, understood some parts of it of it and played around until I got my sensors to work resulting in this pull request.

I do not understand all of the TCA code. The locking part is a little piece of magic to me. So in order to get my BMP180 going, I assume, I habe to integrate the locking mechanism into my code. If possible, could you please push me into the right direction, where I have to look for orientation?
Thanks again for your time.

@caternuson
Copy link
Contributor

You don't need to directly lock / unlock in your driver code. Instead, use a context manager (the with block). For example, here's the basic write in the TSL2591 driver:
https://github.com/adafruit/Adafruit_CircuitPython_TSL2591/blob/1b266923a5ff96be2ac8df6b3508c14f2814eedf/adafruit_tsl2591.py#L158-L162

If you write your driver code like that, and then also pass in a TCA channel (not the TCA itself), like this:

bmp = BMP180(tca[0])

then it should work.

The context manager calls the dunder methods __enter__ at the start and __exit__ at the end. That's what takes care of the lock / unlock.
https://github.com/adafruit/Adafruit_CircuitPython_BusDevice/blob/a8e263bbc013329ff1087fa3b8858c1dcc18b842/adafruit_bus_device/i2c_device.py#L151-L163
That's some Python magic. Nothing specific to CircuitPython.

TLDR = you should be able to get this to work with some minor changes to your driver code

@ingenerd
Copy link
Author

ingenerd commented Jun 6, 2022

@caternuson Tanks. I got it. Very minor changes indeed in my code do the trick. Excellent. Thank you very much for everything.

@ingenerd ingenerd closed this Jun 6, 2022
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.

3 participants