/** * @file tft.c * */ /********************* * INCLUDES *********************/ #include "lv_conf.h" #include "lvgl/lvgl.h" #include #include #include "tft.h" #include "stm32f4xx.h" #include "BSP/SDRAM.h" /********************* * DEFINES *********************/ #if LV_COLOR_DEPTH != 16 && LV_COLOR_DEPTH != 24 && LV_COLOR_DEPTH != 32 #error LV_COLOR_DEPTH must be 16, 24, or 32 #endif /** * @brief LCD status structure definition */ #define LCD_OK ((uint8_t)0x00) #define LCD_ERROR ((uint8_t)0x01) #define LCD_TIMEOUT ((uint8_t)0x02) /********************** * TYPEDEFS **********************/ /********************** * STATIC PROTOTYPES **********************/ /*These 3 functions are needed by LittlevGL*/ static void ex_disp_flush(lv_disp_drv_t *drv, const lv_area_t *area, lv_color_t * color_p); //static void ex_disp_clean_dcache(lv_disp_drv_t *drv); static void DMA_Config(void); static void DMA_TransferComplete(DMA_HandleTypeDef *han); static void DMA_TransferError(DMA_HandleTypeDef *han); /********************** * STATIC VARIABLES **********************/ static lv_disp_drv_t disp_drv; #if LV_COLOR_DEPTH == 16 typedef uint16_t uintpixel_t; #elif LV_COLOR_DEPTH == 24 || LV_COLOR_DEPTH == 32 typedef uint32_t uintpixel_t; #endif /* You can try to change buffer to internal ram by uncommenting line below and commenting * SDRAM one. */ //static uintpixel_t my_fb[TFT_HOR_RES * TFT_VER_RES]; static __IO uintpixel_t * my_fb = (__IO uintpixel_t*) (0xD0000000); extern DMA_HandleTypeDef hdma_memtomem_dma2_stream0; static int32_t x1_flush; static int32_t y1_flush; static int32_t x2_flush; static int32_t y2_fill; static int32_t y_fill_act; static const lv_color_t * buf_to_flush; lv_disp_t *our_disp = NULL; /********************** * MACROS **********************/ /** * Initialize your display here */ void tft_init(void) { /* There is only one display on STM32 */ if(our_disp != NULL) abort(); /* LCD Initialization */ // LCD_Init(); /* LCD Initialization */ // LCD_LayerRgb565Init((uint32_t)my_fb); /* Enable the LCD */ // LCD_DisplayOn(); DMA_Config(); /*----------------------------- * 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*/ static lv_disp_draw_buf_t disp_buf_1; static lv_color_t buf1_1[TFT_HOR_RES * 50]; // static lv_color_t buf1_2[TFT_HOR_RES * 30]; lv_disp_draw_buf_init(&disp_buf_1, buf1_1, NULL, TFT_HOR_RES * 50); /*Initialize the display buffer*/ /*----------------------------------- * Register the display in LittlevGL *----------------------------------*/ 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 = TFT_HOR_RES; disp_drv.ver_res = TFT_VER_RES; /*Used to copy the buffer's content to the display*/ disp_drv.flush_cb = ex_disp_flush; // disp_drv.clean_dcache_cb = ex_disp_clean_dcache; /*Set a display buffer*/ disp_drv.draw_buf = &disp_buf_1; /*Enable software rotation*/ disp_drv.sw_rotate = 1; /*Finally register the driver*/ our_disp = lv_disp_drv_register(&disp_drv); } /********************** * STATIC FUNCTIONS **********************/ /* 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_flush_ready()' has to be called when finished * This function is required only when LV_VDB_SIZE != 0 in lv_conf.h*/ static void ex_disp_flush(lv_disp_drv_t *drv, const lv_area_t *area, lv_color_t * color_p) { int32_t x1 = area->x1; int32_t x2 = area->x2; int32_t y1 = area->y1; int32_t y2 = area->y2; /*Return if the area is out the screen*/ if(x2 < 0) return; if(y2 < 0) return; if(x1 > TFT_HOR_RES - 1) return; if(y1 > TFT_VER_RES - 1) return; /*Truncate the area to the screen*/ int32_t act_x1 = x1 < 0 ? 0 : x1; int32_t act_y1 = y1 < 0 ? 0 : y1; int32_t act_x2 = x2 > TFT_HOR_RES - 1 ? TFT_HOR_RES - 1 : x2; int32_t act_y2 = y2 > TFT_VER_RES - 1 ? TFT_VER_RES - 1 : y2; x1_flush = act_x1; y1_flush = act_y1; x2_flush = act_x2; y2_fill = act_y2; y_fill_act = act_y1; buf_to_flush = color_p; // SCB_CleanInvalidateDCache(); // SCB_InvalidateICache(); /*##-7- Start the DMA transfer using the interrupt mode #*/ /* Configure the source, destination and buffer size DMA fields and Start DMA Stream transfer */ /* Enable All the DMA interrupts */ HAL_StatusTypeDef err; uint32_t length = (x2_flush - x1_flush + 1); #if LV_COLOR_DEPTH == 24 || LV_COLOR_DEPTH == 32 length *= 2; /* STM32 DMA uses 16-bit chunks so multiply by 2 for 32-bit color */ #endif err = HAL_DMA_Start_IT(&hdma_memtomem_dma2_stream0,(uint32_t)buf_to_flush, (uint32_t)&my_fb[y_fill_act * TFT_HOR_RES + x1_flush], length); if(err != HAL_OK) { while(1); /*Halt on error*/ } } //static void ex_disp_clean_dcache(lv_disp_drv_t *drv) //{ // SCB_CleanInvalidateDCache(); //} static void DMA_Config(void) { /*##-5- Select Callbacks functions called after Transfer complete and Transfer error */ HAL_DMA_RegisterCallback(&hdma_memtomem_dma2_stream0, HAL_DMA_XFER_CPLT_CB_ID, DMA_TransferComplete); HAL_DMA_RegisterCallback(&hdma_memtomem_dma2_stream0, HAL_DMA_XFER_ERROR_CB_ID, DMA_TransferError); } /** * @brief DMA conversion complete callback * @note This function is executed when the transfer complete interrupt * is generated * @retval None */ static void DMA_TransferComplete(DMA_HandleTypeDef *han) { y_fill_act ++; if(y_fill_act > y2_fill) { // SCB_CleanInvalidateDCache(); // SCB_InvalidateICache(); lv_disp_flush_ready(&disp_drv); } else { uint32_t length = (x2_flush - x1_flush + 1); buf_to_flush += x2_flush - x1_flush + 1; /*##-7- Start the DMA transfer using the interrupt mode ####################*/ /* Configure the source, destination and buffer size DMA fields and Start DMA Stream transfer */ /* Enable All the DMA interrupts */ #if LV_COLOR_DEPTH == 24 || LV_COLOR_DEPTH == 32 length *= 2; /* STM32 DMA uses 16-bit chunks so multiply by 2 for 32-bit color */ #endif if(HAL_DMA_Start_IT(han,(uint32_t)buf_to_flush, (uint32_t)&my_fb[y_fill_act * TFT_HOR_RES + x1_flush], length) != HAL_OK) { while(1); /*Halt on error*/ } } } /** * @brief DMA conversion error callback * @note This function is executed when the transfer error interrupt * is generated during DMA transfer * @retval None */ static void DMA_TransferError(DMA_HandleTypeDef *han) { }