lvgl / lvgl

Embedded graphics library to create beautiful UIs for any MCU, MPU and display type.
https://lvgl.io
MIT License
16.28k stars 3.19k forks source link

Direct Frame Buffer Generation #735

Closed pete-pjb closed 5 years ago

pete-pjb commented 5 years ago

Hi,

I would just like to say the library is excellent!

I am currently building a system on a Xilinx Zynq device and I have created my own basic VGA monitor driving hardware written in verilog with in the fabric of the FPGA. This is all working fine with littlevgl and FreeRTOS. I would however like to enhance the transfer of the video data to the hardware and was wondering if someone might be able to give me some guidance of where to look in the littlelvgl library and how best to go about what I want to achieve.

Currently Littlevgl delivers the video data in the form of a rectangle to a memory buffer and calls the vga_disp_flush(int32_t x1, int32_t y1, int32_t x2, int32_t y2, const lv_color_t * color_p); function which copies the rectangle to the appropriate position in the VGA frame buffer which my hardware then DMAs out to the monitor. What I would like to do is look at modifying Littlevgl so that if its own memory buffer is as big as the frame buffer, have it treat the buffer as a frame buffer and write the rectangle data directly to the correct location in the full frame buffer and then have my DMA engine collect it directly from that buffer rather than having to copy it using software from buffer to buffer. I hope that makes sense!

If I can get some guidance, I am happy to have ago at implementing what I have suggested and would of course be happy to contribute the changes back to source should any body think it's a good addition for Littlevgl.

Thank you and Kind Regards,

Pete

kisvegabor commented 5 years ago

Hi Pete,

We just added this feature to the dev-5.3 branch a few days ago: #644

Here the config to enable it: https://github.com/littlevgl/lvgl/blob/dev-5.3/lv_conf_templ.h#L90 As the comment says you also need to enable LV_VDB_DOUBLE and set LV_VDB_SIZE = LV_HOR_RES * LV_VER_RES This way you will have two full screen graphics buffer and in disp_flush you only need to change the address of the frame buffer to color_p.

It's a brand new feaure, so any feedback is welcome :)

pete-pjb commented 5 years ago

Hi kisvegabor,

Sorry for my late reply, I have been working in Germany this week so not been at my home office in the UK.

Thank you this sounds a good solution, I will get the dev-5.3 branch and try it. I am quite unwell at the moment so it may be a few days before I get back to you, but I will certainly let you know how it goes. :-)

Kind Regards,

Pete

kisvegabor commented 5 years ago

Okay, take you time :)

pete-pjb commented 5 years ago

Hi Kisvegabor,

I have managed to get a build together based on the dev-5.3 branch all appears to be working as expected but there is one small issue. If I use your demo application with the the three tabs, the tab titles are not being drawn at the top of the screen. If I move the mouse over the area it begins to draw and as soon as I click on a tab everything appears correctly and works fine from that time forwards.

Does that make sense? Can you think of any reason why this might be happening.

I am currently working on the hardware, I have added an interrupt line output from my VGA controller which I am using with a FreeRTOS binary semaphore to synchronise when to change the DMA source address in the vga_disp_flush() function.

Kind Regards,

Pete

kisvegabor commented 5 years ago

Hi Pete,

Can you share your lv_conf.h?

pete-pjb commented 5 years ago

No problem, here it is...

/**
 * @file lv_conf.h
 * 
 */

#ifndef LV_CONF_H
#define LV_CONF_H

/*----------------
 * Dynamic memory
 *----------------*/
/* Memory size which will be used by the library
 * to store the graphical objects and other data */
#define LV_MEM_CUSTOM      0                /*1: use custom malloc/free, 0: use the built-in lv_mem_alloc/lv_mem_free*/
#if LV_MEM_CUSTOM == 0
#define LV_MEM_SIZE    (32U * 1024000U)        /*Size memory used by `lv_mem_alloc` in bytes (>= 2kB)*/
#define LV_MEM_ATTR                         /*Complier prefix for big array declaration*/
#define LV_MEM_AUTO_DEFRAG  1               /*Automatically defrag on free*/
#else       /*LV_MEM_CUSTOM*/
#define LV_MEM_CUSTOM_INCLUDE <stdlib.h>   /*Header for the dynamic memory function*/
#define LV_MEM_CUSTOM_ALLOC   malloc       /*Wrapper to malloc*/
#define LV_MEM_CUSTOM_FREE    free         /*Wrapper to free*/
#endif     /*LV_MEM_CUSTOM*/

