Boilerplate library to get started with LvGL on STM DISCO F746NG board. Adapted from https://os.mbed.com/users/JohnnyK/code/DISCO-F746NG_MbedOs_LvGL_example/

Dependencies:   BSP_DISCO_F746NG

Dependents:   LvGL_F746NG_test

lv_port_disp.c

Committer:
elelthvd
Date:
2020-09-08
Revision:
0:cffa136e7f8f

File content as of revision 0:cffa136e7f8f:

/**
 * @file lv_port_disp_templ.c
 *
 */

 /*Copy this file as "lv_port_disp.c" and set this value to "1" to enable content*/
#if 1

/*********************
 *      INCLUDES
 *********************/
#include "lv_port_disp.h"
#include "lvgl/lvgl.h"
#include "stm32f7xx.h"
#include "stm32746g_discovery.h"
#include "stm32746g_discovery_sdram.h"
#include "stm32746g_discovery_lcd.h"
#include "stm32746g_discovery_ts.h"

/*********************
 *      DEFINES
 *********************/

/**********************
 *      TYPEDEFS
 **********************/

/**********************
 *  STATIC PROTOTYPES
 **********************/
static void disp_init(void);

static void disp_flush(lv_disp_drv_t* disp_drv, const lv_area_t* area, lv_color_t* color_p);

#if LV_USE_GPU
DMA2D_HandleTypeDef Dma2dHandle;
static void DMA2D_Config(void);
static void Error_Handler(void);
static void DMA2D_TransferComplete(DMA2D_HandleTypeDef *hdma2d);
static void DMA2D_TransferError(DMA2D_HandleTypeDef *hdma2d);
static void gpu_blend(lv_disp_drv_t * disp_drv,lv_color_t * dest, const lv_color_t * src, uint32_t length, lv_opa_t opa);
static void gpu_fill(lv_disp_drv_t * disp_drv,lv_color_t *  dest_buf, lv_coord_t dest_width, const lv_area_t * fill_area, lv_color_t color);
#endif

/**********************
 *  STATIC VARIABLES
 **********************/

/**********************
 *      MACROS
 **********************/

/**********************
 *   GLOBAL FUNCTIONS
 **********************/

void lv_port_disp_init(void)
{
    /*-------------------------
     * Initialize your display
     * -----------------------*/
    disp_init();

    /*-----------------------------
     * Create a buffer for drawing
     *----------------------------*/

    /* LittlevGL requires a buffer where it draws the objects. The buffer's has to be greater than 1 display row
     *
     * There are three buffering configurations:
     * 1. Create ONE buffer with some rows: 
     *      LittlevGL will draw the display's content here and writes it to your display
     * 
     * 2. Create TWO buffer with some rows: 
     *      LittlevGL will draw the display's content to a buffer and writes it your display.
     *      You should use DMA to write the buffer's content to the display.
     *      It will enable LittlevGL to draw the next part of the screen to the other buffer while
     *      the data is being sent form the first buffer. It makes rendering and flushing parallel.
     * 
     * 3. Create TWO screen-sized buffer: 
     *      Similar to 2) but the buffer have to be screen sized. When LittlevGL is ready it will give the
     *      whole frame to display. This way you only need to change the frame buffer's address instead of
     *      copying the pixels.
     * */

    /* Example for 1) */
    static lv_disp_buf_t disp_buf_1;
    static lv_color_t buf1_1[LV_HOR_RES_MAX * 10];                      /*A buffer for 10 rows*/
    lv_disp_buf_init(&disp_buf_1, buf1_1, NULL, LV_HOR_RES_MAX * 10);   /*Initialize the display buffer*/

    /* Example for 2) */
    //static lv_disp_buf_t disp_buf_2;
    //static lv_color_t buf2_1[LV_HOR_RES_MAX * 10];                        /*A buffer for 10 rows*/
    //static lv_color_t buf2_2[LV_HOR_RES_MAX * 10];                        /*An other buffer for 10 rows*/
    //lv_disp_buf_init(&disp_buf_2, buf2_1, buf2_2, LV_HOR_RES_MAX * 10);   /*Initialize the display buffer*/

    /* Example for 3) */
    // static lv_disp_buf_t disp_buf_3;
    // static lv_color_t buf3_1[LV_HOR_RES_MAX * LV_VER_RES_MAX];            /*A screen sized buffer*/
    // static lv_color_t buf3_2[LV_HOR_RES_MAX * LV_VER_RES_MAX];            /*An other screen sized buffer*/
    // lv_disp_buf_init(&disp_buf_3, buf3_1, buf3_2, LV_HOR_RES_MAX * LV_VER_RES_MAX);   /*Initialize the display buffer*/


    /*-----------------------------------
     * Register the display in LittlevGL
     *----------------------------------*/

    lv_disp_drv_t disp_drv;                         /*Descriptor of a display driver*/
    lv_disp_drv_init(&disp_drv);                    /*Basic initialization*/
    /*Set up the functions to access to your display*/
    /*Set the resolution of the display*/
    disp_drv.hor_res = 480;
    disp_drv.ver_res = 272;
    /*Used to copy the buffer's content to the display*/
    disp_drv.flush_cb = disp_flush;
    /*Set a display buffer*/
    disp_drv.buffer = &disp_buf_1;
    // disp_drv.buffer = &disp_buf_2;
    // disp_drv.buffer = &disp_buf_3;
#if LV_USE_GPU
    /*Optionally add functions to access the GPU. (Only in buffered mode, LV_VDB_SIZE != 0)*/
    DMA2D_Config();
    /*Blend two color array using opacity*/
    disp_drv.gpu_blend_cb = gpu_blend;
    /*Fill a memory array with a color*/
    disp_drv.gpu_fill_cb = gpu_fill;
#endif
    /*Finally register the driver*/
    lv_disp_drv_register(&disp_drv);
}

