Event based indev (input device) data processing

Is it possible feature to support on the future?

I’m not as familiar with the lvgl code as you, do you think the support for it require a modification on the architecture of lvgl?

Yes. LittlevGL does not have a queue for processing event-based input. So it would require significant changes to the input logic. I’m not sure that @kisvegabor thinks that is necessary at this time.

Well, it’s not a requirement that needs to be addressed on the near future, maybe it’s impractical to implement after all.

I don’t know what is the approach on other graphic libraries for embedded, i will try to take a look at them and see if it’s possible to adapt something in here.

MBED OS have a event queue implementation, it’s discussed here:
Office Hours - Event Queue - Chris Haster

OT: Changed the topic title, i think now it’s better.

Hi,

What you can do is to use the interrupt PIN as you want, e.g. queue the touched points and read that queue in the read function. You can return true to indicate that there is more data to read.

If the queue is empty you need to only set the data to the last value.

Thanks, my end goal is to use only one SPI Master for both TFT controller and touch controller and i think using the touch interrupt can help me with that.

Note that the display related SPI transfer is started from lv_task_handler (main while(1) probably.) It can cause problems if you use the same SPI in an interrupt.

I am struggling with this a bit as well. All of my GUI updates are event driven (interrupts from touch, encoders, clocks, etc). The events trigger many GUI changes: locations of GUI objects, text strings, etc.

I have an lv refresh task that is blocked by a semaphore that is unblocked by an event, but this task could be pre-empted by another event task that ends up changing the GUI in the middle of the lv refresh and causes problems with the refresh. The lv refresh task does not execute on it’s own periodically and I am not using things like animation.

With so many event types, I’m not sure how to use a queue for the lv refresh task, but I’m also not sure how to make sure that interrupts don’t corrupt the VDB during lv refresh.

You either have to disable interrupts while lv_task_handler is running, or, better yet, avoid calling LittlevGL from an interrupt handler.

In a multitasking system, the simplest method to use is to guard all calls to LittlevGL with a mutex.

The general rule with LittlevGL is that only one thread can ever be using it at a time.

The interrupts are timing critical, so they can’t be disabled during a refresh. The lv task semaphore is given by a task that is unblocked by the interrupt. Context is switched when the interrupt handler completes. LVGL isn’t called directly by the handler.

Would using a double VDB solve this situation? The refresh would be running from one VDB, while updates to objects would be hitting the other VDB?

Then you have to avoid using LittlevGL directly inside these interrupts.

I’m a bit confused now. What is the exact issue?

The issue is that various events (clocks, buttons, etc) all update lvgl objects directly. This may happen while an lv refresh is currently executing.

example:

  • a timer interrupt results in an lvgl object location being directly updated
  • after the lv object location update, the lv refresh is unblocked, a refresh takes ~3mS
  • while the lv refresh is still executing, a second event occurs (physical button is pressed)
  • the button handler results in an lvgl object (text string) being directly updated.
  • because the lv refresh is still executing when we return from the button handler, it misses some of the updated VDB caused by the button handler, causing corruption of the display

Okay. I think I understand your problem now.

You can’t be calling LittlevGL APIs from inside your interrupt handlers, unless you can guarantee that lv_task_handler isn’t running at the same time (which can only be done by disabling those interrupts).

If you can find a way of moving LittlevGL calls out of timing-critical interrupts, you could leave those enabled and disable all other interrupts.

I was hoping that using doublevdb would eliminate the contention between object updates and a running lv refresh.

The problem here is that you are making concurrent calls to LittlevGL APIs. The only way to solve that is to not do it :wink: .

As far as I can tell the refresh corruption is merely a symptom of the problem.

Hi,

Has the touch interrupt (as Carlos_Diaz asked) already been implemented in the littlevgl library ?

I would like to use interrupt of FT6236 touch controller to wake up only the display or wake up all the system or to make lib littlevgl read the touch only when the display controller sends an interrupt signal.