#define LV_VGA_DDR_DMA_BASE 0x0F000000      // This is the DDR address the DMA hardware fetches VGA pixel data from (16MB is reserved)
/*===================
   Graphical settings
 *===================*/

/* Horizontal and vertical resolution of the library.*/
#define LV_HOR_RES          (1024)
#define LV_VER_RES          (768)

/* Dot Per Inch: used to initialize default sizes. E.g. a button with width = LV_DPI / 2 -> half inch wide
 * (Not so important, you can adjust it to modify default sizes and spaces)*/
#define LV_DPI              100

/* Enable anti-aliasing (lines, and radiuses will be smoothed) */
#define LV_ANTIALIAS        1       /*1: Enable anti-aliasing*/

/*Screen refresh period in milliseconds*/
#define LV_REFR_PERIOD      30
/*-----------------
 *  VDB settings
 *----------------*/

/* VDB (Virtual Display Buffer) is an internal graphics buffer.
 * To images will be drawn into this buffer first and then
 * the buffer will be passed to your `disp_drv.disp_flush` function to
 * copy it to your frame buffer.
 * VDB is required for: buffered drawing, opacity, anti-aliasing and shadows
 * Learn more: https://docs.littlevgl.com/#Drawing*/

/* Size of the VDB in pixels. Typical size: ~1/10 screen. Must be >= LV_HOR_RES
 * Setting it to 0 will disable VDB and `disp_drv.disp_fill` and `disp_drv.disp_map` functions
 * will be called to draw to the frame buffer directly*/
#define LV_VDB_SIZE         (LV_VER_RES * LV_HOR_RES)

 /* Bit-per-pixel of VDB. Useful for monochrome or non-standard color format displays.
  * Special formats are handled with `disp_drv.vdb_wr`)*/
#define LV_VDB_PX_BPP       LV_COLOR_SIZE       /*LV_COLOR_SIZE comes from LV_COLOR_DEPTH below to set 8, 16 or 32 bit pixel size automatically */

 /* Place VDB to a specific address (e.g. in external RAM)
  * 0: allocate automatically into RAM
  * LV_VDB_ADR_INV: to replace it later with `lv_vdb_set_adr()`*/
#define LV_VDB_ADR          LV_VGA_DDR_DMA_BASE

/* Use two Virtual Display buffers (VDB) parallelize rendering and flushing (optional)
 * The flushing should use DMA to write the frame buffer in the background */
#define LV_VDB_DOUBLE       1

/* Place VDB2 to a specific address (e.g. in external RAM)
 * 0: allocate automatically into RAM
 * LV_VDB_ADR_INV: to replace it later with `lv_vdb_set_adr()`*/
#define LV_VDB2_ADR         LV_VGA_DDR_DMA_BASE + LV_VDB_SIZE

/* Using true double buffering in `disp_drv.disp_flush` you will always get the image of the whole screen.
 * Your only task is to set the rendered image (`color_p` parameter) as frame buffer address or send it to your display.
 * The best if you do in the blank period of you display to avoid tearing effect.
 * Requires:
 * - LV_VDB_SIZE = LV_HOR_RES * LV_VER_RES
 * - LV_VDB_DOUBLE = 1
 */
#define LV_VDB_TRUE_DOUBLE_BUFFERED 1

/*=================
   Misc. setting
 *=================*/

/*Input device settings*/
#define LV_INDEV_READ_PERIOD            50                     /*Input device read period in milliseconds*/
#define LV_INDEV_POINT_MARKER           0                      /*Mark the pressed points  (required: USE_LV_REAL_DRAW = 1)*/
#define LV_INDEV_DRAG_LIMIT             10                     /*Drag threshold in pixels */
#define LV_INDEV_DRAG_THROW             20                     /*Drag throw slow-down in [%]. Greater value means faster slow-down */
#define LV_INDEV_LONG_PRESS_TIME        400                    /*Long press time in milliseconds*/
#define LV_INDEV_LONG_PRESS_REP_TIME    100                    /*Repeated trigger period in long press [ms] */

