/* USER CODE BEGIN Header */ /** ****************************************************************************** * @file : main.c * @brief : Main program body ****************************************************************************** * @attention * * Copyright (c) 2023 STMicroelectronics. * All rights reserved. * * This software is licensed under terms that can be found in the LICENSE file * in the root directory of this software component. * If no LICENSE file comes with this software, it is provided AS-IS. * ****************************************************************************** */ /* USER CODE END Header */ /* Includes ------------------------------------------------------------------*/ #include "main.h" /* Private includes ----------------------------------------------------------*/ /* USER CODE BEGIN Includes */ #include "SDRAM.h" #include "lvgl.h" /* USER CODE END Includes */ /* Private typedef -----------------------------------------------------------*/ /* USER CODE BEGIN PTD */ /* USER CODE END PTD */ /* Private define ------------------------------------------------------------*/ /* USER CODE BEGIN PD */ /* USER CODE END PD */ /* Private macro -------------------------------------------------------------*/ /* USER CODE BEGIN PM */ #define MY_DISP_HOR_RES 800 #define MY_DISP_VER_RES 480 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; static lv_disp_drv_t disp_drv; /*Descriptor of a display driver*/ static void disp_flush(lv_disp_drv_t * disp_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_TransferComplete(DMA_HandleTypeDef *han); static void DMA_TransferError(DMA_HandleTypeDef *han); /* USER CODE END PM */ /* Private variables ---------------------------------------------------------*/ LTDC_HandleTypeDef hltdc; DMA_HandleTypeDef hdma_memtomem_dma2_stream0; SDRAM_HandleTypeDef hsdram1; /* USER CODE BEGIN PV */ /* USER CODE END PV */ /* Private function prototypes -----------------------------------------------*/ void SystemClock_Config(void); static void MX_GPIO_Init(void); static void MX_DMA_Init(void); static void MX_FMC_Init(void); static void MX_LTDC_Init(void); /* USER CODE BEGIN PFP */ uint16_t * lcd_fb = (uint16_t*) (0xC0000000); /* USER CODE END PFP */ /* Private user code ---------------------------------------------------------*/ /* USER CODE BEGIN 0 */ static void disp_flush(lv_disp_drv_t * disp_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 > MY_DISP_HOR_RES - 1) return; if(y1 > MY_DISP_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 > MY_DISP_HOR_RES - 1 ? MY_DISP_HOR_RES - 1 : x2; int32_t act_y2 = y2 > MY_DISP_VER_RES - 1 ? MY_DISP_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); err = HAL_DMA_Start_IT(&hdma_memtomem_dma2_stream0, (uint32_t)buf_to_flush, (uint32_t) &lcd_fb[y_fill_act * MY_DISP_HOR_RES + x1_flush], length); if(err != HAL_OK) { while(1); /*Halt on error*/ } /*IMPORTANT!!! *Inform the graphics library that you are ready with the flushing*/ lv_disp_flush_ready(disp_drv); } 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(HAL_DMA_Start_IT( han, (uint32_t)buf_to_flush, (uint32_t)&lcd_fb[y_fill_act * MY_DISP_HOR_RES + x1_flush], length) != HAL_OK) { while(1); /*Halt on error*/ } } } static void DMA_TransferError(DMA_HandleTypeDef *han) { } static void ex_disp_clean_dcache(lv_disp_drv_t *drv) { SCB_CleanInvalidateDCache(); } void lv_port_disp_init(void) { MX_DMA_Init(); static lv_disp_draw_buf_t draw_buf_dsc_1; static lv_color_t buf1_1[MY_DISP_HOR_RES * 10]; lv_disp_draw_buf_init(&draw_buf_dsc_1, buf1_1, NULL, MY_DISP_HOR_RES * 10); /*Initialize the display buffer*/ /*----------------------------------- * Register the display in LVGL *----------------------------------*/ lv_disp_drv_init(&disp_drv); /*Set the resolution of the display*/ disp_drv.hor_res = MY_DISP_HOR_RES;/*800*/ disp_drv.ver_res = MY_DISP_VER_RES;/*480*/ /*Used to copy the buffer's content to the display*/ disp_drv.flush_cb = disp_flush; disp_drv.clean_dcache_cb = ex_disp_clean_dcache; /*Set a display buffer*/ disp_drv.draw_buf = &draw_buf_dsc_1; /*Finally register the driver*/ lv_disp_drv_register(&disp_drv); } /* USER CODE END 0 */ /** * @brief The application entry point. * @retval int */ 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_FMC_Init(); MX_LTDC_Init(); /* USER CODE BEGIN 2 */ lv_init(); /*Initialize `disp_buf` with the buffer(s) */ lv_port_disp_init(); //lv_example_get_started_1(); lv_demo_widgets(); /* USER CODE END 2 */ /* Infinite loop */ /* USER CODE BEGIN WHILE */ while (1) { /* USER CODE END WHILE */ /* USER CODE BEGIN 3 */ lv_timer_handler(); HAL_Delay(10); //lv_tick_inc(30); //lv_task_handler(); } /* USER CODE END 3 */ } /** * @brief System Clock Configuration * @retval None */ void SystemClock_Config(void) { RCC_OscInitTypeDef RCC_OscInitStruct = {0}; RCC_ClkInitTypeDef RCC_ClkInitStruct = {0}; /** Supply configuration update enable */ HAL_PWREx_ConfigSupply(PWR_LDO_SUPPLY); /** Configure the main internal regulator output voltage */ __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1); while(!__HAL_PWR_GET_FLAG(PWR_FLAG_VOSRDY)) {} __HAL_RCC_SYSCFG_CLK_ENABLE(); __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE0); while(!__HAL_PWR_GET_FLAG(PWR_FLAG_VOSRDY)) {} /** Initializes the RCC Oscillators according to the specified parameters * in the RCC_OscInitTypeDef structure. */ RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI; RCC_OscInitStruct.HSIState = RCC_HSI_DIV1; RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT; RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON; RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI; RCC_OscInitStruct.PLL.PLLM = 32; RCC_OscInitStruct.PLL.PLLN = 480; RCC_OscInitStruct.PLL.PLLP = 2; RCC_OscInitStruct.PLL.PLLQ = 9; RCC_OscInitStruct.PLL.PLLR = 2; RCC_OscInitStruct.PLL.PLLRGE = RCC_PLL1VCIRANGE_1; RCC_OscInitStruct.PLL.PLLVCOSEL = RCC_PLL1VCOWIDE; RCC_OscInitStruct.PLL.PLLFRACN = 0; if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) { Error_Handler(); } /** Initializes the CPU, AHB and APB buses clocks */ RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2 |RCC_CLOCKTYPE_D3PCLK1|RCC_CLOCKTYPE_D1PCLK1; RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK; RCC_ClkInitStruct.SYSCLKDivider = RCC_SYSCLK_DIV1; RCC_ClkInitStruct.AHBCLKDivider = RCC_HCLK_DIV2; RCC_ClkInitStruct.APB3CLKDivider = RCC_APB3_DIV2; RCC_ClkInitStruct.APB1CLKDivider = RCC_APB1_DIV2; RCC_ClkInitStruct.APB2CLKDivider = RCC_APB2_DIV2; RCC_ClkInitStruct.APB4CLKDivider = RCC_APB4_DIV2; if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_4) != HAL_OK) { Error_Handler(); } } /** * @brief LTDC Initialization Function * @param None * @retval None */ static void MX_LTDC_Init(void) { /* USER CODE BEGIN LTDC_Init 0 */ /* USER CODE END LTDC_Init 0 */ LTDC_LayerCfgTypeDef pLayerCfg = {0}; /* USER CODE BEGIN LTDC_Init 1 */ /* USER CODE END LTDC_Init 1 */ hltdc.Instance = LTDC; hltdc.Init.HSPolarity = LTDC_HSPOLARITY_AL; hltdc.Init.VSPolarity = LTDC_VSPOLARITY_AL; hltdc.Init.DEPolarity = LTDC_DEPOLARITY_AL; hltdc.Init.PCPolarity = LTDC_PCPOLARITY_IPC; hltdc.Init.HorizontalSync = 0; hltdc.Init.VerticalSync = 0; hltdc.Init.AccumulatedHBP = 46; hltdc.Init.AccumulatedVBP = 23; hltdc.Init.AccumulatedActiveW = 846; hltdc.Init.AccumulatedActiveH = 503; hltdc.Init.TotalWidth = 1056; hltdc.Init.TotalHeigh = 525; hltdc.Init.Backcolor.Blue = 0; hltdc.Init.Backcolor.Green = 0; hltdc.Init.Backcolor.Red = 0; if (HAL_LTDC_Init(&hltdc) != HAL_OK) { Error_Handler(); } pLayerCfg.WindowX0 = 0; pLayerCfg.WindowX1 = 800; pLayerCfg.WindowY0 = 0; pLayerCfg.WindowY1 = 480; pLayerCfg.PixelFormat = LTDC_PIXEL_FORMAT_RGB565; pLayerCfg.Alpha = 255; pLayerCfg.Alpha0 = 0; pLayerCfg.BlendingFactor1 = LTDC_BLENDING_FACTOR1_PAxCA; pLayerCfg.BlendingFactor2 = LTDC_BLENDING_FACTOR2_PAxCA; pLayerCfg.FBStartAdress = 0xC0000000; pLayerCfg.ImageWidth = 800; pLayerCfg.ImageHeight = 480; pLayerCfg.Backcolor.Blue = 0; pLayerCfg.Backcolor.Green = 0; pLayerCfg.Backcolor.Red = 0; if (HAL_LTDC_ConfigLayer(&hltdc, &pLayerCfg, 0) != HAL_OK) { Error_Handler(); } /* USER CODE BEGIN LTDC_Init 2 */ /* USER CODE END LTDC_Init 2 */ } /** * Enable DMA controller clock * Configure DMA for memory to memory transfers * hdma_memtomem_dma2_stream0 */ static void MX_DMA_Init(void) { /* DMA controller clock enable */ __HAL_RCC_DMA2_CLK_ENABLE(); /* Configure DMA request hdma_memtomem_dma2_stream0 on DMA2_Stream0 */ hdma_memtomem_dma2_stream0.Instance = DMA2_Stream0; hdma_memtomem_dma2_stream0.Init.Request = DMA_REQUEST_MEM2MEM; 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_1QUARTERFULL; hdma_memtomem_dma2_stream0.Init.MemBurst = DMA_MBURST_SINGLE; hdma_memtomem_dma2_stream0.Init.PeriphBurst = DMA_PBURST_SINGLE; if (HAL_DMA_Init(&hdma_memtomem_dma2_stream0) != HAL_OK) { Error_Handler( ); } 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); /* DMA interrupt init */ /* DMA2_Stream0_IRQn interrupt configuration */ HAL_NVIC_SetPriority(DMA2_Stream0_IRQn, 0, 0); HAL_NVIC_EnableIRQ(DMA2_Stream0_IRQn); } /* FMC initialization function */ static void MX_FMC_Init(void) { /* USER CODE BEGIN FMC_Init 0 */ /* USER CODE END FMC_Init 0 */ FMC_SDRAM_TimingTypeDef SdramTiming = {0}; /* USER CODE BEGIN FMC_Init 1 */ /* USER CODE END FMC_Init 1 */ /** Perform the SDRAM1 memory initialization sequence */ hsdram1.Instance = FMC_SDRAM_DEVICE; /* hsdram1.Init */ hsdram1.Init.SDBank = FMC_SDRAM_BANK1; hsdram1.Init.ColumnBitsNumber = FMC_SDRAM_COLUMN_BITS_NUM_9; hsdram1.Init.RowBitsNumber = FMC_SDRAM_ROW_BITS_NUM_13; hsdram1.Init.MemoryDataWidth = FMC_SDRAM_MEM_BUS_WIDTH_16; hsdram1.Init.InternalBankNumber = FMC_SDRAM_INTERN_BANKS_NUM_4; hsdram1.Init.CASLatency = FMC_SDRAM_CAS_LATENCY_3; hsdram1.Init.WriteProtection = FMC_SDRAM_WRITE_PROTECTION_DISABLE; hsdram1.Init.SDClockPeriod = FMC_SDRAM_CLOCK_PERIOD_2; hsdram1.Init.ReadBurst = FMC_SDRAM_RBURST_ENABLE; hsdram1.Init.ReadPipeDelay = FMC_SDRAM_RPIPE_DELAY_0; /* SdramTiming */ SdramTiming.LoadToActiveDelay = 2; SdramTiming.ExitSelfRefreshDelay = 7; SdramTiming.SelfRefreshTime = 5; SdramTiming.RowCycleDelay = 6; SdramTiming.WriteRecoveryTime = 3; SdramTiming.RPDelay = 2; SdramTiming.RCDDelay = 2; if (HAL_SDRAM_Init(&hsdram1, &SdramTiming) != HAL_OK) { Error_Handler( ); } /* USER CODE BEGIN FMC_Init 2 */ SDRAM_Initialization(); /* USER CODE END FMC_Init 2 */ } /** * @brief GPIO Initialization Function * @param None * @retval None */ static void MX_GPIO_Init(void) { GPIO_InitTypeDef GPIO_InitStruct = {0}; /* USER CODE BEGIN MX_GPIO_Init_1 */ /* USER CODE END MX_GPIO_Init_1 */ /* GPIO Ports Clock Enable */ __HAL_RCC_GPIOI_CLK_ENABLE(); __HAL_RCC_GPIOF_CLK_ENABLE(); __HAL_RCC_GPIOC_CLK_ENABLE(); __HAL_RCC_GPIOG_CLK_ENABLE(); __HAL_RCC_GPIOE_CLK_ENABLE(); __HAL_RCC_GPIOH_CLK_ENABLE(); __HAL_RCC_GPIOD_CLK_ENABLE(); __HAL_RCC_GPIOA_CLK_ENABLE(); __HAL_RCC_GPIOB_CLK_ENABLE(); /*Configure GPIO pin Output Level */ HAL_GPIO_WritePin(LCD_BL_GPIO_Port, LCD_BL_Pin, GPIO_PIN_SET); /*Configure GPIO pin : LCD_BL_Pin */ GPIO_InitStruct.Pin = LCD_BL_Pin; GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; HAL_GPIO_Init(LCD_BL_GPIO_Port, &GPIO_InitStruct); /* USER CODE BEGIN MX_GPIO_Init_2 */ /* USER CODE END MX_GPIO_Init_2 */ } /* USER CODE BEGIN 4 */ /* USER CODE END 4 */ /** * @brief This function is executed in case of error occurrence. * @retval None */ void Error_Handler(void) { /* USER CODE BEGIN Error_Handler_Debug */ /* User can add his own implementation to report the HAL error return state */ __disable_irq(); while (1) { } /* USER CODE END Error_Handler_Debug */ } #ifdef USE_FULL_ASSERT /** * @brief Reports the name of the source file and the source line number * where the assert_param error has occurred. * @param file: pointer to the source file name * @param line: assert_param error line source number * @retval None */ void assert_failed(uint8_t *file, uint32_t line) { /* USER CODE BEGIN 6 */ /* User can add his own implementation to report the file name and line number, ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */ /* USER CODE END 6 */ } #endif /* USE_FULL_ASSERT */