/** ****************************************************************************** * @file stm32u5x9j_discovery_lcd.c * @author MCD Application Team * @brief This file includes the driver for Liquid Crystal Display (LCD) module * mounted on MB1829A board (ARGB8888 color format). @verbatim 1. How To use this driver: -------------------------- - This driver is used to drive directly in command mode a LCD TFT using the DSI interface. The following IPs are implied : DSI Host IP block working in conjunction to the LTDC controller. - This driver is linked by construction to LCD. 2. Driver description: ---------------------- + Initialization steps: o Initialize the LCD using the BSP_LCD_Init() function. You can select display orientation with "Orientation" parameter (portrait, landscape, portrait with 180 degrees rotation or landscape with 180 degrees rotation). o Call BSP_LCD_GetXSize() and BSP_LCD_GetYsize() to get respectively width and height in pixels of LCD in the current orientation. o Call BSP_LCD_SetBrightness() and BSP_LCD_GetBrightness() to respectively set and get LCD brightness. o Call BSP_LCD_SetActiveLayer() to select the current active layer. o Call BSP_LCD_GetFormat() to get LCD pixel format supported. + Display on LCD: o Call BSP_LCD_DisplayOn() and BSP_LCD_DisplayOff() to respectively switch on and switch off the LCD display. o First, check that frame buffer is available using BSP_LCD_IsFrameBufferAvailable(). o When frame buffer is available, modify it using following functions: o Call BSP_LCD_WritePixel() and BSP_LCD_ReadPixel() to respectively write and read a pixel. o Call BSP_LCD_DrawHLine() to draw a horizontal line. o Call BSP_LCD_DrawVLine() to draw a vertical line. o Call BSP_LCD_DrawBitmap() to draw a bitmap. o Call BSP_LCD_FillRect() to draw a rectangle. o Call BSP_LCD_FillRGBRect() to draw a rectangle with RGB buffer. o Call BSP_LCD_Refresh() to refresh LCD display. + De-initialization steps: o De-initialize the LCD using the BSP_LCD_DeInit() function. @endverbatim ****************************************************************************** * @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. * ****************************************************************************** */ /* Includes ------------------------------------------------------------------*/ #include "colors.h" #include "stdint.h" #include "string.h" #include STM32_HAL_H /* Common Error codes */ #define BSP_ERROR_NONE 0 #define BSP_ERROR_NO_INIT -1 #define BSP_ERROR_WRONG_PARAM -2 #define BSP_ERROR_BUSY -3 #define BSP_ERROR_PERIPH_FAILURE -4 #define BSP_ERROR_COMPONENT_FAILURE -5 #define BSP_ERROR_UNKNOWN_FAILURE -6 #define BSP_ERROR_UNKNOWN_COMPONENT -7 #define BSP_ERROR_BUS_FAILURE -8 #define BSP_ERROR_CLOCK_FAILURE -9 #define BSP_ERROR_MSP_FAILURE -10 #define BSP_ERROR_FEATURE_NOT_SUPPORTED -11 #define BSP_ERROR_BUS_ACKNOWLEDGE_FAILURE (-102) /* Button user interrupt priority */ #define BSP_BUTTON_USER_IT_PRIORITY \ 0x0FUL /* Default is lowest priority level */ /* LCD interrupt priorities */ #define BSP_LCD_GFXMMU_IT_PRIORITY \ 0x0FUL /* Default is lowest priority level \ */ #define BSP_LCD_LTDC_IT_PRIORITY 0x0FUL /* Default is lowest priority level */ #define BSP_LCD_DSI_IT_PRIORITY 0x0FUL /* Default is lowest priority level */ /* HSPI RAM interrupt priority */ #define BSP_HSPI_RAM_IT_PRIORITY 0x0FUL /* Default is lowest priority level */ #define LCD_PIXEL_FORMAT_ARGB8888 \ 0x00000000U /*!< ARGB8888 LTDC pixel format \ */ #define LCD_PIXEL_FORMAT_RGB888 0x00000001U /*!< RGB888 LTDC pixel format */ #define LCD_PIXEL_FORMAT_RGB565 0x00000002U /*!< RGB565 LTDC pixel format */ #define LCD_PIXEL_FORMAT_ARGB1555 \ 0x00000003U /*!< ARGB1555 LTDC pixel format \ */ #define LCD_PIXEL_FORMAT_ARGB4444 \ 0x00000004U /*!< ARGB4444 LTDC pixel format \ */ #define LCD_PIXEL_FORMAT_L8 0x00000005U /*!< L8 LTDC pixel format */ #define LCD_PIXEL_FORMAT_AL44 0x00000006U /*!< AL44 LTDC pixel format */ #define LCD_PIXEL_FORMAT_AL88 0x00000007U /*!< AL88 LTDC pixel format */ /* LCD instances */ #define LCD_INSTANCES_NBR 1U /* LCD orientations */ #define LCD_ORIENTATION_PORTRAIT 0U #define LCD_ORIENTATION_LANDSCAPE 1U #define LCD_ORIENTATION_PORTRAIT_ROT180 2U #define LCD_ORIENTATION_LANDSCAPE_ROT180 3U #define DSI_POWERON_GPIO_PORT GPIOI #define DSI_POWERON_GPIO_PIN GPIO_PIN_5 #define DSI_POWERON_GPIO_CLOCK_ENABLE() __HAL_RCC_GPIOI_CLK_ENABLE() #define DSI_RESET_GPIO_PORT GPIOD #define DSI_RESET_GPIO_PIN GPIO_PIN_5 #define DSI_RESET_GPIO_CLOCK_ENABLE() __HAL_RCC_GPIOD_CLK_ENABLE() #define VSYNC 1 #define VBP 12 #define VFP 50 #define VACT 481 #define HSYNC 2 #define HBP 1 #define HFP 1 #define HACT 480 #define LCD_WIDTH 480 #define LCD_HEIGHT 480 #define PIXEL_PER_LINE 768U #define BYTE_PER_PIXEL 4U /* ARGB8888 */ #include "gfxmmu_lut.h" /** @addtogroup BSP * @{ */ /** @addtogroup STM32U5x9J_DISCOVERY * @{ */ /** @defgroup STM32U5x9J_DISCOVERY_LCD LCD * @{ */ /** @defgroup STM32U5x9J_DISCOVERY_LCD_Private_Defines LCD Private Constants * @{ */ /** * @} */ /** @defgroup STM32U5x9J_DISCOVERY_LCD_Private_Variables LCD Private Variables * @{ */ __attribute__((section(".fb1"))) ALIGN_32BYTES(uint32_t PhysFrameBuffer0[184320]); __attribute__((section(".fb2"))) ALIGN_32BYTES(uint32_t PhysFrameBuffer1[184320]); __attribute__((section(".gfxmmu_table"))) uint32_t gfxmmu_lut[2 * GFXMMU_LUT_SIZE]; __attribute__((section(".framebuffer_select"))) uint32_t act_frame_buffer = 0; #if (USE_HAL_GFXMMU_REGISTER_CALLBACKS == 1) static uint32_t LcdGfxmmu_IsMspCbValid[LCD_INSTANCES_NBR] = {0}; #endif /* (USE_HAL_GFXMMU_REGISTER_CALLBACKS == 1) */ #if (USE_HAL_LTDC_REGISTER_CALLBACKS == 1) static uint32_t LcdLtdc_IsMspCbValid[LCD_INSTANCES_NBR] = {0}; #endif /* (USE_HAL_LTDC_REGISTER_CALLBACKS == 1) */ #if (USE_HAL_DSI_REGISTER_CALLBACKS == 1) static uint32_t LcdDsi_IsMspCbValid[LCD_INSTANCES_NBR] = {0}; #endif /* (USE_HAL_DSI_REGISTER_CALLBACKS == 1) */ GFXMMU_HandleTypeDef hlcd_gfxmmu = {0}; LTDC_HandleTypeDef hlcd_ltdc = {0}; DSI_HandleTypeDef hlcd_dsi = {0}; static DSI_VidCfgTypeDef DSIVidCfg = {0}; uint16_t window_x0 = 0; uint16_t window_y0 = 0; uint16_t window_x1 = 0; uint16_t window_y1 = 0; uint16_t cursor_x = 0; uint16_t cursor_y = 0; /** * @} */ /** @defgroup STM32U5x9J_DISCOVERY_LCD_Private_FunctionPrototypes LCD Private * Function Prototypes * @{ */ static int32_t LCD_Init(void); static int32_t LCD_DeInit(void); static void GFXMMU_MspInit(GFXMMU_HandleTypeDef *hgfxmmu); static void GFXMMU_MspDeInit(GFXMMU_HandleTypeDef *hgfxmmu); static void LTDC_MspInit(LTDC_HandleTypeDef *hltdc); static void LTDC_MspDeInit(LTDC_HandleTypeDef *hltdc); static void DSI_MspInit(DSI_HandleTypeDef *hdsi); static void DSI_MspDeInit(DSI_HandleTypeDef *hdsi); #if (USE_HAL_DSI_REGISTER_CALLBACKS == 1) static void DSI_EndOfRefreshCallback(DSI_HandleTypeDef *hdsi); #endif /* (USE_HAL_DSI_REGISTER_CALLBACKS == 1) */ /** * @} */ /** @addtogroup STM32U5x9J_DISCOVERY_LCD_Exported_Functions * @{ */ /** * @brief Initialize the LCD. * @param Instance LCD Instance. * @param Orientation LCD_ORIENTATION_PORTRAIT, LCD_ORIENTATION_LANDSCAPE, * LCD_ORIENTATION_PORTRAIT_ROT180 or * LCD_ORIENTATION_LANDSCAPE_ROT180. * @retval BSP status. */ int32_t BSP_LCD_Init(uint32_t Instance, uint32_t Orientation) { int32_t status = BSP_ERROR_NONE; if ((Instance >= LCD_INSTANCES_NBR) || (Orientation > LCD_ORIENTATION_LANDSCAPE_ROT180)) { status = BSP_ERROR_WRONG_PARAM; } else if ((Orientation == LCD_ORIENTATION_LANDSCAPE) || (Orientation == LCD_ORIENTATION_LANDSCAPE_ROT180)) { status = BSP_ERROR_FEATURE_NOT_SUPPORTED; } else { if (LCD_Init() != 0) { status = BSP_ERROR_PERIPH_FAILURE; } } return status; } /** * @brief De-Initialize the LCD. * @param Instance LCD Instance. * @retval BSP status. */ int32_t BSP_LCD_DeInit(uint32_t Instance) { int32_t status = BSP_ERROR_NONE; if (Instance >= LCD_INSTANCES_NBR) { status = BSP_ERROR_WRONG_PARAM; } else { if (LCD_DeInit() != 0) { status = BSP_ERROR_PERIPH_FAILURE; } } return status; } /** * @brief Set the display on. * @param Instance LCD Instance. * @retval BSP status. */ int32_t BSP_LCD_DisplayOn(uint32_t Instance) { int32_t status = BSP_ERROR_NONE; if (Instance >= LCD_INSTANCES_NBR) { status = BSP_ERROR_WRONG_PARAM; } else { /* Set the display on */ if (HAL_DSI_ShortWrite(&hlcd_dsi, 0, DSI_DCS_SHORT_PKT_WRITE_P1, DSI_SET_DISPLAY_ON, 0x00) != HAL_OK) { status = BSP_ERROR_WRONG_PARAM; } } return status; } /** * @brief Set the display off. * @param Instance LCD Instance. * @retval BSP status. */ int32_t BSP_LCD_DisplayOff(uint32_t Instance) { int32_t status = BSP_ERROR_NONE; if (Instance >= LCD_INSTANCES_NBR) { status = BSP_ERROR_WRONG_PARAM; } else { /* Set the display off */ if (HAL_DSI_ShortWrite(&hlcd_dsi, 0, DSI_DCS_SHORT_PKT_WRITE_P1, DSI_SET_DISPLAY_OFF, 0x00) != HAL_OK) { status = BSP_ERROR_WRONG_PARAM; } } return status; } /** * @brief Set the display brightness. * @param Instance LCD Instance. * @param Brightness [00: Min (black), 100 Max]. * @retval BSP status. */ int32_t BSP_LCD_SetBrightness(uint32_t Instance, uint32_t Brightness) { int32_t status; if ((Instance >= LCD_INSTANCES_NBR) || (Brightness > 100U)) { status = BSP_ERROR_WRONG_PARAM; } else { status = BSP_ERROR_FEATURE_NOT_SUPPORTED; } return status; } /** * @brief Get the display brightness. * @param Instance LCD Instance. * @param Brightness [00: Min (black), 100 Max]. * @retval BSP status. */ int32_t BSP_LCD_GetBrightness(uint32_t Instance, uint32_t *Brightness) { int32_t status; if ((Instance >= LCD_INSTANCES_NBR) || (Brightness == NULL)) { status = BSP_ERROR_WRONG_PARAM; } else { status = BSP_ERROR_FEATURE_NOT_SUPPORTED; } return status; } /** * @brief Get the LCD X size. * @param Instance LCD Instance. * @param Xsize LCD X size. * @retval BSP status. */ int32_t BSP_LCD_GetXSize(uint32_t Instance, uint32_t *Xsize) { int32_t status = BSP_ERROR_NONE; if ((Instance >= LCD_INSTANCES_NBR) || (Xsize == NULL)) { status = BSP_ERROR_WRONG_PARAM; } else { /* Get the display Xsize */ *Xsize = LCD_WIDTH; } return status; } /** * @brief Get the LCD Y size. * @param Instance LCD Instance. * @param Ysize LCD Y size. * @retval BSP status. */ int32_t BSP_LCD_GetYSize(uint32_t Instance, uint32_t *Ysize) { int32_t status = BSP_ERROR_NONE; if ((Instance >= LCD_INSTANCES_NBR) || (Ysize == NULL)) { status = BSP_ERROR_WRONG_PARAM; } else { /* Get the display Ysize */ *Ysize = LCD_HEIGHT; } return status; } /** * @brief Set the LCD active layer. * @param Instance LCD Instance. * @param LayerIndex Active layer index. * @retval BSP status. */ int32_t BSP_LCD_SetActiveLayer(uint32_t Instance, uint32_t LayerIndex) { int32_t status = BSP_ERROR_NONE; if (Instance >= LCD_INSTANCES_NBR) { status = BSP_ERROR_WRONG_PARAM; } else { /* Nothing to do */ UNUSED(LayerIndex); } return status; } /** * @brief Get pixel format supported by LCD. * @param Instance LCD Instance. * @param Format Pointer on pixel format. * @retval BSP status. */ int32_t BSP_LCD_GetFormat(uint32_t Instance, uint32_t *Format) { int32_t status = BSP_ERROR_NONE; if (Instance >= LCD_INSTANCES_NBR) { status = BSP_ERROR_WRONG_PARAM; } else { /* Get pixel format supported by LCD */ *Format = LCD_PIXEL_FORMAT_ARGB8888; } return status; } void MX_GFXMMU_Reinit(GFXMMU_HandleTypeDef *hgfxmmu) { /* Initialize GFXMMU */ hgfxmmu->Instance = GFXMMU; hgfxmmu->Init.BlocksPerLine = GFXMMU_192BLOCKS; hgfxmmu->Init.DefaultValue = 0xFFFFFFFFU; hgfxmmu->Init.Buffers.Buf0Address = (uint32_t)PhysFrameBuffer0; hgfxmmu->Init.Buffers.Buf1Address = (uint32_t)PhysFrameBuffer1; hgfxmmu->Init.Buffers.Buf2Address = 0; hgfxmmu->Init.Buffers.Buf3Address = 0; #if defined(GFXMMU_CR_CE) hgfxmmu->Init.CachePrefetch.Activation = DISABLE; hgfxmmu->Init.CachePrefetch.CacheLock = GFXMMU_CACHE_LOCK_DISABLE; hgfxmmu->Init.CachePrefetch.CacheLockBuffer = GFXMMU_CACHE_LOCK_BUFFER0; /* NU */ hgfxmmu->Init.CachePrefetch.CacheForce = GFXMMU_CACHE_FORCE_ENABLE; /* NU */ hgfxmmu->Init.CachePrefetch.OutterBufferability = GFXMMU_OUTTER_BUFFERABILITY_DISABLE; hgfxmmu->Init.CachePrefetch.OutterCachability = GFXMMU_OUTTER_CACHABILITY_DISABLE; hgfxmmu->Init.CachePrefetch.Prefetch = GFXMMU_PREFETCH_DISABLE; #endif /* GFXMMU_CR_CE */ #if defined(GFXMMU_CR_ACE) hgfxmmu->Init.AddressCache.Activation = DISABLE; hgfxmmu->Init.AddressCache.AddressCacheLockBuffer = GFXMMU_ADDRESSCACHE_LOCK_BUFFER0; #endif /* GFXMMU_CR_ACE */ hgfxmmu->Init.Interrupts.Activation = DISABLE; hgfxmmu->Init.Interrupts.UsedInterrupts = GFXMMU_AHB_MASTER_ERROR_IT; /* NU */ } /** * @brief MX GFXMMU initialization. * @param hgfxmmu GFXMMU handle. * @retval HAL status. */ __weak HAL_StatusTypeDef MX_GFXMMU_Init(GFXMMU_HandleTypeDef *hgfxmmu) { MX_GFXMMU_Reinit(hgfxmmu); return HAL_GFXMMU_Init(hgfxmmu); } /** * @brief MX LTDC clock configuration. * @param hltdc LTDC handle. * @retval HAL status. */ __weak HAL_StatusTypeDef MX_LTDC_ClockConfig(LTDC_HandleTypeDef *hltdc) { RCC_PeriphCLKInitTypeDef PLL3InitPeriph = {0}; /* Prevent unused argument(s) compilation warning */ UNUSED(hltdc); /* Start and configurre PLL3 */ /* HSE = 16MHZ */ /* 16/(M=4) = 4MHz input (min) */ /* 4*(N=125) = 500MHz VCO (almost max) */ /* 500/(P=8) = 62.5 for DSI ie exactly the lane byte clock*/ /* 500/(R=24) = 20.83 for LTDC exact match with DSI bandwidth */ PLL3InitPeriph.PeriphClockSelection = RCC_PERIPHCLK_LTDC; PLL3InitPeriph.LtdcClockSelection = RCC_LTDCCLKSOURCE_PLL3; PLL3InitPeriph.PLL3.PLL3M = 4; PLL3InitPeriph.PLL3.PLL3N = 125; PLL3InitPeriph.PLL3.PLL3P = 8; PLL3InitPeriph.PLL3.PLL3Q = 8; PLL3InitPeriph.PLL3.PLL3R = 24; PLL3InitPeriph.PLL3.PLL3FRACN = 0; PLL3InitPeriph.PLL3.PLL3RGE = RCC_PLLVCIRANGE_1; PLL3InitPeriph.PLL3.PLL3ClockOut = RCC_PLL3_DIVR | RCC_PLL3_DIVP; PLL3InitPeriph.PLL3.PLL3Source = RCC_PLLSOURCE_HSE; return HAL_RCCEx_PeriphCLKConfig(&PLL3InitPeriph); } void MX_LTDC_Reinit(LTDC_HandleTypeDef *hltdc) { /* LTDC initialization */ 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 = HSYNC - 1; hltdc->Init.AccumulatedHBP = HSYNC + HBP - 1; hltdc->Init.AccumulatedActiveW = HACT + HBP + HSYNC - 1; hltdc->Init.TotalWidth = HACT + HBP + HFP + HSYNC - 1; hltdc->Init.Backcolor.Red = 0; /* Not used default value */ hltdc->Init.Backcolor.Green = 0; /* Not used default value */ hltdc->Init.Backcolor.Blue = 0; /* Not used default value */ hltdc->Init.Backcolor.Reserved = 0xFF; HAL_LTDCEx_StructInitFromVideoConfig(&hlcd_ltdc, &DSIVidCfg); } /** * @brief MX LTDC initialization. * @param hltdc LTDC handle. * @retval HAL status. */ __weak HAL_StatusTypeDef MX_LTDC_Init(LTDC_HandleTypeDef *hltdc) { MX_LTDC_Reinit(hltdc); return HAL_LTDC_Init(hltdc); } // HAL_StatusTypeDef MX_LTDC_ReConfigLayer(LTDC_HandleTypeDef *hltdc, uint32_t // LayerIndex) //{ // LTDC_LayerCfgTypeDef LayerCfg = {0}; // ///* LTDC layer configuration */ // LayerCfg.WindowX0 = 0; // LayerCfg.WindowX1 = LCD_WIDTH; // LayerCfg.WindowY0 = 1; // LayerCfg.WindowY1 = (uint32_t)LCD_HEIGHT + 1UL; // LayerCfg.PixelFormat = LTDC_PIXEL_FORMAT_ARGB8888; // LayerCfg.Alpha = 0xFF; /* NU default value */ // LayerCfg.Alpha0 = 0; /* NU default value */ // LayerCfg.BlendingFactor1 = LTDC_BLENDING_FACTOR1_PAxCA; /* Not Used: default // value */ LayerCfg.BlendingFactor2 = LTDC_BLENDING_FACTOR2_PAxCA; /* Not // Used: default value */ LayerCfg.FBStartAdress = // GFXMMU_VIRTUAL_BUFFER0_BASE; LayerCfg.ImageWidth = PIXEL_PER_LINE; /* // Number of pixels per line in virtual frame buffer */ LayerCfg.ImageHeight = // LCD_HEIGHT; LayerCfg.Backcolor.Red = 0; /* Not Used: default value */ // LayerCfg.Backcolor.Green = 0; /* Not Used: default value */ // LayerCfg.Backcolor.Blue = 0; /* Not Used: default value */ // LayerCfg.Bac // return HAL_LTDC_ConfigLayer(hltdc, &LayerCfg, LayerIndex);kcolor.Reserved = // 0xFF; //} /** * @brief MX LTDC layer configuration. * @param hltdc LTDC handle. * @param LayerIndex LTDC layer index. * @retval HAL status. */ __weak HAL_StatusTypeDef MX_LTDC_ConfigLayer(LTDC_HandleTypeDef *hltdc, uint32_t LayerIndex, uint32_t fb_addr) { LTDC_LayerCfgTypeDef LayerCfg = {0}; /* LTDC layer configuration */ LayerCfg.WindowX0 = 0; LayerCfg.WindowX1 = LCD_WIDTH; LayerCfg.WindowY0 = 1; LayerCfg.WindowY1 = (uint32_t)LCD_HEIGHT + 1UL; LayerCfg.PixelFormat = LTDC_PIXEL_FORMAT_ARGB8888; LayerCfg.Alpha = 0xFF; /* NU default value */ LayerCfg.Alpha0 = 0; /* NU default value */ LayerCfg.BlendingFactor1 = LTDC_BLENDING_FACTOR1_PAxCA; /* Not Used: default value */ LayerCfg.BlendingFactor2 = LTDC_BLENDING_FACTOR2_PAxCA; /* Not Used: default value */ LayerCfg.FBStartAdress = fb_addr; LayerCfg.ImageWidth = PIXEL_PER_LINE; /* Number of pixels per line in virtual frame buffer */ LayerCfg.ImageHeight = LCD_HEIGHT; LayerCfg.Backcolor.Red = 0; /* Not Used: default value */ LayerCfg.Backcolor.Green = 0; /* Not Used: default value */ LayerCfg.Backcolor.Blue = 0; /* Not Used: default value */ LayerCfg.Backcolor.Reserved = 0xFF; return HAL_LTDC_ConfigLayer(hltdc, &LayerCfg, LayerIndex); } /** * @brief MX DSI initialization. * @param hdsi DSI handle. * @retval HAL status. */ HAL_StatusTypeDef MX_DSI_Reinit(DSI_HandleTypeDef *hdsi) { /* DSI initialization */ hdsi->Instance = DSI; hdsi->Init.AutomaticClockLaneControl = DSI_AUTO_CLK_LANE_CTRL_DISABLE; /* We have 1 data lane at 500Mbps => lane byte clock at 500/8 = 62,5 MHZ */ /* We want TX escape clock at around 20MHz and under 20MHz so clock division * is set to 4 */ hdsi->Init.TXEscapeCkdiv = 4; hdsi->Init.NumberOfLanes = DSI_TWO_DATA_LANES; hdsi->Init.PHYFrequencyRange = DSI_DPHY_FRANGE_450MHZ_510MHZ; hdsi->Init.PHYLowPowerOffset = 0; /* Configure the DSI for Video mode */ DSIVidCfg.VirtualChannelID = 0; DSIVidCfg.HSPolarity = DSI_HSYNC_ACTIVE_HIGH; DSIVidCfg.VSPolarity = DSI_VSYNC_ACTIVE_HIGH; DSIVidCfg.DEPolarity = DSI_DATA_ENABLE_ACTIVE_HIGH; DSIVidCfg.ColorCoding = DSI_RGB888; DSIVidCfg.Mode = DSI_VID_MODE_BURST; DSIVidCfg.PacketSize = LCD_WIDTH; DSIVidCfg.NullPacketSize = 0xFFFU; DSIVidCfg.HorizontalSyncActive = HSYNC * 3; DSIVidCfg.HorizontalBackPorch = HBP * 3; DSIVidCfg.HorizontalLine = (HACT + HSYNC + HBP + HFP) * 3; DSIVidCfg.VerticalSyncActive = VSYNC; DSIVidCfg.VerticalBackPorch = VBP; DSIVidCfg.VerticalFrontPorch = VFP; DSIVidCfg.VerticalActive = VACT; DSIVidCfg.LPCommandEnable = DSI_LP_COMMAND_ENABLE; DSIVidCfg.LPLargestPacketSize = 64; /* Specify for each region of the video frame, if the transmission of command * in LP mode is allowed in this region */ /* while streaming is active in video mode */ DSIVidCfg.LPHorizontalFrontPorchEnable = DSI_LP_HFP_ENABLE; DSIVidCfg.LPHorizontalBackPorchEnable = DSI_LP_HBP_ENABLE; DSIVidCfg.LPVerticalActiveEnable = DSI_LP_VACT_ENABLE; DSIVidCfg.LPVerticalFrontPorchEnable = DSI_LP_VFP_ENABLE; DSIVidCfg.LPVerticalBackPorchEnable = DSI_LP_VBP_ENABLE; DSIVidCfg.LPVerticalSyncActiveEnable = DSI_LP_VSYNC_ENABLE; DSIVidCfg.FrameBTAAcknowledgeEnable = DSI_FBTAA_ENABLE; DSIVidCfg.LooselyPacked = DSI_LOOSELY_PACKED_DISABLE; return HAL_OK; } /** * @brief MX DSI initialization. * @param hdsi DSI handle. * @retval HAL status. */ __weak HAL_StatusTypeDef MX_DSI_Init(DSI_HandleTypeDef *hdsi) { DSI_PLLInitTypeDef PLLInit = {0}; /* DSI initialization */ hdsi->Instance = DSI; hdsi->Init.AutomaticClockLaneControl = DSI_AUTO_CLK_LANE_CTRL_DISABLE; /* We have 1 data lane at 500Mbps => lane byte clock at 500/8 = 62,5 MHZ */ /* We want TX escape clock at around 20MHz and under 20MHz so clock division * is set to 4 */ hdsi->Init.TXEscapeCkdiv = 4; hdsi->Init.NumberOfLanes = DSI_TWO_DATA_LANES; hdsi->Init.PHYFrequencyRange = DSI_DPHY_FRANGE_450MHZ_510MHZ; hdsi->Init.PHYLowPowerOffset = 0; PLLInit.PLLNDIV = 125; PLLInit.PLLIDF = 4; PLLInit.PLLODF = 2; PLLInit.PLLVCORange = DSI_DPHY_VCO_FRANGE_800MHZ_1GHZ; PLLInit.PLLChargePump = DSI_PLL_CHARGE_PUMP_2000HZ_4400HZ; PLLInit.PLLTuning = DSI_PLL_LOOP_FILTER_2000HZ_4400HZ; if (HAL_DSI_Init(hdsi, &PLLInit) != HAL_OK) { return HAL_ERROR; } if (HAL_DSI_SetGenericVCID(&hlcd_dsi, 0) != HAL_OK) { return HAL_ERROR; } /* Configure the DSI for Video mode */ DSIVidCfg.VirtualChannelID = 0; DSIVidCfg.HSPolarity = DSI_HSYNC_ACTIVE_HIGH; DSIVidCfg.VSPolarity = DSI_VSYNC_ACTIVE_HIGH; DSIVidCfg.DEPolarity = DSI_DATA_ENABLE_ACTIVE_HIGH; DSIVidCfg.ColorCoding = DSI_RGB888; DSIVidCfg.Mode = DSI_VID_MODE_BURST; DSIVidCfg.PacketSize = LCD_WIDTH; DSIVidCfg.NullPacketSize = 0xFFFU; DSIVidCfg.HorizontalSyncActive = HSYNC * 3; DSIVidCfg.HorizontalBackPorch = HBP * 3; DSIVidCfg.HorizontalLine = (HACT + HSYNC + HBP + HFP) * 3; DSIVidCfg.VerticalSyncActive = VSYNC; DSIVidCfg.VerticalBackPorch = VBP; DSIVidCfg.VerticalFrontPorch = VFP; DSIVidCfg.VerticalActive = VACT; DSIVidCfg.LPCommandEnable = DSI_LP_COMMAND_ENABLE; DSIVidCfg.LPLargestPacketSize = 64; /* Specify for each region of the video frame, if the transmission of command * in LP mode is allowed in this region */ /* while streaming is active in video mode */ DSIVidCfg.LPHorizontalFrontPorchEnable = DSI_LP_HFP_ENABLE; DSIVidCfg.LPHorizontalBackPorchEnable = DSI_LP_HBP_ENABLE; DSIVidCfg.LPVerticalActiveEnable = DSI_LP_VACT_ENABLE; DSIVidCfg.LPVerticalFrontPorchEnable = DSI_LP_VFP_ENABLE; DSIVidCfg.LPVerticalBackPorchEnable = DSI_LP_VBP_ENABLE; DSIVidCfg.LPVerticalSyncActiveEnable = DSI_LP_VSYNC_ENABLE; DSIVidCfg.FrameBTAAcknowledgeEnable = DSI_FBTAA_ENABLE; DSIVidCfg.LooselyPacked = DSI_LOOSELY_PACKED_DISABLE; /* Drive the display */ if (HAL_DSI_ConfigVideoMode(&hlcd_dsi, &DSIVidCfg) != HAL_OK) { return HAL_ERROR; } return HAL_OK; } /** * @brief MX DMA2D initialization. * @param hdma2d DMA2D handle. * @param Mode DMA2D transfer mode. * @param OffLine DMA2D output offset. * @retval HAL status. */ __weak HAL_StatusTypeDef MX_DMA2D_Init(DMA2D_HandleTypeDef *hdma2d, uint32_t Mode, uint32_t OffLine) { /* Register to memory mode with ARGB8888 as color Mode */ hdma2d->Instance = DMA2D; hdma2d->Init.Mode = Mode; hdma2d->Init.ColorMode = DMA2D_OUTPUT_ARGB8888; hdma2d->Init.OutputOffset = OffLine; hdma2d->Init.AlphaInverted = DMA2D_REGULAR_ALPHA; hdma2d->Init.RedBlueSwap = DMA2D_RB_REGULAR; hdma2d->Init.BytesSwap = DMA2D_BYTES_REGULAR; hdma2d->Init.LineOffsetMode = DMA2D_LOM_PIXELS; /* DMA2D Initialization */ return HAL_DMA2D_Init(hdma2d); } #if (USE_HAL_GFXMMU_REGISTER_CALLBACKS == 1) /** * @brief Register Default LCD GFXMMU Msp Callbacks * @retval BSP status */ int32_t BSP_LCD_GFXMMU_RegisterDefaultMspCallbacks(uint32_t Instance) { int32_t status = BSP_ERROR_NONE; if (Instance >= LCD_INSTANCES_NBR) { status = BSP_ERROR_WRONG_PARAM; } else { __HAL_GFXMMU_RESET_HANDLE_STATE(&hlcd_gfxmmu); /* Register default MspInit/MspDeInit Callback */ if (HAL_GFXMMU_RegisterCallback(&hlcd_gfxmmu, HAL_GFXMMU_MSPINIT_CB_ID, GFXMMU_MspInit) != HAL_OK) { status = BSP_ERROR_PERIPH_FAILURE; } else if (HAL_GFXMMU_RegisterCallback(&hlcd_gfxmmu, HAL_GFXMMU_MSPDEINIT_CB_ID, GFXMMU_MspDeInit) != HAL_OK) { status = BSP_ERROR_PERIPH_FAILURE; } else { LcdGfxmmu_IsMspCbValid[Instance] = 1U; } } /* BSP status */ return status; } /** * @brief Register LCD GFXMMU Msp Callback * @param Callbacks pointer to LCD MspInit/MspDeInit callback functions * @retval BSP status */ int32_t BSP_LCD_GFXMMU_RegisterMspCallbacks(uint32_t Instance, BSP_LCD_GFXMMU_Cb_t *Callback) { int32_t status = BSP_ERROR_NONE; if (Instance >= LCD_INSTANCES_NBR) { status = BSP_ERROR_WRONG_PARAM; } else { __HAL_GFXMMU_RESET_HANDLE_STATE(&hlcd_gfxmmu); /* Register MspInit/MspDeInit Callbacks */ if (HAL_GFXMMU_RegisterCallback(&hlcd_gfxmmu, HAL_GFXMMU_MSPINIT_CB_ID, Callback->pMspGfxmmuInitCb) != HAL_OK) { status = BSP_ERROR_PERIPH_FAILURE; } else if (HAL_GFXMMU_RegisterCallback( &hlcd_gfxmmu, HAL_GFXMMU_MSPDEINIT_CB_ID, Callback->pMspGfxmmuDeInitCb) != HAL_OK) { status = BSP_ERROR_PERIPH_FAILURE; } else { LcdGfxmmu_IsMspCbValid[Instance] = 1U; } } /* BSP status */ return status; } #endif /* USE_HAL_GFXMMU_REGISTER_CALLBACKS */ #if (USE_HAL_LTDC_REGISTER_CALLBACKS == 1) /** * @brief Register Default LCD LTDC Msp Callbacks * @retval BSP status */ int32_t BSP_LCD_LTDC_RegisterDefaultMspCallbacks(uint32_t Instance) { int32_t status = BSP_ERROR_NONE; if (Instance >= LCD_INSTANCES_NBR) { status = BSP_ERROR_WRONG_PARAM; } else { __HAL_LTDC_RESET_HANDLE_STATE(&hlcd_ltdc); /* Register default MspInit/MspDeInit Callback */ if (HAL_LTDC_RegisterCallback(&hlcd_ltdc, HAL_LTDC_MSPINIT_CB_ID, LTDC_MspInit) != HAL_OK) { status = BSP_ERROR_PERIPH_FAILURE; } else if (HAL_LTDC_RegisterCallback(&hlcd_ltdc, HAL_LTDC_MSPDEINIT_CB_ID, LTDC_MspDeInit) != HAL_OK) { status = BSP_ERROR_PERIPH_FAILURE; } else { LcdLtdc_IsMspCbValid[Instance] = 1U; } } /* BSP status */ return status; } /** * @brief Register LCD LTDC Msp Callback * @param Callbacks pointer to LCD MspInit/MspDeInit callback functions * @retval BSP status */ int32_t BSP_LCD_LTDC_RegisterMspCallbacks(uint32_t Instance, BSP_LCD_LTDC_Cb_t *Callback) { int32_t status = BSP_ERROR_NONE; if (Instance >= LCD_INSTANCES_NBR) { status = BSP_ERROR_WRONG_PARAM; } else { __HAL_LTDC_RESET_HANDLE_STATE(&hlcd_ltdc); /* Register MspInit/MspDeInit Callbacks */ if (HAL_LTDC_RegisterCallback(&hlcd_ltdc, HAL_LTDC_MSPINIT_CB_ID, Callback->pMspLtdcInitCb) != HAL_OK) { status = BSP_ERROR_PERIPH_FAILURE; } else if (HAL_LTDC_RegisterCallback(&hlcd_ltdc, HAL_LTDC_MSPDEINIT_CB_ID, Callback->pMspLtdcDeInitCb) != HAL_OK) { status = BSP_ERROR_PERIPH_FAILURE; } else { LcdLtdc_IsMspCbValid[Instance] = 1U; } } /* BSP status */ return status; } #endif /* USE_HAL_LTDC_REGISTER_CALLBACKS */ #if (USE_HAL_DSI_REGISTER_CALLBACKS == 1) /** * @brief Register Default LCD DSI Msp Callbacks * @retval BSP status */ int32_t BSP_LCD_DSI_RegisterDefaultMspCallbacks(uint32_t Instance) { int32_t status = BSP_ERROR_NONE; if (Instance >= LCD_INSTANCES_NBR) { status = BSP_ERROR_WRONG_PARAM; } else { __HAL_DSI_RESET_HANDLE_STATE(&hlcd_dsi); /* Register default MspInit/MspDeInit Callback */ if (HAL_DSI_RegisterCallback(&hlcd_dsi, HAL_DSI_MSPINIT_CB_ID, DSI_MspInit) != HAL_OK) { status = BSP_ERROR_PERIPH_FAILURE; } else if (HAL_DSI_RegisterCallback(&hlcd_dsi, HAL_DSI_MSPDEINIT_CB_ID, DSI_MspDeInit) != HAL_OK) { status = BSP_ERROR_PERIPH_FAILURE; } else { LcdDsi_IsMspCbValid[Instance] = 1U; } } /* BSP status */ return status; } /** * @brief Register LCD DSI Msp Callback * @param Callbacks pointer to LCD MspInit/MspDeInit callback functions * @retval BSP status */ int32_t BSP_LCD_DSI_RegisterMspCallbacks(uint32_t Instance, BSP_LCD_DSI_Cb_t *Callback) { int32_t status = BSP_ERROR_NONE; if (Instance >= LCD_INSTANCES_NBR) { status = BSP_ERROR_WRONG_PARAM; } else { __HAL_DSI_RESET_HANDLE_STATE(&hlcd_dsi); /* Register MspInit/MspDeInit Callbacks */ if (HAL_DSI_RegisterCallback(&hlcd_dsi, HAL_DSI_MSPINIT_CB_ID, Callback->pMspDsiInitCb) != HAL_OK) { status = BSP_ERROR_PERIPH_FAILURE; } else if (HAL_DSI_RegisterCallback(&hlcd_dsi, HAL_DSI_MSPDEINIT_CB_ID, Callback->pMspDsiDeInitCb) != HAL_OK) { status = BSP_ERROR_PERIPH_FAILURE; } else { LcdDsi_IsMspCbValid[Instance] = 1U; } } /* BSP status */ return status; } #endif /* USE_HAL_DSI_REGISTER_CALLBACKS */ #if (USE_HAL_DMA2D_REGISTER_CALLBACKS == 1) /** * @brief Register Default LCD DMA2D Msp Callbacks * @retval BSP status */ int32_t BSP_LCD_DMA2D_RegisterDefaultMspCallbacks(uint32_t Instance) { int32_t status = BSP_ERROR_NONE; if (Instance >= LCD_INSTANCES_NBR) { status = BSP_ERROR_WRONG_PARAM; } else { __HAL_DMA2D_RESET_HANDLE_STATE(&hlcd_dma2d); /* Register default MspInit/MspDeInit Callback */ if (HAL_DMA2D_RegisterCallback(&hlcd_dma2d, HAL_DMA2D_MSPINIT_CB_ID, DMA2D_MspInit) != HAL_OK) { status = BSP_ERROR_PERIPH_FAILURE; } else if (HAL_DMA2D_RegisterCallback(&hlcd_dma2d, HAL_DMA2D_MSPDEINIT_CB_ID, DMA2D_MspDeInit) != HAL_OK) { status = BSP_ERROR_PERIPH_FAILURE; } else { LcdDma2d_IsMspCbValid[Instance] = 1U; } } /* BSP status */ return status; } /** * @brief Register LCD DMA2D Msp Callback * @param Callbacks pointer to LCD MspInit/MspDeInit callback functions * @retval BSP status */ int32_t BSP_LCD_DMA2D_RegisterMspCallbacks(uint32_t Instance, BSP_LCD_DMA2D_Cb_t *Callback) { int32_t status = BSP_ERROR_NONE; if (Instance >= LCD_INSTANCES_NBR) { status = BSP_ERROR_WRONG_PARAM; } else { __HAL_DMA2D_RESET_HANDLE_STATE(&hlcd_dma2d); /* Register MspInit/MspDeInit Callbacks */ if (HAL_DMA2D_RegisterCallback(&hlcd_dma2d, HAL_DMA2D_MSPINIT_CB_ID, Callback->pMspDma2dInitCb) != HAL_OK) { status = BSP_ERROR_PERIPH_FAILURE; } else if (HAL_DMA2D_RegisterCallback( &hlcd_dma2d, HAL_DMA2D_MSPDEINIT_CB_ID, Callback->pMspDma2dDeInitCb) != HAL_OK) { status = BSP_ERROR_PERIPH_FAILURE; } else { LcdDma2d_IsMspCbValid[Instance] = 1U; } } /* BSP status */ return status; } #endif /* USE_HAL_DMA2D_REGISTER_CALLBACKS */ /** * @} */ /** @defgroup STM32U5x9J_DISCOVERY_LCD_Private_Functions LCD Private Functions * @{ */ /** * @brief Initialize LCD. * @retval BSP status. */ static int32_t LCD_Init(void) { int32_t status = BSP_ERROR_NONE; uint32_t ErrorNumber = 0; DSI_PHY_TimerTypeDef PhyTimers = {0}; DSI_HOST_TimeoutTypeDef HostTimeouts = {0}; /***************/ /* GFXMMU init */ /***************/ #if (USE_HAL_GFXMMU_REGISTER_CALLBACKS == 0) GFXMMU_MspInit(&hlcd_gfxmmu); #else /* Register the GFXMMU MSP Callbacks */ if (LcdGfxmmu_IsMspCbValid[0] == 0U) { if (BSP_LCD_GFXMMU_RegisterDefaultMspCallbacks(0) != BSP_ERROR_NONE) { status = BSP_ERROR_PERIPH_FAILURE; } } #endif /* (USE_HAL_GFXMMU_REGISTER_CALLBACKS == 0) */ if (status == BSP_ERROR_NONE) { /* GFXMMU peripheral initialization */ if (MX_GFXMMU_Init(&hlcd_gfxmmu) != HAL_OK) { status = BSP_ERROR_PERIPH_FAILURE; } /* Initialize LUT */ else if (HAL_GFXMMU_ConfigLut(&hlcd_gfxmmu, 0, LCD_WIDTH, (uint32_t)&gfxmmu_lut) != HAL_OK) { status = BSP_ERROR_PERIPH_FAILURE; } else { /* Disable non visible lines : from line 480 to 1023 */ if (HAL_OK != HAL_GFXMMU_DisableLutLines(&hlcd_gfxmmu, LCD_WIDTH, 544)) { status = BSP_ERROR_PERIPH_FAILURE; } } } /************/ /* DSI init */ /************/ if (status == BSP_ERROR_NONE) { #if (USE_HAL_DSI_REGISTER_CALLBACKS == 0) DSI_MspInit(&hlcd_dsi); #else /* Register the DSI MSP Callbacks */ if (LcdDsi_IsMspCbValid[0] == 0U) { if (BSP_LCD_DSI_RegisterDefaultMspCallbacks(0) != BSP_ERROR_NONE) { status = BSP_ERROR_PERIPH_FAILURE; } } #endif /* (USE_HAL_DSI_REGISTER_CALLBACKS == 0) */ if (status == BSP_ERROR_NONE) { /* DSI peripheral initialization */ if (MX_DSI_Init(&hlcd_dsi) != HAL_OK) { status = BSP_ERROR_PERIPH_FAILURE; } } } /*********************/ /* LCD configuration */ /*********************/ if (status == BSP_ERROR_NONE) { PhyTimers.ClockLaneHS2LPTime = 11; PhyTimers.ClockLaneLP2HSTime = 40; PhyTimers.DataLaneHS2LPTime = 12; PhyTimers.DataLaneLP2HSTime = 23; PhyTimers.DataLaneMaxReadTime = 0; PhyTimers.StopWaitTime = 7; if (HAL_DSI_ConfigPhyTimer(&hlcd_dsi, &PhyTimers) != HAL_OK) { return 6; } HostTimeouts.TimeoutCkdiv = 1; HostTimeouts.HighSpeedTransmissionTimeout = 0; HostTimeouts.LowPowerReceptionTimeout = 0; HostTimeouts.HighSpeedReadTimeout = 0; HostTimeouts.LowPowerReadTimeout = 0; HostTimeouts.HighSpeedWriteTimeout = 0; HostTimeouts.HighSpeedWritePrespMode = 0; HostTimeouts.LowPowerWriteTimeout = 0; HostTimeouts.BTATimeout = 0; if (HAL_DSI_ConfigHostTimeouts(&hlcd_dsi, &HostTimeouts) != HAL_OK) { return 7; } if (HAL_DSI_ConfigFlowControl(&hlcd_dsi, DSI_FLOW_CONTROL_BTA) != HAL_OK) { return 7; } /* Enable the DSI host */ __HAL_DSI_ENABLE(&hlcd_dsi); /*************/ /* LTDC init */ /*************/ if (status == BSP_ERROR_NONE) { if (MX_LTDC_ClockConfig(&hlcd_ltdc) != HAL_OK) { status = BSP_ERROR_PERIPH_FAILURE; } else { #if (USE_HAL_LTDC_REGISTER_CALLBACKS == 0) LTDC_MspInit(&hlcd_ltdc); #else /* Register the LTDC MSP Callbacks */ if (LcdLtdc_IsMspCbValid[0] == 0U) { if (BSP_LCD_LTDC_RegisterDefaultMspCallbacks(0) != BSP_ERROR_NONE) { status = BSP_ERROR_PERIPH_FAILURE; } } #endif /* (USE_HAL_GFXMMU_REGISTER_CALLBACKS == 0) */ if (status == BSP_ERROR_NONE) { /* LTDC peripheral initialization */ if (MX_LTDC_Init(&hlcd_ltdc) != HAL_OK) { status = BSP_ERROR_PERIPH_FAILURE; } else { if (MX_LTDC_ConfigLayer(&hlcd_ltdc, LTDC_LAYER_1, GFXMMU_VIRTUAL_BUFFER0_BASE_S) != HAL_OK) { status = BSP_ERROR_PERIPH_FAILURE; } } } } } /* Start DSI */ if (HAL_DSI_Start(&(hlcd_dsi)) != HAL_OK) { return 8; } /* CMD Mode */ uint8_t InitParam1[3] = {0xFF, 0x83, 0x79}; if (HAL_DSI_LongWrite(&hlcd_dsi, 0, DSI_DCS_LONG_PKT_WRITE, 3, 0xB9, InitParam1) != HAL_OK) { ErrorNumber++; } /* SETPOWER */ uint8_t InitParam2[16] = {0x44, 0x1C, 0x1C, 0x37, 0x57, 0x90, 0xD0, 0xE2, 0x58, 0x80, 0x38, 0x38, 0xF8, 0x33, 0x34, 0x42}; if (HAL_DSI_LongWrite(&hlcd_dsi, 0, DSI_DCS_LONG_PKT_WRITE, 16, 0xB1, InitParam2) != HAL_OK) { ErrorNumber++; } /* SETDISP */ uint8_t InitParam3[9] = {0x80, 0x14, 0x0C, 0x30, 0x20, 0x50, 0x11, 0x42, 0x1D}; if (HAL_DSI_LongWrite(&hlcd_dsi, 0, DSI_DCS_LONG_PKT_WRITE, 9, 0xB2, InitParam3) != HAL_OK) { ErrorNumber++; } /* Set display cycle timing */ uint8_t InitParam4[10] = {0x01, 0xAA, 0x01, 0xAF, 0x01, 0xAF, 0x10, 0xEA, 0x1C, 0xEA}; if (HAL_DSI_LongWrite(&hlcd_dsi, 0, DSI_DCS_LONG_PKT_WRITE, 10, 0xB4, InitParam4) != HAL_OK) { ErrorNumber++; } /* SETVCOM */ uint8_t InitParam5[4] = {00, 00, 00, 0xC0}; if (HAL_DSI_LongWrite(&hlcd_dsi, 0, DSI_DCS_LONG_PKT_WRITE, 4, 0xC7, InitParam5) != HAL_OK) { ErrorNumber++; } /* Set Panel Related Registers */ if (HAL_DSI_ShortWrite(&hlcd_dsi, 0, DSI_DCS_SHORT_PKT_WRITE_P1, 0xCC, 0x02) != HAL_OK) { ErrorNumber++; } if (HAL_DSI_ShortWrite(&hlcd_dsi, 0, DSI_DCS_SHORT_PKT_WRITE_P1, 0xD2, 0x77) != HAL_OK) { ErrorNumber++; } uint8_t InitParam6[37] = {0x00, 0x07, 0x00, 0x00, 0x00, 0x08, 0x08, 0x32, 0x10, 0x01, 0x00, 0x01, 0x03, 0x72, 0x03, 0x72, 0x00, 0x08, 0x00, 0x08, 0x33, 0x33, 0x05, 0x05, 0x37, 0x05, 0x05, 0x37, 0x0A, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x01, 0x00, 0x0E}; if (HAL_DSI_LongWrite(&hlcd_dsi, 0, DSI_DCS_LONG_PKT_WRITE, 37, 0xD3, InitParam6) != HAL_OK) { ErrorNumber++; } uint8_t InitParam7[34] = { 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x19, 0x19, 0x18, 0x18, 0x18, 0x18, 0x19, 0x19, 0x01, 0x00, 0x03, 0x02, 0x05, 0x04, 0x07, 0x06, 0x23, 0x22, 0x21, 0x20, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00}; if (HAL_DSI_LongWrite(&hlcd_dsi, 0, DSI_DCS_LONG_PKT_WRITE, 34, 0xD5, InitParam7) != HAL_OK) { ErrorNumber++; } uint8_t InitParam8[32] = {0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x19, 0x19, 0x18, 0x18, 0x19, 0x19, 0x18, 0x18, 0x06, 0x07, 0x04, 0x05, 0x02, 0x03, 0x00, 0x01, 0x20, 0x21, 0x22, 0x23, 0x18, 0x18, 0x18, 0x18}; if (HAL_DSI_LongWrite(&hlcd_dsi, 0, DSI_DCS_LONG_PKT_WRITE, 35, 0xD6, InitParam8) != HAL_OK) { ErrorNumber++; } /* SET GAMMA */ uint8_t InitParam9[42] = { 0x00, 0x16, 0x1B, 0x30, 0x36, 0x3F, 0x24, 0x40, 0x09, 0x0D, 0x0F, 0x18, 0x0E, 0x11, 0x12, 0x11, 0x14, 0x07, 0x12, 0x13, 0x18, 0x00, 0x17, 0x1C, 0x30, 0x36, 0x3F, 0x24, 0x40, 0x09, 0x0C, 0x0F, 0x18, 0x0E, 0x11, 0x14, 0x11, 0x12, 0x07, 0x12, 0x14, 0x18}; if (HAL_DSI_LongWrite(&hlcd_dsi, 0, DSI_DCS_LONG_PKT_WRITE, 42, 0xE0, InitParam9) != HAL_OK) { ErrorNumber++; } uint8_t InitParam10[3] = {0x2C, 0x2C, 00}; if (HAL_DSI_LongWrite(&hlcd_dsi, 0, DSI_DCS_LONG_PKT_WRITE, 3, 0xB6, InitParam10) != HAL_OK) { ErrorNumber++; } if (HAL_DSI_ShortWrite(&hlcd_dsi, 0, DSI_DCS_SHORT_PKT_WRITE_P1, 0xBD, 0x00) != HAL_OK) { ErrorNumber++; } uint8_t InitParam11[] = { 0x01, 0x00, 0x07, 0x0F, 0x16, 0x1F, 0x27, 0x30, 0x38, 0x40, 0x47, 0x4E, 0x56, 0x5D, 0x65, 0x6D, 0x74, 0x7D, 0x84, 0x8A, 0x90, 0x99, 0xA1, 0xA9, 0xB0, 0xB6, 0xBD, 0xC4, 0xCD, 0xD4, 0xDD, 0xE5, 0xEC, 0xF3, 0x36, 0x07, 0x1C, 0xC0, 0x1B, 0x01, 0xF1, 0x34, 0x00}; if (HAL_DSI_LongWrite(&hlcd_dsi, 0, DSI_DCS_LONG_PKT_WRITE, 42, 0xC1, InitParam11) != HAL_OK) { ErrorNumber++; } if (HAL_DSI_ShortWrite(&hlcd_dsi, 0, DSI_DCS_SHORT_PKT_WRITE_P1, 0xBD, 0x01) != HAL_OK) { ErrorNumber++; } uint8_t InitParam12[] = { 0x00, 0x08, 0x0F, 0x16, 0x1F, 0x28, 0x31, 0x39, 0x41, 0x48, 0x51, 0x59, 0x60, 0x68, 0x70, 0x78, 0x7F, 0x87, 0x8D, 0x94, 0x9C, 0xA3, 0xAB, 0xB3, 0xB9, 0xC1, 0xC8, 0xD0, 0xD8, 0xE0, 0xE8, 0xEE, 0xF5, 0x3B, 0x1A, 0xB6, 0xA0, 0x07, 0x45, 0xC5, 0x37, 0x00}; if (HAL_DSI_LongWrite(&hlcd_dsi, 0, DSI_DCS_LONG_PKT_WRITE, 42, 0xC1, InitParam12) != HAL_OK) { ErrorNumber++; } if (HAL_DSI_ShortWrite(&hlcd_dsi, 0, DSI_DCS_SHORT_PKT_WRITE_P1, 0xBD, 0x02) != HAL_OK) { ErrorNumber++; } uint8_t InitParam13[42] = { 0x00, 0x09, 0x0F, 0x18, 0x21, 0x2A, 0x34, 0x3C, 0x45, 0x4C, 0x56, 0x5E, 0x66, 0x6E, 0x76, 0x7E, 0x87, 0x8E, 0x95, 0x9D, 0xA6, 0xAF, 0xB7, 0xBD, 0xC5, 0xCE, 0xD5, 0xDF, 0xE7, 0xEE, 0xF4, 0xFA, 0xFF, 0x0C, 0x31, 0x83, 0x3C, 0x5B, 0x56, 0x1E, 0x5A, 0xFF}; if (HAL_DSI_LongWrite(&hlcd_dsi, 0, DSI_DCS_LONG_PKT_WRITE, 42, 0xC1, InitParam13) != HAL_OK) { ErrorNumber++; } if (HAL_DSI_ShortWrite(&hlcd_dsi, 0, DSI_DCS_SHORT_PKT_WRITE_P1, 0xBD, 0x00) != HAL_OK) { ErrorNumber++; } /* Exit Sleep Mode*/ if (HAL_DSI_ShortWrite(&hlcd_dsi, 0, DSI_DCS_SHORT_PKT_WRITE_P0, 0x11, 0x00) != HAL_OK) { ErrorNumber++; } HAL_Delay(120); /* Display On */ if (HAL_DSI_ShortWrite(&hlcd_dsi, 0, DSI_DCS_SHORT_PKT_WRITE_P0, 0x29, 0x00) != HAL_OK) { ErrorNumber++; } HAL_Delay(120); if (ErrorNumber != 0U) { status = BSP_ERROR_PERIPH_FAILURE; } } return status; } /** * @brief De-Initialize LCD. * @retval BSP status. */ static int32_t LCD_DeInit(void) { int32_t status = BSP_ERROR_NONE; uint32_t ErrorNumber = 0; /* Disable DSI wrapper */ __HAL_DSI_WRAPPER_DISABLE(&hlcd_dsi); /* Set display off */ if (HAL_DSI_ShortWrite(&hlcd_dsi, 0, DSI_DCS_SHORT_PKT_WRITE_P1, DSI_SET_DISPLAY_OFF, 0x00) != HAL_OK) { ErrorNumber++; } /* Wait before entering in sleep mode */ HAL_Delay(2000); /* Put LCD in sleep mode */ if (HAL_DSI_ShortWrite(&hlcd_dsi, 0, DSI_DCS_SHORT_PKT_WRITE_P0, DSI_ENTER_SLEEP_MODE, 0x0) != HAL_OK) { ErrorNumber++; } HAL_Delay(120); /* De-initialize DSI */ if (HAL_DSI_DeInit(&hlcd_dsi) != HAL_OK) { ErrorNumber++; } #if (USE_HAL_DSI_REGISTER_CALLBACKS == 0) DSI_MspDeInit(&hlcd_dsi); #endif /* (USE_HAL_DSI_REGISTER_CALLBACKS == 0) */ /* De-initialize LTDC */ if (HAL_LTDC_DeInit(&hlcd_ltdc) != HAL_OK) { ErrorNumber++; } #if (USE_HAL_LTDC_REGISTER_CALLBACKS == 0) LTDC_MspDeInit(&hlcd_ltdc); #endif /* (USE_HAL_LTDC_REGISTER_CALLBACKS == 0) */ /* De-initialize GFXMMU */ if (HAL_GFXMMU_DeInit(&hlcd_gfxmmu) != HAL_OK) { ErrorNumber++; } #if (USE_HAL_GFXMMU_REGISTER_CALLBACKS == 0) GFXMMU_MspDeInit(&hlcd_gfxmmu); #endif /* (USE_HAL_GFXMMU_REGISTER_CALLBACKS == 0) */ if (ErrorNumber != 0U) { status = BSP_ERROR_PERIPH_FAILURE; } return status; } /** * @brief Initialize GFXMMU MSP. * @param hgfxmmu GFXMMU handle * @retval None */ static void GFXMMU_MspInit(GFXMMU_HandleTypeDef *hgfxmmu) { /* Prevent unused argument(s) compilation warning */ UNUSED(hgfxmmu); /* GFXMMU clock enable */ __HAL_RCC_GFXMMU_CLK_ENABLE(); /* Enable GFXMMU interrupt */ HAL_NVIC_SetPriority(GFXMMU_IRQn, BSP_LCD_GFXMMU_IT_PRIORITY, 0); HAL_NVIC_EnableIRQ(GFXMMU_IRQn); } /** * @brief De-Initialize GFXMMU MSP. * @param hgfxmmu GFXMMU handle * @retval None */ static void GFXMMU_MspDeInit(GFXMMU_HandleTypeDef *hgfxmmu) { /* Prevent unused argument(s) compilation warning */ UNUSED(hgfxmmu); /* Disable GFXMMU interrupt */ HAL_NVIC_DisableIRQ(GFXMMU_IRQn); /* GFXMMU clock disable */ __HAL_RCC_GFXMMU_CLK_DISABLE(); } /** * @brief Initialize LTDC MSP. * @param hltdc LTDC handle * @retval None */ static void LTDC_MspInit(LTDC_HandleTypeDef *hltdc) { /* Prevent unused argument(s) compilation warning */ UNUSED(hltdc); /* Enable LCD clock */ __HAL_RCC_LTDC_CLK_ENABLE(); /* Enable LTDC interrupt */ HAL_NVIC_SetPriority(LTDC_IRQn, BSP_LCD_LTDC_IT_PRIORITY, 0); HAL_NVIC_EnableIRQ(LTDC_IRQn); HAL_NVIC_SetPriority(LTDC_ER_IRQn, BSP_LCD_LTDC_IT_PRIORITY, 0); HAL_NVIC_EnableIRQ(LTDC_ER_IRQn); } /** * @brief De-Initialize LTDC MSP. * @param hltdc LTDC handle * @retval None */ static void LTDC_MspDeInit(LTDC_HandleTypeDef *hltdc) { /* Prevent unused argument(s) compilation warning */ UNUSED(hltdc); /* Disable LTDC interrupts */ HAL_NVIC_DisableIRQ(LTDC_ER_IRQn); HAL_NVIC_DisableIRQ(LTDC_IRQn); /* LTDC clock disable */ __HAL_RCC_LTDC_CLK_DISABLE(); } /** * @brief Initialize DSI MSP. * @param hdsi DSI handle * @retval None */ static void DSI_MspInit(DSI_HandleTypeDef *hdsi) { RCC_PeriphCLKInitTypeDef PLL3InitPeriph = {0}; RCC_PeriphCLKInitTypeDef DSIPHYInitPeriph = {0}; GPIO_InitTypeDef GPIO_InitStruct = {0}; UNUSED(hdsi); /* Enable GPIOI & GPIOD clocks */ __HAL_RCC_GPIOD_CLK_ENABLE(); __HAL_RCC_GPIOI_CLK_ENABLE(); /* Configure DSI Reset pin */ GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; GPIO_InitStruct.Pull = GPIO_PULLDOWN; GPIO_InitStruct.Pin = GPIO_PIN_5; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; HAL_GPIO_Init(GPIOD, &GPIO_InitStruct); /* Configure LCD Backlight Pin */ GPIO_InitStruct.Mode = GPIO_MODE_INPUT; GPIO_InitStruct.Pull = GPIO_PULLUP; GPIO_InitStruct.Pin = GPIO_PIN_6; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; HAL_GPIO_Init(GPIOI, &GPIO_InitStruct); /* Enable DSI clock */ __HAL_RCC_DSI_CLK_ENABLE(); /** ################ Set DSI clock to D-PHY source clock ################## * **/ /* Start and configurre PLL3 */ /* HSE = 16MHZ */ /* 16/(M=4) = 4MHz input (min) */ /* 4*(N=125) = 500MHz VCO (almost max) */ /* 500/(P=8) = 62.5 for DSI ie exactly the lane byte clock*/ PLL3InitPeriph.PeriphClockSelection = RCC_PERIPHCLK_DSI; PLL3InitPeriph.DsiClockSelection = RCC_DSICLKSOURCE_PLL3; PLL3InitPeriph.PLL3.PLL3M = 4; PLL3InitPeriph.PLL3.PLL3N = 125; PLL3InitPeriph.PLL3.PLL3P = 8; PLL3InitPeriph.PLL3.PLL3Q = 8; PLL3InitPeriph.PLL3.PLL3R = 24; PLL3InitPeriph.PLL3.PLL3FRACN = 0; PLL3InitPeriph.PLL3.PLL3RGE = RCC_PLLVCIRANGE_1; PLL3InitPeriph.PLL3.PLL3ClockOut = RCC_PLL3_DIVR | RCC_PLL3_DIVP; PLL3InitPeriph.PLL3.PLL3Source = RCC_PLLSOURCE_HSE; (void)HAL_RCCEx_PeriphCLKConfig(&PLL3InitPeriph); __HAL_RCC_DSI_CLK_ENABLE(); /* Switch to D-PHY source clock */ /* Enable the DSI host */ hlcd_dsi.Instance = DSI; __HAL_DSI_ENABLE(&hlcd_dsi); /* Enable the DSI PLL */ __HAL_DSI_PLL_ENABLE(&hlcd_dsi); HAL_Delay(1); /* Enable the clock lane and the digital section of the D-PHY */ hlcd_dsi.Instance->PCTLR |= (DSI_PCTLR_CKE | DSI_PCTLR_DEN); /* Set the TX escape clock division factor */ hlcd_dsi.Instance->CCR = 4; HAL_Delay(1); /* Config DSI Clock to DSI PHY */ DSIPHYInitPeriph.PeriphClockSelection = RCC_PERIPHCLK_DSI; DSIPHYInitPeriph.DsiClockSelection = RCC_DSICLKSOURCE_DSIPHY; (void)HAL_RCCEx_PeriphCLKConfig(&DSIPHYInitPeriph); /* Reset */ HAL_Delay(11); HAL_GPIO_WritePin(GPIOD, GPIO_PIN_5, GPIO_PIN_SET); HAL_Delay(150); /* Reset the TX escape clock division factor */ hlcd_dsi.Instance->CCR &= ~DSI_CCR_TXECKDIV; /* Disable the DSI PLL */ __HAL_DSI_PLL_DISABLE(&hlcd_dsi); /* Disable the DSI host */ __HAL_DSI_DISABLE(&hlcd_dsi); /** ######################################################################### * **/ /* Enable DSI NVIC interrupt */ /* Default is lowest priority level */ HAL_NVIC_SetPriority(DSI_IRQn, 0x0FUL, 0); HAL_NVIC_EnableIRQ(DSI_IRQn); } /** * @brief De-Initialize DSI MSP. * @param hdsi DSI handle * @retval None */ static void DSI_MspDeInit(DSI_HandleTypeDef *hdsi) { RCC_PeriphCLKInitTypeDef PLL3InitPeriph = {0}; UNUSED(hdsi); /* Switch to PLL3 before Disable */ PLL3InitPeriph.PeriphClockSelection = RCC_PERIPHCLK_DSI; PLL3InitPeriph.DsiClockSelection = RCC_DSICLKSOURCE_PLL3; PLL3InitPeriph.PLL3.PLL3M = 4; PLL3InitPeriph.PLL3.PLL3N = 125; PLL3InitPeriph.PLL3.PLL3P = 8; PLL3InitPeriph.PLL3.PLL3Q = 8; PLL3InitPeriph.PLL3.PLL3R = 24; PLL3InitPeriph.PLL3.PLL3FRACN = 0; PLL3InitPeriph.PLL3.PLL3RGE = RCC_PLLVCIRANGE_1; PLL3InitPeriph.PLL3.PLL3ClockOut = RCC_PLL3_DIVR | RCC_PLL3_DIVP; PLL3InitPeriph.PLL3.PLL3Source = RCC_PLLSOURCE_HSE; (void)HAL_RCCEx_PeriphCLKConfig(&PLL3InitPeriph); /* DSI clock disable */ __HAL_RCC_DSI_CLK_DISABLE(); /** @brief Toggle Sw reset of DSI IP */ __HAL_RCC_DSI_FORCE_RESET(); __HAL_RCC_DSI_RELEASE_RESET(); /* Disable DSI interrupts */ HAL_NVIC_DisableIRQ(DSI_IRQn); } void display_pixeldata(uint16_t c) { uint32_t address = 0; if (act_frame_buffer == 0) { address = GFXMMU_VIRTUAL_BUFFER1_BASE_S; } else { address = GFXMMU_VIRTUAL_BUFFER0_BASE_S; } /* Get the rectangle start address */ address = (address + (4 * ((cursor_y + 120) * PIXEL_PER_LINE + (cursor_x + 120)))); *(__IO uint32_t *)(address) = rgb565_to_rgb888(c) | 0xFF000000; cursor_x++; if (cursor_x > window_x1) { cursor_x = window_x0; cursor_y++; } if (cursor_y > window_y1) { cursor_y = window_y0; } } // this is just for compatibility with DMA2D using algorithms uint8_t *const DISPLAY_DATA_ADDRESS = 0; void display_reset_state() {} void display_set_window(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1) { window_x0 = x0; window_y0 = y0; window_x1 = x1; window_y1 = y1; cursor_x = x0; cursor_y = y0; } uint8_t *display_get_wr_addr(void) { uint32_t address = 0; if (act_frame_buffer == 0) { address = GFXMMU_VIRTUAL_BUFFER1_BASE_S; } else { address = GFXMMU_VIRTUAL_BUFFER0_BASE_S; } /* Get the rectangle start address */ address = (address + (4 * ((cursor_y + 120) * PIXEL_PER_LINE + (cursor_x + 120)))); return (uint8_t *)address; } uint32_t *display_get_fb_addr(void) { uint32_t address = 0; if (act_frame_buffer == 0) { address = GFXMMU_VIRTUAL_BUFFER1_BASE_S; } else { address = GFXMMU_VIRTUAL_BUFFER0_BASE_S; } return (uint32_t *)address; } void display_efficient_clear(void) { if (act_frame_buffer == 0) { memset(PhysFrameBuffer1, 0x00, sizeof(PhysFrameBuffer1)); } else { memset(PhysFrameBuffer0, 0x00, sizeof(PhysFrameBuffer0)); } } uint16_t display_get_window_width(void) { return window_x1 - window_x0 + 1; } uint16_t display_get_window_height(void) { return window_y1 - window_y0 + 1; } void display_shift_window(uint16_t pixels) { uint16_t w = display_get_window_width(); uint16_t h = display_get_window_height(); uint16_t line_rem = w - (cursor_x - window_x0); if (pixels < line_rem) { cursor_x += pixels; return; } // start of next line pixels = pixels - line_rem; cursor_x = window_x0; cursor_y++; // add the rest of pixels cursor_y = window_y0 + (((cursor_y - window_y0) + (pixels / w)) % h); cursor_x += pixels % w; } uint16_t display_get_window_offset(void) { return PIXEL_PER_LINE - display_get_window_width(); } int display_orientation(int degrees) { return degrees; } int display_get_orientation(void) { return 0; } int display_backlight(int val) { return val; } void display_init(void) { RCC_PeriphCLKInitTypeDef PeriphClkInit = {0}; /** Initializes the common periph clock */ PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_LTDC | RCC_PERIPHCLK_DSI; PeriphClkInit.DsiClockSelection = RCC_DSICLKSOURCE_PLL3; PeriphClkInit.LtdcClockSelection = RCC_LTDCCLKSOURCE_PLL3; PeriphClkInit.PLL3.PLL3Source = RCC_PLLSOURCE_HSE; PeriphClkInit.PLL3.PLL3M = 4; PeriphClkInit.PLL3.PLL3N = 125; PeriphClkInit.PLL3.PLL3P = 8; PeriphClkInit.PLL3.PLL3Q = 2; PeriphClkInit.PLL3.PLL3R = 24; PeriphClkInit.PLL3.PLL3RGE = RCC_PLLVCIRANGE_0; PeriphClkInit.PLL3.PLL3FRACN = 0; PeriphClkInit.PLL3.PLL3ClockOut = RCC_PLL3_DIVP | RCC_PLL3_DIVR; HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit); memset(PhysFrameBuffer0, 0x00, sizeof(PhysFrameBuffer0)); memset(PhysFrameBuffer1, 0x00, sizeof(PhysFrameBuffer1)); memcpy(gfxmmu_lut, gfxmmu_lut_config_argb8888, sizeof(gfxmmu_lut_config_argb8888)); BSP_LCD_Init(0, LCD_ORIENTATION_PORTRAIT); BSP_LCD_SetBrightness(0, 100); BSP_LCD_SetActiveLayer(0, 0); BSP_LCD_DisplayOn(0); } void display_reinit(void) { memcpy(gfxmmu_lut, gfxmmu_lut_config_argb8888, sizeof(gfxmmu_lut_config_argb8888)); /* Switch to D-PHY source clock */ /* Enable the DSI host */ hlcd_dsi.Instance = DSI; MX_GFXMMU_Reinit(&hlcd_gfxmmu); MX_DSI_Reinit(&hlcd_dsi); MX_LTDC_Reinit(&hlcd_ltdc); if (act_frame_buffer == 0) { MX_LTDC_ConfigLayer(&hlcd_ltdc, 0, GFXMMU_VIRTUAL_BUFFER0_BASE_S); } else { MX_LTDC_ConfigLayer(&hlcd_ltdc, 0, GFXMMU_VIRTUAL_BUFFER1_BASE_S); } } void display_sync(void) {} void display_refresh(void) { if (act_frame_buffer == 0) { act_frame_buffer = 1; MX_LTDC_ConfigLayer(&hlcd_ltdc, 0, GFXMMU_VIRTUAL_BUFFER1_BASE_S); memcpy(PhysFrameBuffer0, PhysFrameBuffer1, sizeof(PhysFrameBuffer1)); } else { act_frame_buffer = 0; MX_LTDC_ConfigLayer(&hlcd_ltdc, 0, GFXMMU_VIRTUAL_BUFFER0_BASE_S); memcpy(PhysFrameBuffer1, PhysFrameBuffer0, sizeof(PhysFrameBuffer1)); } } const char *display_save(const char *prefix) { return NULL; } void display_clear_save(void) {} void display_pixeldata_dirty(void) {}