/*Color settings*/
#define LV_COLOR_DEPTH     32                     /*Color depth: 1/8/16/32*/
#define LV_COLOR_16_SWAP   0                      /*Swap the 2 bytes of RGB565 color. Useful if the display has a 8 bit interface (e.g. SPI)*/
#define LV_COLOR_SCREEN_TRANSP        0           /*1: Enable screen transparency. Useful for OSD or other overlapping GUIs. Requires ARGB8888 colors*/
#define LV_COLOR_TRANSP    LV_COLOR_LIME          /*Images pixels with this color will not be drawn (with chroma keying)*/

/*Text settings*/
#define LV_TXT_UTF8             1                /*Enable UTF-8 coded Unicode character usage */
#define LV_TXT_BREAK_CHARS     " ,.;:-_"         /*Can break texts on these chars*/
#define LV_TXT_LINE_BREAK_LONG_LEN 12 /* If a character is at least this long, will break wherever "prettiest" */
#define LV_TXT_LINE_BREAK_LONG_PRE_MIN_LEN 3 /* Minimum number of characters of a word to put on a line before a break */
#define LV_TXT_LINE_BREAK_LONG_POST_MIN_LEN 1 /* Minimum number of characters of a word to put on a line after a break */

/*Graphics feature usage*/
#define USE_LV_ANIMATION        1               /*1: Enable all animations*/
#define USE_LV_SHADOW           1               /*1: Enable shadows*/
#define USE_LV_GROUP            1               /*1: Enable object groups (for keyboards)*/
#define USE_LV_GPU              0               /*1: Enable GPU interface*/
#define USE_LV_REAL_DRAW        0               /*1: Enable function which draw directly to the frame buffer instead of VDB (required if LV_VDB_SIZE = 0)*/
#define USE_LV_FILESYSTEM       1               /*1: Enable file system (required by images*/

/*Compiler settings*/
#define LV_ATTRIBUTE_TICK_INC                 /* Define a custom attribute to `lv_tick_inc` function */
#define LV_ATTRIBUTE_TASK_HANDLER             /* Define a custom attribute to `lv_task_handler` function */
#define LV_COMPILER_VLA_SUPPORTED    1        /* 1: Variable length array is supported*/
#define LV_COMPILER_NON_CONST_INIT_SUPPORTED 1  /* 1: Initialization with non constant values are supported */

/*HAL settings*/
#define LV_TICK_CUSTOM     0                        /*1: use a custom tick source (removing the need to manually update the tick with `lv_tick_inc`) */
#if LV_TICK_CUSTOM == 1
#define LV_TICK_CUSTOM_INCLUDE  "Arduino.h"         /*Header for the sys time function*/
#define LV_TICK_CUSTOM_SYS_TIME_EXPR (millis())     /*Expression evaluating to current systime in ms*/
#endif     /*LV_TICK_CUSTOM*/

/*Log settings*/
#define USE_LV_LOG      0   /*Enable/disable the log module*/
#if USE_LV_LOG
/* How important log should be added:
 * LV_LOG_LEVEL_TRACE       A lot of logs to give detailed information
 * LV_LOG_LEVEL_INFO        Log important events
 * LV_LOG_LEVEL_WARN        Log if something unwanted happened but didn't caused problem
 * LV_LOG_LEVEL_ERROR       Only critical issue, when the system may fail
 */
#define LV_LOG_LEVEL    LV_LOG_LEVEL_INFO
/* 1: Print the log with 'printf'; 0: user need to register a callback*/

#define LV_LOG_PRINTF   0
#endif  /*USE_LV_LOG*/
/*================
 *  THEME USAGE
 *================*/
#define LV_THEME_LIVE_UPDATE    1       /*1: Allow theme switching at run time. Uses 8..10 kB of RAM*/

#define USE_LV_THEME_TEMPL      0       /*Just for test*/
#define USE_LV_THEME_DEFAULT    1       /*Built mainly from the built-in styles. Consumes very few RAM*/
#define USE_LV_THEME_ALIEN      1       /*Dark futuristic theme*/
#define USE_LV_THEME_NIGHT      1       /*Dark elegant theme*/
#define USE_LV_THEME_MONO       1       /*Mono color theme for monochrome displays*/
#define USE_LV_THEME_MATERIAL   1       /*Flat theme with bold colors and light shadows*/
#define USE_LV_THEME_ZEN        1       /*Peaceful, mainly light theme */
#define USE_LV_THEME_NEMO       1       /*Water-like theme based on the movie "Finding Nemo"*/

