Ah, solved it!
Turns out the example at driver/generic/lvindev_example.py
is all wrong, possibly describing a previous API. One does not need ‘modlvindev’ anymore, and the convention for the callback is a little different than is documented. The callback gets two arguments: a pointer to the lv_indev_drv_t
that you initialised with and a pointer to the lv_indev_data_t
that holds the coordinates.
The README at the lv_binding_micropython
GitHub Repo used the current API when they show using the SDL mouse driver:
# Register SDL mouse driver
indev_drv = lv.indev_drv_t()
indev_drv.init()
indev_drv.type = lv.INDEV_TYPE.POINTER
indev_drv.read_cb = SDL.mouse_read
indev_drv.register()
But then you still have to work out how the callback is called, which can be gleaned from the source. Clearly documentation is lacking here, and the included example is flat-out wrong. I’ll file an issue.
To see how it’s done: below is a complete, working, freshly-tested driver for the FT6X36 touch IC:
import lvgl as lv
from machine import I2C, Pin
class ft6x36:
def __init__(self, i2c_dev=0, sda=21, scl=22, addr=0x38, size_x=320, size_y=280, inv_x=False, inv_y=False, swap_xy=False):
self.size_x, self.size_y = size_x, size_y
self.inv_x, self.inv_y, self.swap_xy = inv_x, inv_y, swap_xy
self.i2c = I2C(i2c_dev, sda=Pin(sda), scl=Pin(scl))
self.addr = addr
self.point = lv.point_t( {'x': 0, 'y': 0} )
self.state = lv.INDEV_STATE.REL
indev_drv = lv.indev_drv_t()
indev_drv.init()
indev_drv.type = lv.INDEV_TYPE.POINTER
indev_drv.read_cb = self.callback
indev_drv.register()
def callback(self, driverptr, dataptr):
sensorbytes = self.i2c.readfrom_mem(self.addr, 2, 5)
points = sensorbytes[0]
x = (sensorbytes[1] << 8 | sensorbytes[2]) & 0x0fff
y = (sensorbytes[3] << 8 | sensorbytes[4]) & 0x0fff
if x < self.size_x and y < self.size_y:
x = size_x - x - 1 if self.inv_x else x
y = size_y - y - 1 if self.inv_y else y
(x, y) = (y, x) if self.swap_xy else (x, y)
if points == 1 or points == 2:
self.point = {'x': x, 'y': y}
self.state = lv.INDEV_STATE.PR
elif points == 0:
self.state = lv.INDEV_STATE.REL
data = lv.indev_data_t.cast(dataptr)
data.point = self.point
data.state = self.state
return False
On my M5Stack Core2, the following gives me a pressable button:
import lvgl as lv
from ili9XXX import ili9341
from ft6x36 import ft6x36
disp = ili9341(mosi=23, miso=38, clk=18, dc=15, cs=5, invert=True, rot=0x10)
touch = ft6x36()
scr = lv.obj()
btn = lv.btn(scr)
btn.align(lv.scr_act(), lv.ALIGN.CENTER, 0, 0)
label = lv.label(btn)
label.set_text("Button")
# Load the screen
lv.scr_load(scr)