/**********************
 *   STATIC FUNCTIONS
 **********************/

/* Initialize your display and the required peripherals. */
static void disp_init(void){
    /*You code here*/
    BSP_LCD_Init();
#if LV_COLOR_DEPTH == 16
    Dma2dHandle.LayerCfg[0].InputColorMode = DMA2D_INPUT_RGB565;
     BSP_LCD_LayerRgb565Init(1, LCD_FB_START_ADDRESS));
#elif LV_COLOR_DEPTH == 24 || LV_COLOR_DEPTH == 32
    BSP_LCD_LayerDefaultInit(0, LCD_FB_START_ADDRESS);
#endif
    BSP_LCD_DisplayOn();
    BSP_LCD_SelectLayer(0);
}

/* Flush the content of the internal buffer the specific area on the display
 * You can use DMA or any hardware acceleration to do this operation in the background but
 * 'lv_disp_flush_ready()' has to be called when finished. */
static void disp_flush(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
    uint16_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)
            BSP_LCD_DrawPixel( x, y, color_p->full);
            color_p++;
        }
    }
    // IMPORTANT!!!* Inform the graphics library that you are ready with the flushing
    lv_disp_flush_ready(disp_drv);
}


/*OPTIONAL: GPU INTERFACE*/
#if LV_USE_GPU

/* If your MCU has hardware accelerator (GPU) then you can use it to blend to memories using opacity
 * It can be used only in buffered mode (LV_VDB_SIZE != 0 in lv_conf.h)*/