/*==================
 *    FONT USAGE
 *===================*/

/* More info about fonts: https://littlevgl.com/basics#fonts
 * To enable a built-in font use 1,2,4 or 8 values
 * which will determine the bit-per-pixel */
#define USE_LV_FONT_DEJAVU_10              4
#define USE_LV_FONT_DEJAVU_10_LATIN_SUP    4
#define USE_LV_FONT_DEJAVU_10_CYRILLIC     4
#define USE_LV_FONT_SYMBOL_10              4

#define USE_LV_FONT_DEJAVU_20              4
#define USE_LV_FONT_DEJAVU_20_LATIN_SUP    4
#define USE_LV_FONT_DEJAVU_20_CYRILLIC     4
#define USE_LV_FONT_SYMBOL_20              4

#define USE_LV_FONT_DEJAVU_30              4
#define USE_LV_FONT_DEJAVU_30_LATIN_SUP    4
#define USE_LV_FONT_DEJAVU_30_CYRILLIC     4
#define USE_LV_FONT_SYMBOL_30              4

#define USE_LV_FONT_DEJAVU_40              4
#define USE_LV_FONT_DEJAVU_40_LATIN_SUP    4
#define USE_LV_FONT_DEJAVU_40_CYRILLIC     4
#define USE_LV_FONT_SYMBOL_40              4

#define USE_LV_FONT_MONOSPACE_8            4

/* Optionally declare your custom fonts here.
 * You can use these fonts as default font too
 * and they will be available globally. E.g.
 * #define LV_FONT_CUSTOM_DECLARE LV_FONT_DECLARE(my_font_1) \
 *                                LV_FONT_DECLARE(my_font_2) \
 */
#define LV_FONT_CUSTOM_DECLARE

#define LV_FONT_DEFAULT        &lv_font_dejavu_20     /*Always set a default font from the built-in fonts*/

/*===================
 *  LV_OBJ SETTINGS
 *==================*/
#define LV_OBJ_FREE_NUM_TYPE    uint32_t    /*Type of free number attribute (comment out disable free number)*/
#define LV_OBJ_FREE_PTR         1           /*Enable the free pointer attribute*/

/*==================
 *  LV OBJ X USAGE 
 *================*/
/*
 * Documentation of the object types: https://littlevgl.com/object-types
 */

/*****************
 * Simple object
 *****************/

/*Label (dependencies: -*/
#define USE_LV_LABEL    1
#if USE_LV_LABEL != 0
#define LV_LABEL_SCROLL_SPEED       25     /*Hor, or ver. scroll speed [px/sec] in 'LV_LABEL_LONG_SCROLL/ROLL' mode*/
#endif

/*Image (dependencies: lv_label*/
#define USE_LV_IMG      1
#if USE_LV_IMG != 0
#define LV_IMG_CF_INDEXED   1       /*Enable indexed (palette) images*/
#define LV_IMG_CF_ALPHA     1       /*Enable alpha indexed images*/
#endif

/*Line (dependencies: -*/
#define USE_LV_LINE     1

/*Arc (dependencies: -)*/
#define USE_LV_ARC      1

/*******************
 * Container objects
 *******************/

/*Container (dependencies: -*/
#define USE_LV_CONT     1

/*Page (dependencies: lv_cont)*/
#define USE_LV_PAGE     1

/*Window (dependencies: lv_cont, lv_btn, lv_label, lv_img, lv_page)*/
#define USE_LV_WIN      1

/*Tab (dependencies: lv_page, lv_btnm)*/
#define USE_LV_TABVIEW      1
#if USE_LV_TABVIEW != 0
#define LV_TABVIEW_ANIM_TIME    300     /*Time of slide animation [ms] (0: no animation)*/
#endif

/*Tileview (dependencies: lv_page) */
#define USE_LV_TILEVIEW     1
#if USE_LV_TILEVIEW
#define LV_TILEVIEW_ANIM_TIME   300     /*Time of slide animation [ms] (0: no animation)*/
#endif

