F429 Simple Custom TFT Driver

Description

I’m making a simple custom TFT driver for F429 with dma2d only. But I’m getting a problem like this:

Imaget

My functions to draw image, rectangles, fillscreen are working perfectly.

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

Custom STM32F429BIT6 with RGB888 (800x480) and SDRAM

What LVGL version are you using?

V8.0

What have you tried so far?

Change to internal/external RAM

Code to reproduce

My tft code is here

/**
 * @file tft.c
 *
 */

/*********************
 *      INCLUDES
 *********************/
#include "lv_conf.h"
#include "lvgl/lvgl.h"
#include <string.h>
#include <stdlib.h>

#include "tft.h"
#include "stm32f4xx.h"


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

static lv_disp_drv_t display_drv;                         /*Descriptor of a display driver*/

void tft_init(void)
{
	SDRAM_init(&hsdram1);
	HAL_LTDC_SetAddress(&hltdc,(uint32_t) LCD_FRAME_BUFFER + BUFFER_OFFSET,0);
	
   /*-----------------------------
	* 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*/

	#define SDRAM_START_ADDR  ((uint32_t)0xD0000000)
	#define FB_SIZE						((uint32_t)LV_HOR_RES_MAX * LV_VER_RES_MAX * 2)
	
	/* Internal RAM */
	#define valor 20
	static lv_disp_buf_t disp_buf_2;
  static lv_color_t buf2_1[LV_HOR_RES_MAX * valor];                        /*A buffer for 10 rows*/
  static lv_color_t buf2_2[LV_HOR_RES_MAX * valor];                        /*An other buffer for 10 rows*/
  lv_disp_buf_init(&disp_buf_2, buf2_1, buf2_2, LV_HOR_RES_MAX * valor);   /*Initialize the display buffer*/
	
	/* External RAM (SDRAM) */
//	static lv_disp_buf_t disp_buf_2;
//	static lv_color_t *buf2_1 = (lv_color_t *)(SDRAM_START_ADDR + FB_SIZE);                      /*A buffer for 10 rows*/
//	static lv_color_t *buf2_2 = (lv_color_t *)(SDRAM_START_ADDR + FB_SIZE + (TFT_HOR_RES * 48));                      /*A buffer for 10 rows*/
//	lv_disp_buf_init(&disp_buf_2, buf2_1, buf2_2, LV_HOR_RES_MAX * 48);   /*Initialize the display buffer*/

	lv_disp_drv_init(&display_drv); 
	
	/*Set the resolution of the display*/
  display_drv.hor_res = 800;
  display_drv.ver_res = 480;

  /*Used to copy the buffer's content to the display*/
  display_drv.flush_cb = disp_flush;

  /*Set a display buffer*/
  display_drv.buffer = &disp_buf_2;

  /*Finally register the driver*/
  lv_disp_drv_register(&display_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_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)
{
	DMA2D_DrawImage((uint32_t)color_p, area->x1, area->y1, (area->x2) - (area->x1), (area->y2) - (area->y1));
  lv_disp_flush_ready(disp_drv);
}


FMC_SDRAM_CommandTypeDef command;

void SDRAM_init(SDRAM_HandleTypeDef *hsdram)
{
	__IO uint32_t tmpr = 0;

	command.CommandMode = FMC_SDRAM_CMD_CLK_ENABLE;
	command.CommandTarget = FMC_SDRAM_CMD_TARGET_BANK2;
	command.AutoRefreshNumber = 1;
	command.ModeRegisterDefinition = 0;
	HAL_SDRAM_SendCommand(hsdram, &command, SDRAM_TIMEOUT);
	HAL_Delay(10);
	command.CommandMode = FMC_SDRAM_CMD_PALL;
	command.CommandTarget = FMC_SDRAM_CMD_TARGET_BANK2;
	command.AutoRefreshNumber = 1;
	command.ModeRegisterDefinition = 0;
	HAL_SDRAM_SendCommand(hsdram, &command, SDRAM_TIMEOUT);
	HAL_Delay(10);
	command.CommandMode = FMC_SDRAM_CMD_AUTOREFRESH_MODE;
	command.CommandTarget = FMC_SDRAM_CMD_TARGET_BANK2;
	command.AutoRefreshNumber = 4;
	command.ModeRegisterDefinition = 0;
	HAL_SDRAM_SendCommand(hsdram, &command, SDRAM_TIMEOUT);
	HAL_Delay(10);

	tmpr = (uint32_t) 0x01 | 0x00 | 0x30 | 0x00 | 0x200;
	command.CommandMode = FMC_SDRAM_CMD_LOAD_MODE;
	command.CommandTarget = FMC_SDRAM_CMD_TARGET_BANK2;
	command.AutoRefreshNumber = 1;
	command.ModeRegisterDefinition = tmpr;
	HAL_SDRAM_SendCommand(hsdram, &command, SDRAM_TIMEOUT);
	HAL_Delay(10);

	HAL_SDRAM_ProgramRefreshRate(hsdram, 1386);
}

void DMA2D_DrawImage(uint32_t data, uint32_t x, uint32_t y, uint32_t width, uint32_t height)
{
  //uint32_t destination = (LCD_FRAME_BUFFER + BUFFER_OFFSET) + (x + y * LV_HOR_RES_MAX) * 3;

  hdma2d.Instance = DMA2D;

  hdma2d.Init.Mode = DMA2D_M2M;
  hdma2d.Init.ColorMode = DMA2D_OUTPUT_RGB888;
  hdma2d.Init.OutputOffset = LV_HOR_RES_MAX - width;

  // Foreground
  hdma2d.LayerCfg[0].AlphaMode = DMA2D_NO_MODIF_ALPHA;
  hdma2d.LayerCfg[0].InputColorMode = DMA2D_OUTPUT_RGB888;
  hdma2d.LayerCfg[0].InputOffset = 0;//LV_HOR_RES_MAX - width;
  hdma2d.LayerCfg[0].InputAlpha = 0x00;


  HAL_DMA2D_Init(&hdma2d);
	HAL_DMA2D_Start(&hdma2d, (uint32_t)data, (LCD_FRAME_BUFFER + BUFFER_OFFSET) + (x + y * LV_HOR_RES_MAX) * 3, width, height);
  HAL_DMA2D_PollForTransfer(&hdma2d, 10);
}

void DMA2D_FillRect(uint32_t color, uint32_t x, uint32_t y, uint32_t width, uint32_t height)
{
  hdma2d.Init.Mode = DMA2D_R2M;
  hdma2d.Init.OutputOffset = LV_HOR_RES_MAX - width;

  HAL_DMA2D_Init(&hdma2d);
  HAL_DMA2D_Start(&hdma2d, color, (LCD_FRAME_BUFFER + BUFFER_OFFSET) + (x + y * LV_HOR_RES_MAX) * 3, width, height);
  HAL_DMA2D_PollForTransfer(&hdma2d, 10);
}


You might be off-by-one in disp_flush with the width and height. Usually you need to use x2 - x1 + 1 and y2 - y1 + 1.

Oh, I forget this. Thanks.

But now I’m trying to draw a linemeter, I can see it, but with some bugs…

Imaget