Refresh all objects in task

Hello,

My application is based on sysmon app example.

I have created all my object and styles in main thread.

When the refresh task is called only changed objects are displayed.

How do I force the refresh of all object ?

Hi,

LittlevGL should take care or the refreshing properly. There should be an issue in your code or driver. Can you send a screenshot to see exactly what happens?

1 Like

Yes, this is a screenshot after objects creation

And this is after the task refreshing, only changed objects is displayed

This is part of my config

#define LV_HOR_RES (128)
#define LV_VER_RES (128)

#define LV_VDB_SIZE ((LV_VER_RES * LV_HOR_RES))

#define LV_VDB_DOUBLE 1

Strange. It should work.
How does your display driver look like?

disp_map and disp_fill are not implemented because not used.

this is the disp_flush

static void disp_flush(int32_t x1, int32_t y1, int32_t x2, int32_t y2, const lv_color_t * color_p)
{
    /*The most simple case (but also the slowest) to put all pixels to the screen one-by-one*/

    int txLen = 512;
    int remain = (x2-x1+1)*(y2-y1+1)*sizeof(lv_color_t);
    unsigned char *pBuffer = color_p;

    command(SSD1351_CMD_SETCOLUMN);
    command(x1);         //cloumn start address
    command(x2);    //OLED_WIDTH - 1); //cloumn end address
    command(SSD1351_CMD_SETROW);
    command(y1);         //page atart address
    command(y2);    //OLED_HEIGHT - 1); //page end address
    command(SSD1351_CMD_WRITERAM);

    digitalWrite(DC, HIGH);
    while (remain > txLen)
    {
        wiringPiSPIDataRW(CHANNEL, pBuffer, txLen);
        remain -= txLen;
        pBuffer += txLen;
    }
    wiringPiSPIDataRW(CHANNEL, pBuffer, remain);


    /* IMPORTANT!!!
     * Inform the graphics library that you are ready with the flushing*/
    lv_flush_ready();

}

And this is initialisation for ssd1351

static void command(unsigned char cmd)
{
    digitalWrite(DC, LOW);
    wiringPiSPIDataRW(CHANNEL, &cmd, 1);
}

static void data(unsigned char cmd) 
{
digitalWrite(DC, HIGH);
wiringPiSPIDataRW(CHANNEL, &cmd, 1);
}
/* Initialize your display and the required peripherals. */
static void disp_init(void)
{
/*You code here*/
pinMode(RST, OUTPUT);
pinMode(DC, OUTPUT);
wiringPiSPISetup(CHANNEL, 2000000);    //2M

digitalWrite(RST, HIGH);
delay(10);
digitalWrite(RST, LOW);
delay(10);
digitalWrite(RST, HIGH);


command(SSD1351_CMD_COMMANDLOCK);
data(0x12); 								// Unlock OLED driver IC MCU interface from entering command
command(SSD1351_CMD_COMMANDLOCK);
data(0xB1);								// Command A2,B1,B3,BB,BE,C1 accessible if in unlock state 
command(SSD1351_CMD_DISPLAYOFF);			// Display off, no args
command(SSD1351_CMD_CLOCKDIV);
data(0xF1);								// 7:4 = Oscillator Freq, 3:0 = CLK Div Ratio (A[3:0]+1 = 1..16)
command(SSD1351_CMD_MUXRATIO);
data(127);

command(SSD1351_CMD_SETREMAP);
data(0x74);

command(SSD1351_CMD_SETCOLUMN);;
data(0x00);
data(0x7F);
command(SSD1351_CMD_SETROW);
data(0x00);
data(0x7F);

command(SSD1351_CMD_STARTLINE);
data(0);

command(SSD1351_CMD_DISPLAYOFFSET);
data(0x00);
command(SSD1351_CMD_SETGPIO);
data(0x00);
command(SSD1351_CMD_FUNCTIONSELECT);
data(0x01);								// internal (diode drop)
command(SSD1351_CMD_PRECHARGE);
data(0x32);
command(SSD1351_CMD_VCOMH);
data(0x05);
command(SSD1351_CMD_NORMALDISPLAY);
command(SSD1351_CMD_CONTRASTABC);
data(0xC8);
data(0x80);
data(0xC8);
command(SSD1351_CMD_CONTRASTMASTER);
data(0x0F);
command(SSD1351_CMD_SETVSL);
data(0xA0);
data(0xB5);
data(0x55);
command(SSD1351_CMD_PRECHARGE2);
data(0x01);
command(SSD1351_CMD_DISPLAYON);				// Main screen turn on

}

I have found the problem.

In the main thread I create 4 screens like that

//create all screens
home_screen = lv_scr_act(); //lv_obj_create(NULL, NULL);
sensor_a_screen = lv_obj_create(NULL, NULL);
sensor_b_screen = lv_obj_create(NULL, NULL);
config_screen = lv_obj_create(NULL, NULL);

lv_scr_load(home_screen);

I just add the lv_scr_load(home_screen); at the beginning of my task and it is ok, I have now the entire screen refreshed.

Glad to hear that you found the problem. Although it shouldn’t matter in general. Maybe it’s related to the other parts of your code.

So I don’t know where is the problem, I have tried to comment all other screen, same.

Let’s try something really simple: one screen with two buttons and nothing else. Is it working well?

I have reproduced the problem with very simple test :
If I uncomment lv_scr_load(home_screen); the two labels are refreshed else only label1

#include "regulants.h"
#include <stdio.h>
#include <stdint.h>
#include <unistd.h>
#include <signal.h>
#include <sys/time.h>
#include <time.h>


static void sysmon_task(void * param);

static lv_task_t * refr_task;

lv_obj_t * label1;
lv_obj_t * btn1;
lv_obj_t * label2;

