rm-hull / luma.core

A component library providing a Pillow-compatible drawing canvas, and other functionality to support drawing primitives and text-rendering capabilities for small displays on the Raspberry Pi and other single board computers.
https://luma-core.readthedocs.io
MIT License
148 stars 52 forks source link

"OSError: [Errno 95] Operation not supported" when attempting to use i2c_rdwr function on SMBus i2c interface #276

Open ryjelsum opened 6 months ago

ryjelsum commented 6 months ago

(Alternate title; Feature request: 'strict' SMBus i2c mode)

Hi, this is a bit of an odd one, but I'd figure I'd throw it up here if not for somebody to address, then to document the solution a little bit better for anyone else who's run into this issue (or similar) down the line.

I've been playing around with the example programs on my x86 desktop PC, with various i2c USB dongles, as well as hooking LCDs (character and OLED) up to the SMBus on my motherboard, since it has a header for it. luma.lcd has worked fine in my very limited testing, but I ran into some issues with attempting to run luma.oled on an I2C OLED display; the error that is in the title.

Full traceback:

jrg@tremere ~/src/$ ~/src/luma/bin/python ~/src/luma.examples/examples/perfloop.py -d ssd1306 -i i2c --width 128 --height 64 --i2c-port=6
Testing display rendering performance
Press Ctrl-C to abort test

Traceback (most recent call last):
  File "/home/jrg/src/luma.examples/examples/perfloop.py", line 55, in <module>
    main()
  File "/home/jrg/src/luma.examples/examples/perfloop.py", line 28, in main
    device = get_device()
  File "/home/jrg/src/luma.examples/examples/demo_opts.py", line 59, in get_device
    device = cmdline.create_device(args)
  File "/home/jrg/src/luma/lib/python3.10/site-packages/luma/core/cmdline.py", line 241, in create_device
    device = Device(serial_interface=interface(), **params)
  File "/home/jrg/src/luma/lib/python3.10/site-packages/luma/oled/device/__init__.py", line 279, in __init__
    self.clear()
  File "/home/jrg/src/luma/lib/python3.10/site-packages/luma/core/mixin.py", line 46, in clear
    self.display(Image.new(self.mode, self.size))
  File "/home/jrg/src/luma/lib/python3.10/site-packages/luma/oled/device/__init__.py", line 311, in display
    self.data(list(buf))
  File "/home/jrg/src/luma/lib/python3.10/site-packages/luma/core/device.py", line 55, in data
    self._serial_interface.data(data)
  File "/home/jrg/src/luma/lib/python3.10/site-packages/luma/core/interface/serial.py", line 131, in data
    write(list(data[i:i + block_size]))
  File "/home/jrg/src/luma/lib/python3.10/site-packages/luma/core/interface/serial.py", line 140, in _write_large_block
    self._bus.i2c_rdwr(self._i2c_msg_write(self._addr, [self._data_mode] + data))
  File "/home/jrg/src/luma/lib/python3.10/site-packages/smbus2/smbus2.py", line 658, in i2c_rdwr
    ioctl(self.fd, I2C_RDWR, ioctl_data)
OSError: [Errno 95] Operation not supported

The root of the issue is that apparently, i2c_rdwr is not included / supported by (all) SMBus interfaces, but it is included in the python smbus library nonetheless. I'm putting the issue here since it seems to be an issue with some of the core component.

I have managed to get this "functional", in the sense that is now outputting to the display, by going into the serial.py file, in the 'data' function, and replacing "if self._managed:" with "if False:". (forcing it to always act as 'unmanaged' by the smbus library, as I understand it?) This is a hack, it massively hurts performance, and I'm pretty damn sure it's not the best way to do it, it was just the only way I could understand how. It'd be cool to see if this issue could be addressed in a less amateur way.

Totally understand if this is not something you want to touch, because this is well outside of the intended use case of single-board computers. Just didn't want to feel like all this work went to waste :)

thijstriemstra commented 6 months ago

let's start with the essential: what smbus version? what python version? luma.core version? etc??

ryjelsum commented 6 months ago

My bad, I shouldn't be filing issues late at night :)

Python 3.10.14, smbus2 version 0.4.3, luma.core version 2.4.2, luma.oled version 3.13.0, on NixOS 23.11, kernel 6.6.30.