Description
Everything is showing properly, but quick transitions fail to render and shows images dragged along the x axis. As an example, images of how the lv_demo_widgets
looks are attached. You can see how the top tab bar, showing properly on the first run, fails to render after automatically sliding to next screen. Additionally, while the animation is scrolling the window up and down, I’m able to see some glitches on the body of the window that is scrolling, not being completely smooth.
What MCU/Processor/Board and compiler are you using?
STM32F407, STM32F4-DISCO, gcc, LVGL 7.1, and ILI9325 320x240 Display
Originally clock working at 168 MHz
What do you want to achieve?
Just displaying lv_demo_widgets
on this MCU + Display
What have you tried so far?
-Slowing down clock speed
-Using different DMA configurations
-Increasing timings for FSCM operations
-Adding time delay after lv_disp_flush_ready
-Test different sizes for disp_drv.buffer
between DISP_HOR_RES * 10
and DISP_HOR_RES * 120
-Using one and two buffers
No improvement was found during these changes. Even if refresh is strongly slowed down, the problem persists
Code to reproduce
/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
#define DISP_HOR_RES 320
#define DISP_VER_RES 240
#define DISP_BUFFER_LINES 60
/* USER CODE END PD */
/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */
/* USER CODE END PM */
/* Private variables ---------------------------------------------------------*/
/* USER CODE BEGIN PV */
static lv_disp_drv_t disp_drv;
static volatile uint16_t *my_fb = (volatile uint16_t *) 0x60020000;
static uint32_t x1_flush;
static uint32_t y1_flush;
static uint32_t x2_flush;
static uint32_t y2_fill;
static uint32_t y_fill_act;
static lv_color_t *buf_to_flush;
static lv_color_t disp_buf1[DISP_HOR_RES * DISP_BUFFER_LINES];
static lv_color_t disp_buf2[DISP_HOR_RES * DISP_BUFFER_LINES];
static lv_disp_buf_t buf;
int main(void) {
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_DMA_Init();
MX_FSMC_Init();
/* USER CODE BEGIN 2 */
ili9325_Init();
lv_init();
lv_disp_buf_init(&buf, disp_buf1, disp_buf2, DISP_HOR_RES * DISP_BUFFER_LINES);
lv_disp_drv_init(&disp_drv);
disp_drv.buffer = &buf;
disp_drv.hor_res = 320;
disp_drv.ver_res = 240;
disp_drv.flush_cb = my_flush_cb;
lv_disp_drv_register(&disp_drv);
lv_demo_widgets();
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1) {
HAL_Delay(10);
lv_task_handler();
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
static void my_flush_cb(lv_disp_drv_t *disp_drv, const lv_area_t *area, lv_color_t *color_p) {
/*Return if the area is out the screen*/
if (area->x2 < 0) return;
if (area->y2 < 0) return;
if (area->x1 > DISP_HOR_RES - 1) return;
if (area->y1 > DISP_VER_RES - 1) return;
/*Truncate the area to the screen*/
int32_t act_x1 = area->x1 < 0 ? 0 : area->x1;
int32_t act_y1 = area->y1 < 0 ? 0 : area->y1;
int32_t act_x2 = area->x2 > DISP_HOR_RES - 1 ? DISP_HOR_RES - 1 : area->x2;
int32_t act_y2 = area->y2 > DISP_VER_RES - 1 ? DISP_VER_RES - 1 : area->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;
/* Set Cursor */
ili9325_SetCursor(x1_flush, y1_flush);
/* Prepare to write GRAM */
LCD_IO_WriteReg(LCD_REG_34);
/*##-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;
err = HAL_DMA_Start_IT(&hdma_memtomem_dma2_stream0,
(uint32_t) buf_to_flush,
(uint32_t) my_fb,
(x2_flush - x1_flush + 1));
if (err != HAL_OK) {
while (1); /*Halt on error*/
}
}
void DMA_TransferComplete(DMA_HandleTypeDef *han) {
y_fill_act++;
if (y_fill_act > y2_fill) {
lv_disp_flush_ready(&disp_drv);
} else {
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 (HAL_DMA_Start_IT(han, (uint32_t) buf_to_flush, (uint32_t) my_fb,
(x2_flush - x1_flush + 1)) != HAL_OK) {
while (1); /*Halt on error*/
}
}
}
Actual DMA configuration
hdma_memtomem_dma2_stream0.Instance = DMA2_Stream0;
hdma_memtomem_dma2_stream0.Init.Channel = DMA_CHANNEL_0;
hdma_memtomem_dma2_stream0.Init.Direction = DMA_MEMORY_TO_MEMORY;
hdma_memtomem_dma2_stream0.Init.PeriphInc = DMA_PINC_ENABLE;
hdma_memtomem_dma2_stream0.Init.MemInc = DMA_MINC_ENABLE;
hdma_memtomem_dma2_stream0.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
hdma_memtomem_dma2_stream0.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
hdma_memtomem_dma2_stream0.Init.Mode = DMA_NORMAL;
hdma_memtomem_dma2_stream0.Init.Priority = DMA_PRIORITY_HIGH;
hdma_memtomem_dma2_stream0.Init.FIFOMode = DMA_FIFOMODE_ENABLE;
hdma_memtomem_dma2_stream0.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_HALFFULL;
hdma_memtomem_dma2_stream0.Init.MemBurst = DMA_MBURST_INC4;
hdma_memtomem_dma2_stream0.Init.PeriphBurst = DMA_PBURST_INC4;
if (HAL_DMA_Init(&hdma_memtomem_dma2_stream0) != HAL_OK)
{
Error_Handler();
}
Actual FSCM timing configuration
/* Timing for FSCM */
Timing.AddressSetupTime = 2;
Timing.AddressHoldTime = 7;
Timing.DataSetupTime = 20;
Timing.BusTurnAroundDuration = 0;
Timing.CLKDivision = 16;
Timing.DataLatency = 17;
Timing.AccessMode = FSMC_ACCESS_MODE_A;
/* ExtTiming */
Screenshot and/or video
First run
After first transition, see the tab bar (the rest of the image is blurry because its automatically scrolling up & down)
After second transition, see the tab bar (the rest of the image is blurry because its automatically scrolling up & down)