Communication with LCD

Description

I am working on a custom board which has stm32f3 controller communicating with LCD (SSD2119) over 4-wire SPI interface.

What MCU/Processor/Board and compiler are you using?

Application Controller - STM32F303
LCD Controller - SSD2119
Board - Custom

What do you want to achieve?

  • I want to display certain shapes, text boxes, buttons and images on the display.
  • For that I need to understand how the data are sent to the LCD.

What have you tried so far?

I have gone through all the examples and documents of LVGL library.

Code to reproduce

NA

Screenshot and/or video

NA.

Hi @ksoni306,

Assuming you have followed the setup instructions in the documentation. I think Display Porting in LVGL documentation is a good place to start.

In summary, all you have to do is define the buffer for your display, register the LVGL driver and callback function for flushing the buffer to your display.

Define the buffer,

/*A static or global variable to store the buffers*/
static lv_disp_buf_t disp_buf;

/*Static or global buffer(s). The second buffer is optional*/
static lv_color_t buf_1[MY_DISP_HOR_RES * 10];
static lv_color_t buf_2[MY_DISP_HOR_RES * 10];

/*Initialize `disp_buf` with the buffer(s) */
lv_disp_buf_init(&disp_buf, buf_1, buf_2, MY_DISP_HOR_RES*10);

Register the display driver for LVGL,

lv_disp_drv_t disp_drv;                 /*A variable to hold the drivers. Can be local variable*/
lv_disp_drv_init(&disp_drv);            /*Basic initialization*/
disp_drv.buffer = &disp_buf;            /*Set an initialized buffer*/
disp_drv.flush_cb = my_flush_cb;        /*Set a flush callback to draw to the display*/
lv_disp_t * disp;
disp = lv_disp_drv_register(&disp_drv); /*Register the driver and save the created display objects*/

my_flush_cb is where you send the pixel data to your LCD. You can refer SSD1963 driver flush function and you can use it as a starting point for your flush_cb function.