#define REFR_TIME    500

timer_t gTimerid;

void timer_handler (int signum)
{
    lv_tick_inc(1);
}

void main(void)
{

    /***********************
     * Initialize wiringPi
     ***********************/
    if (wiringPiSetup() < 0)
    {
        return;
    }

    /***********************
     * Initialize LittlevGL
     ***********************/
    lv_init();
    lv_port_disp_init();

    /***********************
     * Initialize Theme
     ***********************/

    lv_theme_zen_init(0 /* hue */,&lv_font_monospace_8 /* use LV_FONT_DEFAULT */);
    lv_theme_set_current( lv_theme_get_zen() );
    lv_obj_set_style(lv_scr_act(), lv_theme_get_current()->bg);

    /***********************
     * Initialize Tick timer
     ***********************/
    (void) signal(SIGALRM, timer_handler);

    struct itimerspec value;

    value.it_value.tv_sec = 0;
    value.it_value.tv_nsec = 1;

    value.it_interval.tv_sec = 0;
    value.it_interval.tv_nsec = 1;

    timer_create (CLOCK_REALTIME, NULL, &gTimerid);

    timer_settime (gTimerid, 0, &value, NULL);


    LV_LOG_TRACE("Set tick timer 1 ms ok");

    /*
     *   Testsq
     */
    sysmon_create();

    while(1)
    {
        /* Periodically call this function.
         * The timing is not critical but should be between 1..10 ms */
        lv_task_handler();


        delay(5);
    }

}


/**
 * Initialize the system monitor
 */
void sysmon_create(void)
{

    refr_task = lv_task_create(sysmon_task, REFR_TIME, LV_TASK_PRIO_LOW, NULL);

    /*Create a title label*/
    label1 = lv_label_create(lv_scr_act(), NULL);
    lv_label_set_text(label1, "Default buttons");
    lv_obj_align(label1, NULL, LV_ALIGN_IN_TOP_MID, 0, 5);

    /*Add a label to the button*/
    label2 = lv_label_create(lv_scr_act(), NULL);
    lv_obj_align(label2, label1, LV_ALIGN_OUT_BOTTOM_MID, 0, 10);

    lv_label_set_text(label2, "Normal");

    sysmon_task(NULL);
}

static void sysmon_task(void * param)
{

    (void) param;    /*Unused*/

    //lv_scr_load(home_screen);
    lv_label_set_text(label1, "Test");

}

How/where do you create home_screen?

Sorry I delete it before last test replace with

lv_scr_load(lv_scr_act())

I’ve tested in the simulator on PC and it was working well for me.
refr

Do you use the latest master branch?

Can you reproduce the issue in the simulator?

Yes I git clone 6 days ago.

No I trust you.

So the problem come from my driver ?

I don’t understand how the graphic driver could be the cause.

The entire buffer is sent for each frame :

Info: Screen create ready       (lvgl/lv_core/lv_obj.c #202)
Info: Screen create ready       (lvgl/lv_core/lv_obj.c #202)
Info: Screen create ready       (lvgl/lv_core/lv_obj.c #202)
Info: lv_init ready     (lvgl/lv_core/lv_obj.c #121)
Info: label created     (lvgl/lv_objx/lv_label.c #133)
Info: label created     (lvgl/lv_objx/lv_label.c #133)
Info: disp_flush (0 0) (127 127)        (lv_port_disp.c #247)
Info: disp_flush (0 0) (127 127)        (lv_port_disp.c #247)
Info: disp_flush (0 0) (127 127)        (lv_port_disp.c #247)
Info: disp_flush (0 0) (127 127)        (lv_port_disp.c #247)
Info: disp_flush (0 0) (127 127)        (lv_port_disp.c #247)
Info: disp_flush (0 0) (127 127)        (lv_port_disp.c #247)
Info: disp_flush (0 0) (127 127)        (lv_port_disp.c #247)

May be a problem in my lv_conf ?

@kisvegabor

@sam76 mentioned that they use LV_VDB_DOUBLE. Maybe the culprit is there?

Its also suspicious to me because the zen theme should have a withe-ish background but in your screenshots it was black. What is you comment out this line.

In addition let’s try with LV_VDB_SIZE (LV_HOR_RES * 10) and LV_VDB_SOUBLE 0 as @embeddedt suggested. Hopefully we will see something useful.

I have modified the zen theme, inverted all black and white color :blush:

Since yesterday I make some try with LV_VDB_SOUBLE 0 and this morning find another bug in my driver (only flush from origin working). All is fine now.

If I keep LV_VDB_SIZE to the full resolution, am I optimize the speed of the library ?

Yes, LittlevGL can draw the whole screen at once if you have LV_VDB_SIZE set to the size of your display.

Actually it’s only a little bit of optimization because usually it’s not so “expensive” to draw the screen in multiple parts. With LV_VDB_DOUBLE you should use DMA in the SPI transfer and when the DMA finished call lv_flush_ready() in the “DMA ready” interrupt. It could result in ~double FPS because while you transfer the data to the display LittlevGL could render the next chunk.

However, (here comes the tricky part) imagine what happens with a 1/3 screen sized VDB and LV_VDB_DOUBLE.

  1. Render first 1/3 screen chunk (10 ms)
  2. Send first 1/3 chunk and render the second 1/3 chunk (10 ms)
  3. Send second 1/3 chunk and render the third 1/3 chunk (10 ms)
  4. Send the third 1/3 chunk (10 ms)

It was 40 ms in the example

But with screen sized VDB.

  1. Render full screen (30 ms)
  2. Send the full screen (30ms)

60 ms in total.

So if you can properly implement non blocking SPI transfer, it’s even better to use a smaller VDB.