static void DMA2D_Config(void){
    //onfigure the DMA2D Mode, Color Mode and output offset
    Dma2dHandle.Init.Mode         = DMA2D_M2M_BLEND;
#if LV_COLOR_DEPTH == 16
    Dma2dHandle.Init.ColorMode    = DMA2D_RGB565;
#elif LV_COLOR_DEPTH == 24 || LV_COLOR_DEPTH == 32
    Dma2dHandle.Init.ColorMode    = DMA2D_ARGB8888;
#endif
    Dma2dHandle.Init.OutputOffset = 0x0;
    //DMA2D Callbacks Configuration
    Dma2dHandle.XferCpltCallback  = DMA2D_TransferComplete;
    Dma2dHandle.XferErrorCallback = DMA2D_TransferError;
    //Foreground Configuration
    Dma2dHandle.LayerCfg[1].AlphaMode = DMA2D_REPLACE_ALPHA;
    Dma2dHandle.LayerCfg[1].InputAlpha = 0xFF;
#if LV_COLOR_DEPTH == 16
    Dma2dHandle.LayerCfg[1].InputColorMode = DMA2D_INPUT_RGB565;
#elif LV_COLOR_DEPTH == 24 || LV_COLOR_DEPTH == 32
    Dma2dHandle.LayerCfg[1].InputColorMode = DMA2D_INPUT_ARGB8888;
#endif
    Dma2dHandle.LayerCfg[1].InputOffset = 0x0;
    //Background Configuration 
    Dma2dHandle.LayerCfg[0].AlphaMode = DMA2D_REPLACE_ALPHA;
    Dma2dHandle.LayerCfg[0].InputAlpha = 0xFF;
#if LV_COLOR_DEPTH == 16
    Dma2dHandle.LayerCfg[0].InputColorMode = DMA2D_INPUT_RGB565;
#elif LV_COLOR_DEPTH == 24 || LV_COLOR_DEPTH == 32
    Dma2dHandle.LayerCfg[0].InputColorMode = DMA2D_INPUT_ARGB8888;
#endif
    Dma2dHandle.LayerCfg[0].InputOffset = 0x0;
    Dma2dHandle.Instance   = DMA2D;
    //DMA2D Initialization
    if(HAL_DMA2D_Init(&Dma2dHandle) != HAL_OK){
        Error_Handler();// Initialization Error 
    }
    HAL_DMA2D_ConfigLayer(&Dma2dHandle, 0);
    HAL_DMA2D_ConfigLayer(&Dma2dHandle, 1);
}

static void gpu_blend(lv_disp_drv_t * disp_drv, lv_color_t * dest, const lv_color_t * src, uint32_t length, lv_opa_t opa){
    /*Wait for the previous operation*/
    HAL_DMA2D_PollForTransfer(&Dma2dHandle, 100);
    Dma2dHandle.Init.Mode         = DMA2D_M2M_BLEND;
    /* DMA2D Initialization */
    if(HAL_DMA2D_Init(&Dma2dHandle) != HAL_OK){
        /* Initialization Error */
        while(1);
    }
    Dma2dHandle.LayerCfg[1].InputAlpha = opa;
    HAL_DMA2D_ConfigLayer(&Dma2dHandle, 1);
    HAL_DMA2D_BlendingStart(&Dma2dHandle, (uint32_t) src, (uint32_t) dest, (uint32_t)dest, length, 1);
}

/* If your MCU has hardware accelerator (GPU) then you can use it to fill a memory with a color
 * It can be used only in buffered mode (LV_VDB_SIZE != 0 in lv_conf.h)*/
static void gpu_fill(lv_disp_drv_t * disp_drv, lv_color_t * dest_buf, lv_coord_t dest_width, const lv_area_t * fill_area, lv_color_t color){
    /*Wait for the previous operation*/
    HAL_DMA2D_PollForTransfer(&Dma2dHandle, 100);
    Dma2dHandle.Init.Mode         = DMA2D_R2M;
   /* DMA2D Initialization */
   if(HAL_DMA2D_Init(&Dma2dHandle) != HAL_OK){
     /* Initialization Error */
     while(1);
   }
   Dma2dHandle.LayerCfg[1].InputAlpha = 0xff;
   HAL_DMA2D_ConfigLayer(&Dma2dHandle, 1);
   lv_color_t * dest_buf_ofs = dest_buf;
   dest_buf_ofs += dest_width * fill_area->y1;
   dest_buf_ofs += fill_area->x1;
   lv_coord_t area_w = lv_area_get_width(fill_area);
   uint32_t i;
   for(i = fill_area->y1; i <= fill_area->y2; i++) {
       /*Wait for the previous operation*/
       HAL_DMA2D_PollForTransfer(&Dma2dHandle, 100);
       HAL_DMA2D_BlendingStart(&Dma2dHandle, (uint32_t) lv_color_to32(color), (uint32_t) dest_buf_ofs, (uint32_t)dest_buf_ofs, area_w, 1);
       dest_buf_ofs += dest_width;
   }
}

static void Error_Handler(void){
    while(1){}
}

static void DMA2D_TransferComplete(DMA2D_HandleTypeDef *hdma2d){

}

static void DMA2D_TransferError(DMA2D_HandleTypeDef *hdma2d){
    
}

#endif  /*LV_USE_GPU*/

#else /* Enable this file at the top */

/* This dummy typedef exists purely to silence -Wpedantic. */
typedef int keep_pedantic_happy;
#endif