/*************************
 * Data visualizer objects
 *************************/

/*Bar (dependencies: -)*/
#define USE_LV_BAR      1

/*Line meter (dependencies: *;)*/
#define USE_LV_LMETER   1

/*Gauge (dependencies:bar, lmeter)*/
#define USE_LV_GAUGE    1

/*Chart (dependencies: -)*/
#define USE_LV_CHART    1

/*Table (dependencies: lv_label)*/
#define USE_LV_TABLE    1
#if USE_LV_TABLE
#define LV_TABLE_COL_MAX    12
#endif

/*LED (dependencies: -)*/
#define USE_LV_LED      1

/*Message box (dependencies: lv_rect, lv_btnm, lv_label)*/
#define USE_LV_MBOX     1

/*Text area (dependencies: lv_label, lv_page)*/
#define USE_LV_TA       1
#if USE_LV_TA != 0
#define LV_TA_CURSOR_BLINK_TIME 400     /*ms*/
#define LV_TA_PWD_SHOW_TIME     1500    /*ms*/
#endif

/*Spinbox (dependencies: lv_ta)*/
#define USE_LV_SPINBOX       1

/*Calendar (dependencies: -)*/
#define USE_LV_CALENDAR 1

/*Preload (dependencies: arc)*/
#define USE_LV_PRELOAD      1
#if USE_LV_PRELOAD != 0
#define LV_PRELOAD_DEF_ARC_LENGTH   60      /*[deg]*/
#define LV_PRELOAD_DEF_SPIN_TIME    1000    /*[ms]*/
#define LV_PRELOAD_DEF_ANIM         LV_PRELOAD_TYPE_SPINNING_ARC
#endif

/*Canvas (dependencies: lv_img)*/
#define USE_LV_CANVAS       1
/*************************
 * User input objects
 *************************/

/*Button (dependencies: lv_cont*/
#define USE_LV_BTN      1
#if USE_LV_BTN != 0
#define LV_BTN_INK_EFFECT   1       /*Enable button-state animations - draw a circle on click (dependencies: USE_LV_ANIMATION)*/
#endif

/*Image Button (dependencies: lv_btn*/
#define USE_LV_IMGBTN   1
#if USE_LV_IMGBTN
#define LV_IMGBTN_TILED 0           /*1: The imgbtn requires left, mid and right parts and the width can be set freely*/
#endif

/*Button matrix (dependencies: -)*/
#define USE_LV_BTNM     1

/*Keyboard (dependencies: lv_btnm)*/
#define USE_LV_KB       1

/*Check box (dependencies: lv_btn, lv_label)*/
#define USE_LV_CB       1

/*List (dependencies: lv_page, lv_btn, lv_label, (lv_img optionally for icons ))*/
#define USE_LV_LIST     1
#if USE_LV_LIST != 0
#define LV_LIST_FOCUS_TIME  100 /*Default animation time of focusing to a list element [ms] (0: no animation)  */
#endif

/*Drop down list (dependencies: lv_page, lv_label)*/
#define USE_LV_DDLIST    1
#if USE_LV_DDLIST != 0
#define LV_DDLIST_ANIM_TIME     200     /*Open and close default animation time [ms] (0: no animation)*/
#endif

/*Roller (dependencies: lv_ddlist)*/
#define USE_LV_ROLLER    1
#if USE_LV_ROLLER != 0
#define LV_ROLLER_ANIM_TIME     200     /*Focus animation time [ms] (0: no animation)*/
#endif

/*Slider (dependencies: lv_bar)*/
#define USE_LV_SLIDER    1

/*Switch (dependencies: lv_slider)*/
#define USE_LV_SW       1

#endif /*LV_CONF_H*/
kisvegabor commented 5 years ago

It seems correct.

I true double buffered mode the parts which were changed are copied to the other frame buffer to keep them syncronised. It seems, at first time the refreshed area (the whole screen) is not copied. Maybe there is a synchronization issue in the driver.

Do you call lv_vdb_flush_ready() when the new frame buffer is really applied?

The relevant part of the code where the copy of the areas happens is here: https://github.com/littlevgl/lvgl/blob/dev-5.3/lv_core/lv_refr.c#L226 Hopefully, you can debug what is going on.