void my_flush_cb(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p)
{
    /*The most simple case (but also the slowest) to put all pixels to the screen one-by-one*/
    int32_t x, y;
    for(y = area->y1; y <= area->y2; y++) {
        for(x = area->x1; x <= area->x2; x++) {
            put_px(x, y, *color_p)
            color_p++;
        }
    }

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

Once all set, you can try below code for simple button example,

lv_obj_t * btn = lv_btn_create(lv_scr_act(), NULL);     /*Add a button the current screen*/
lv_obj_set_pos(btn, 10, 10);                            /*Set its position*/
lv_obj_set_size(btn, 120, 50);                          /*Set its size*/

lv_obj_t * label = lv_label_create(btn, NULL);          /*Add a label to the button*/
lv_label_set_text(label, "Button");                     /*Set the labels text*/

while (1) {
    lv_task_handler();
    usleep(10 * 1000); /*Sleep for 10 millisecond*/
    lv_tick_inc(10);   /*Tell LittelvGL that 10 milliseconds were elapsed*/
}

Hope this will give you the kickstart you need. Let me know if you have any more questions.

Best Regards,
Prasad.

Hello,

Thank you for the response.
Yes I have read the mentioned document and have implemented the necessary steps in my code.

static lv_color_t disp_buf1[LCD_HOR_RES * 10];
static lv_color_t disp_buf2[LCD_HOR_RES * 10];
static lv_disp_buf_t buf;

/*Initialize `disp_buf` with the buffer(s) */
lv_disp_buf_init(&buf, disp_buf1, disp_buf2, LCD_HOR_RES * 10);	 /*The second buffer is optional*/

lv_disp_drv_init(&disp_drv);	 	/*Basic initialization*/

disp_drv.buffer = &buf;				/*Set an initialized buffer*/
disp_drv.flush_cb = ssd2119_flush;	/*Set a flush callback to draw to the display*/
lv_disp_drv_register(&disp_drv);	/*Register the driver and save the created display objects*/`

Below is the flush_cb

void ssd2119_flush(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p)
{
	int32_t x, y;
union{
	struct{
		uint8_t color_data_msb;
		uint8_t color_data_lsb;
	}color_data;
	lv_color_t pixel_color;
}pixel_color_info;

pixel_color_info.pixel_color = *color_p;

ssd2119_write_reg(SSD2119_X_RAM_ADDR_REG, 0x0000);	//RAM Address Set
ssd2119_write_reg(SSD2119_Y_RAM_ADDR_REG, 0x0000);	//RAM Address Set
ssd2119_write_reg(SSD2119_V_RAM_POS_REG, 0xEF00);	//Vertical RAM Address
ssd2119_write_reg(SSD2119_H_RAM_START_REG, 0x0000);	//Horz. RAM Address 
ssd2119_write_reg(SSD2119_H_RAM_END_REG, 0x013F);	//Horz. RAM Address 

ssd2119_cmd(SSD2119_RAM_DATA_REG);

/*put all pixels to the screen one-by-one*/
for(y = area->y1; y <= area->y2; y++) {
    for(x = area->x1; x <= area->x2; x++) {
		ssd2119_data_single(pixel_color_info.color_data.color_data_msb);
		ssd2119_data_single(pixel_color_info.color_data.color_data_lsb);
        color_p++;
    }
}
	/* IMPORTANT!!!
	* Inform the graphics library that you are ready with the flushing*/
    lv_disp_flush_ready(disp_drv);
}

As you have mentioned in the above example I have created a button using the code provided by you. My system is non RTOS based so I have not called the β€œlv_task_handler()”.
I am not to see anything on the screen. After debugging further I came to know that flush_cb is not executed in my code.

HI @ksoni306,

You must call lv_task_handler() periodically every few milliseconds to handle LVGL related tasks. And also it requires to call lv_tick_inc(x) in every x milliseconds to tell the elapsed time to LVGL.

Your ssd2119_flush will not call without lv_task_handler() and lv_tick_inc(x).

I would give a try below code at the end of your main function and see what appears on the screen,

while (1) {
    lv_task_handler();
    usleep(10 * 1000); /*Sleep for 10 millisecond*/
    lv_tick_inc(10);   /*Tell LittelvGL that 10 milliseconds were elapsed*/
}

Remember it is recommended to call lv_tick_inc(x) in an interrupt or using a timer. But you can leave that for later as the above code will work fine just to get you started.

Best Regards,
Prasad.

Hi Prasad,

I have tried the following

while (1) {
lv_task_handler();
usleep(10 * 1000); /*Sleep for 10 millisecond*/
lv_tick_inc(10);   /*Tell LittelvGL that 10 milliseconds were elapsed*/

}

But the system goes in Hardfault.
Is there any memory requirement?
Following are the code snippets related to memory in my code.

lv_conf.h:

    /*=========================
   Memory manager settings
 *=========================*/

/* LittelvGL's internal memory manager's settings.
 * The graphical objects and other related data are stored here. */

/* 1: use custom malloc/free, 0: use the built-in `lv_mem_alloc` and `lv_mem_free` */
#define LV_MEM_CUSTOM      0
#if LV_MEM_CUSTOM == 0
/* Size of the memory used by `lv_mem_alloc` in bytes (>= 2kB)*/
#  define LV_MEM_SIZE    (10U * 1024U)

/* Complier prefix for a big array declaration */
#  define LV_MEM_ATTR

/* Set an address for the memory pool instead of allocating it as an array.
 * Can be in external SRAM too. */
#  define LV_MEM_ADR          0

/* Automatically defrag. on free. Defrag. means joining the adjacent free cells. */
#  define LV_MEM_AUTO_DEFRAG  1
#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*/

As you can notice I have kept LV_MEM_SIZE as 10KB

Display frame buffer

	static lv_color_t disp_buf1[LCD_HOR_RES * 10];
	static lv_color_t disp_buf2[LCD_HOR_RES * 10];

where LCD_HOR_RES = 320

Heap Size = 0x2800
Stack Size = 0x400

Is there anything required?

Typically you can get away with default memory settings in LVGL config. Do you have more information about HardFault?

Your heap size is sufficient. However, Your stack size is under the minimum. Can you change the stack size to 0x800 and try again? The recommended stack size is 0x2800

Hi Prasad,

Yes the issue was related to the Stack Size. Once I increased the stack size to 0x2000 the Hardfault issue was resolved.
I have not experimented with different values of the stack and heap size yet. But with heap size = 0x2800 and stack size = 0x2000 the button example worked.

Thank you for the support.

1 Like

You are welcome. I’m glad it’s working for you now.

Remember your current implementation of ssd2119_flush is sending one pixel at a time. Which is not recommended as it is a slow process. Try sending 16-bits of pixel data to your screen at once or two Bytes in two calls.

Cheers!