Closed remisarrailh closed 2 years ago
Hmm...since displayio.I2CDisplay()
is a core function, the type checking is happening in the C code. And tca[0]
is of type TCAChannel
. When tca[0]
is more typically passed to other CircuitPython libraries, the strict type checking does not occur in that scenario.
It doesn't look like inheritance could solve this:
Adafruit CircuitPython 7.2.5 on 2022-04-06; Adafruit ItsyBitsy M4 Express with samd51g19
>>> import board
>>> import busio
>>> import displayio
>>> class Foo(busio.I2C):
... def bar(self):
... print("hello")
...
>>> foo = Foo(board.SCL, board.SDA)
>>> display_bus = displayio.I2CDisplay(foo, device_address=0x3C)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: i2c_bus must be of type I2C
>>> type(foo)
<class 'Foo'>
>>>
Right, this is not going to work. The communication with the I2C display is done directly via the busio.I2C()
implementation, at the C level, so you can't substitute a duck-typed I2C device.
An emulation of displayio
and I2CDisplay
could be written in python, but it would probably not run very fast.
You can support multiple displays by using the address selector line on the SSD1306 to make it respond to another address (0x3D instead of 0x3C), but that only works for two displays per I2C bus. You can use another I2C bus, and if you run out of I2C busses, you can start using bitbangio.I2C
on yet more pins. At some point you may run out of RAM to support so many displays.
Another option might be to manually mux the TCA? Essentially, don't use this library. Pass in the main I2C bus displayio.I2CDisplay()
. Your application code would then need to take care of switching TCA channels between any displayio
calls to the displays attached to the various channels.
@caternuson Thanks this solution works.
Of course my code is more of a dirty hack then a functional one and update is not really fast (I need to release displays each times for it to works and add a sleep or else some display will not update, or the code even crash).
I'm also using tiny oled (72x42) and I have a weird offset error (that's why I used a Width/height different to its size, seems to works fine) but I digress.
I managed to make it works without resetting the display if I manually create each display on the terminal, and restart (CTRL-D)
import board
import displayio
import terminalio
import adafruit_displayio_ssd1306
from adafruit_display_text import label
import time
# Create I2C bus as normal
displayio.release_displays()
def tca_select(channel):
while not i2c.try_lock():
pass
i2c.writeto(0x70, bytearray([1 << channel]))
i2c.unlock()
i2c = board.I2C() # uses board.SCL and board.SDA
n = 0
while True:
for i in range(0,8):
tca_select(i)
display_bus = displayio.I2CDisplay(i2c, device_address=0x3C)
display = adafruit_displayio_ssd1306.SSD1306(display_bus, width=100, height=42)
print("TCA Channel: " + str(i))
text = str(i + n)
text_area = label.Label(terminalio.FONT, text=text, scale=5, color=0xFFFF00, x=40, y=16)
display.show(text_area)
time.sleep(0.05)
displayio.release_displays()
n = n + 1
I posted my solution on Gists for posterity https://gist.github.com/maditnerd/c0da9b2b81544ecf21220ed2a1321dd7
My goal was to make a midi sequencer with button underneath the screen, (each screen displaying the note on each step) but I'll probably never have a refresh rate good enough for that, even if I use C, I'll figure out something else.
https://user-images.githubusercontent.com/2841495/168129648-78e0cdc7-84ba-4e2b-a495-239f2d45935b.mov
I guess you can close the issue, since I have a solution which doesn't involve using the library.
What refresh rate do you need? You're looping on initialization code above. Might buy back some performance by removing that from loop. Like here:
display_bus = displayio.I2CDisplay(i2c, device_address=0x3C)
display = adafruit_displayio_ssd1306.SSD1306(display_bus, width=100, height=42)
But agree this approach is a bit hack-ish and will result in somewhat messy code. Since the TCA muxing will need to be carefully (and manually) interleaved with all the displayio calls.
Going to close issue since this is essentially something that won't work for reasons danh mentions above. Unfortunately. Sorry though. Looks like a really cool project.
I'm trying to plug 8 SSD1306 display using a TCA9548A multiplexer (on a Adafruit NRF Sense board). When I scan them, it correctly detects each displays
Unfortunately when I try to initialize the display, I get an TypeError as the tca channel object is not a I2C object.