Thank’s.

Hi,

In dev-7.0 @embeddedt implemented that the display refresh, the indev read and the animation tasks shuts down themself when they have nothing to do. So from LittlevGL’s side no task will be executed if you UI does nothing.

lv_task_handler returns the time to the next task to execute, i.e. you can sleep this long. LV_NO_TASK_READY will be returned if there are no tasks to run.

It allows you to sleep until any external event (e.g. touch interrupt) happens.

Actually, the indev task does not shut itself down yet. I haven’t gotten to the input system yet. So, if you have an input device registered, lv_task_handler will still run every 30ms.

Sorry for the confusion.

However, you can stop it manually e.g. if there are no interrupts for 300 ms.

Hi Baldhead. I was too thinking this would be a nice feature, but as i started looking into it I just added to touchpad_read() to only read I2C if an interrrupt has occured. Now there is very little overhead when nothing is being updated on the display.

BTW, first post - stumbled upon this library and am really enjoying using it!

3 Likes

So currently I have the need to stop the constant polling of the TOUCH driver.
I am trying to connect three devices to the spi bus… sd card, display and touch.
All devices connect to the SBI bus (example shown below) but when I list directory in a while loop, periodically it returns errors.
This is due to collisions between the SD card and the touch driver.
By using touch.indev_drv.set_read_cb(None) prevents the read function from running that causes the collision.
But now I need a manual way to monitor an IRQ Pin to fire the touch read() function.
So I need a method to remove the auto polling to a manual IRQ Pin touch.
Collisions still will happen but I’m hoping to use some type of flag to prioritize SD over touch.

I believe LVGL should be dormant until called upon to refresh a screen or to react to a touch via an IRQ.
I am trying to stop as much unnecessary traffic on the SPI bus as we are trying to troubleshoot lost interrupts and other issues that is causing crashes within hours to days.

If I comment out… touch.indev_drv.set_read_cb(None)
I get [Errno 5] EIO

Example…

import lvgl as lv
from ili9XXX import ili9341
from xpt2046 import xpt2046
import os, time, sdcard
from machine import SPI, Pin

# Mount SD Card
sd = sdcard.SDCard(SPI(2), Pin(14), baudrate=10000000)
os.mount(sd, '/sd')
# Load Graphics Touch Drivers
lv.init()
disp = ili9341(spihost=2, miso=-1, mosi=-1, clk=-1, cs=15, mhz=10, dc=13, rst=-1, power=-1, factor=48, half_duplex=False, double_buffer=True, backlight=27, backlight_on=1)
touch = xpt2046(spihost=2, cs=5, mhz=1, half_duplex=False)

def button_cb(e):
	if e.get_code() == lv.EVENT.CLICKED:
		u_name.set_text('Got Clicked')
		print('clicked !!!')
scr = lv.scr_act()
u_name = lv.label(scr)
u_name.align(lv.ALIGN.TOP_MID, 0, 40)
u_name.set_style_text_font(lv.font_montserrat_20, 0)
u_name.set_text('S P I  Issues')
btn = lv.btn(scr)
btn.align(lv.ALIGN.TOP_MID, 0, 200)
btn.add_event(button_cb, lv.EVENT.CLICKED, None)
btn_lbl = lv.label(btn)
btn_lbl.set_text("CLICK Me")
lv.scr_load(scr)

touch.indev_drv.set_read_cb(None)		# stops touch from (reading) !!!!!

da_num = 1
while True:
	try:
		u_name.set_text(str(da_num))
		time.sleep_ms(50)	# THIS IS VERY IMPORTANT !!!!!!!!!!!!!!!!!
		print(os.listdir('sd/data'))
	except Exception as e:
		print(e)
	da_num += 1
	time.sleep_ms(500)

How can I stop this “indev task” and assign this to an IRQ?
btw, I am using lv_micropython master (v9)

Help much appreciated