As a workaround, I suggest calling

lv_obj_invalidate(lv_scr_act());
lv_refr_now();

after 100 ms to refresh the whole screen again. You need to ensure that lv_task_handler is running in this 100 ms to the inital (wrong) refreshing.

pete-pjb commented 5 years ago

Hi Kisvegabor,

It seems adding the two calls you mentioned after creating the tabs appears to fix the problem for me... :-)

lv_obj_t * tab1 = lv_tabview_add_tab(tv, "Lighting"); lv_obj_t * tab2 = lv_tabview_add_tab(tv, "Heating"); lv_obj_t * tab3 = lv_tabview_add_tab(tv, "Security"); lv_obj_invalidate(lv_scr_act()); lv_refr_now();

I assume you mean the lv_flush_ready() function? If so I do....

My driver function looks like this:

void vga_disp_flush(int32_t x1, int32_t y1, int32_t x2, int32_t y2, const lv_color_t * color_p) {`

    static uint8_t  first_call = 1;
    vga->vga_fbuf_addr = (uint32_t)color_p;
    if( first_call ) {
        first_call =  0;
        vga->total_pixels &= ~DMA_FIFO_RST;     // Release Reset
        vga->total_pixels |= DMA_FRAME_READY;   // Start Proceedings
        vga->irq_reg = VGA_IRQ_EN;
        vga_ready = pdTRUE;
    } else {
        xSemaphoreTake( vga_sem, portMAX_DELAY );
    }
    lv_flush_ready();
}

The variable vga is a memory mapped peripheral and we set the dma source address to color_p on entry, the semaphore vga_sem is kicked by an interrupt when the dma has copied the entire frame, we then call lv_flush_ready() to tell littlevgl to process the next buffer.

Thanks very much for your help I will close this comment now if you are happy for me to do so...

Kind Regards,

Pete

kisvegabor commented 5 years ago

Yes, I meant lv_flush_ready, sorry. :)

So when the DMA is ready you get an interrupt and call xSemaphoreGive(). Not sure if it's the problem, but then lv_flush_ready(); should be called in the interrupt because it tells lvgl that the old frame buffer is alrady not used.

Side topic: It seems like a very interesting project. I don't know its nature (proprietary, open-source, hobby?) but if you would like to share and/or advertise it there are some good ways:

pete-pjb commented 5 years ago

Hi again,

Yes I call xSemaphoreGiveFromISR(); from my interrupt when the DMA reaches the end of it's Full Frame transfer(The hardware has an asynchronous FIFO which is loaded with data from a 32-bit AXI interface clocked at 200MHz for sending out to the screen using the VGA pixel clock and H/V signals) so lv_flush_ready(); is called pretty much as soon as the interrupt arrives from the vga_disp_flush() function as required. I have been working with various RTOS platforms for around 20 years and I prefer to do all 'my work' in worker threads triggered by various RTOS specific messaging passing mechanisms keeping my interrupt handler code to a minimum at all times, which I have found makes for a 'more predictable real-time performance' from any RTOS. So hence I don't call lv_flush_ready() directly in the IRQ handler code (even though it appears to be a very basic function which at first glance looks to be interrupt safe) I just block on the semaphore in the vga_disp_flush(); function until the interrupt has arrived. I have checked the addressing and execution of both the software and hardware and all is working correctly, The frames are alternating between the address 0x0F0000000 and 0x0F300000 which is what I would expect for a 1024 x 768 x 32 bit screen as configured in lv_conf.h

I have traced the code through from startup I see the first frame come through from littlevgl which is an entire white blank screen as expected and then the next frame I receive is the 'write screen' from the demo (minus the tabs at the top which are just blank white all values 0xFF). If I add the calls you suggested (lv_obj_invalidate(lv_scr_act()); lv_refr_now();) the second frame buffer data then shows the top area of the screen to be different values representing the blue colour of the tabs and the tabs show on the screen correcting the problem.

With regard to the project, I have been working with electronics since I was about 5 years old, building various circuits etc. I got my first computer (Sinclair ZX81 (Z80)with 1K of RAM!) in the early 80's at age 12 and progressed through BBC micros(6502), Atari STs(Motorola 68000) and eventually onto PCs. I have designed for work, embedded systems with various 8051 micros, STM32s, Texas Instruments DSPs, Motorola (now Freescale/NXP) Network processing SOCs, 386/486/Pentium/PCI based systems and Xilinx devices.
I am currently working on a personal project for my own home for automation based on the Zedboard. I initially looked at Linux but it's far to big and bloated these days hence the FreeRTOS/LittleVGL route. I am intending to share my work in the form of a home automation system. I have other Verilog based controllers on board as well as the VGA controller, to control WS2812B LED strips, multi-channel PWM dimmers, security sensors, temperature and humidity sensors(DHT22), PIR sensors, solenoid valve control and sound detection. I have various electronic circuits to interface everything together. I am also looking at trying to incorporate a VNC server for remote device control in the longer term to enable tablet/mobile phone and PC access to the system. The Verilog controllers are instantiated in the programmable logic fabric of a Zynq 7020 device and interfaced to the on-board dual ARM Cortex-A9 cores via memory mapped AXI interfaces. I am running two instantiations of FreeRTOS, one on each core, using one core to run the GUI, management and IP stack and the other core to do the real-time processing of system events etc. with a block of shared memory for the cores to exchange information. Once I have the system completed I will share it with the open source community, I would certainly consider writing a blog at the release stage also if that is helpful to yourself and Littlevgl.

At the same time I am also evaluating the framework for a commercial application which unfortunately wont be open source, but if we use the framework we will certainly be making a financial contribution to Littlevgl later on when we get into production.

How did you get into all this kind of stuff then?

Kind Regards,

Pete

kisvegabor commented 5 years ago

I see. It's strange, I don't know why it occurs. Anyway, it's working this way. :)

Thanks for the introduction! I found it a good idea to have an issue where we can write a few lines about ourselves. So I opened one: https://github.com/littlevgl/lvgl/issues/786

The home automation project sounds very well and complex! I never thought to use FPGA/CPLD in a project like this. I'm waiting to see it!

If you want you can add the commercial project to the References. It's a little bit of advertisement too.

kisvegabor commented 5 years ago

As the issue seems to be solved I close it.

If it's still not working please reopen the issue and comment here.

tino456 commented 4 years ago

Hi, I am quite new working with littlevgl. I am trying to have a quick popping up of an object (a big rectangle) which almost cannot be seen by human eyes. Then a different screen appears. For making sure my object is flushed and shown, but not too long, I was trying to set up double buffering, because using only one buffer, I am facing the problem that either the object is shown for too long, or not shown at all. Now my question is, how to exactly set the address of the frame buffer to color_p in fbdev_flush(), as you (@kisvegabor ) mentioned above:

This way you will have two full screen graphics buffer and in disp_flush you only need to change the address of the frame buffer to color_p.

How do I do that? Is it written down somewhere?

I enabled LV_VDB_DOUBLE already and set LV_VDB_SIZE = LV_HOR_RES * LV_VER_RES, as mentioned above. I also set up a second buffer in init_lvgl(): static lv_color_t buf_2[LV_HOR_RES_MAX * LV_VER_RES_MAX];.

Any help would be appreciated!

embeddedt commented 4 years ago

@tino456 What version of LittlevGL are you using? As far as I know, the defines you are using don't exist in 6.0+; instead, everything is driven through code. Here's our example for true double buffering.

tino456 commented 4 years ago

Thanks for your help @embeddedt . I am on version 6.0.2 so you might be right! As far as I understand from your example, the only thing really that is actually changed compared to the one-buffer-version is that you provide a second buffer static lv_color_t buf3_2[LV_HOR_RES_MAX * LV_VER_RES_MAX]; and initialized the display with two buffers buf3_2 and buf3_1. Or am I missing something? But only providing a second buffer is not going to automate the mechanism that LittlevGL draws into one buffer while the content of the other buffer is sent to display in the background (as described in the documentary), right? Instead, I will still need to change the frame buffer's address manually when calling disp_flush()? Or is this done automatically? Thank you!

kisvegabor commented 4 years ago

I will still need to change the frame buffer's address manually when calling disp_flush()? Or is this done automatically?

You need to change the FB's address in disp_flush manually because it's a hardware-specific thing.

tino456 commented 4 years ago

I got it, thank you!