[STM32F4] 【STM32F469I试用】LCD简单测试之“弹幕”

[复制链接]
 楼主| hwl1023 发表于 2015-12-22 22:19 | 显示全部楼层 |阅读模式
       STM32F469有个分辨率很高的4寸屏幕,无论显示图片还是字体都很清晰细腻,下面的测试就模仿大家经常见到的“弹幕”效果进行测试。:lol
板载的LCD是使用MIPI接口(DSI)来实现的,配合LTDC和DMA2D使用更加功能强大。LCD驱动部分总的结构框图如下:
1.png
DSI接口配置较为复杂,还好的是ST给出了参考的配置过程,分别初始化SDRAM,DSI,LTDC这些接口即可,使用时直接写SDRAM用来更新显示。除此之外也可以使用CubeMX配置更加简单方便。
主要的LCD初始化代码如下:
  1. uint8_t BSP_LCD_InitEx(LCD_OrientationTypeDef orientation)
  2. {
  3.   DSI_PLLInitTypeDef dsiPllInit;
  4.   static RCC_PeriphCLKInitTypeDef  PeriphClkInitStruct;
  5.   uint32_t LcdClock  = 27429; /*!< LcdClk = 27429 kHz */
  6.   uint32_t Clockratio  = 0;
  7.   uint32_t laneByteClk_kHz = 0;
  8.   uint32_t                   VSA; /*!< Vertical start active time in units of lines */
  9.   uint32_t                   VBP; /*!< Vertical Back Porch time in units of lines */
  10.   uint32_t                   VFP; /*!< Vertical Front Porch time in units of lines */
  11.   uint32_t                   VACT; /*!< Vertical Active time in units of lines = imageSize Y in pixels to display */
  12.   uint32_t                   HSA; /*!< Horizontal start active time in units of lcdClk */
  13.   uint32_t                   HBP; /*!< Horizontal Back Porch time in units of lcdClk */
  14.   uint32_t                   HFP; /*!< Horizontal Front Porch time in units of lcdClk */
  15.   uint32_t                   HACT; /*!< Horizontal Active time in units of lcdClk = imageSize X in pixels to display */
  16.   
  17.   
  18.   /* Toggle Hardware Reset of the DSI LCD using
  19.   * its XRES signal (active low) */
  20.   BSP_LCD_Reset();
  21.   
  22.   /* Call first MSP Initialize only in case of first initialization
  23.   * This will set IP blocks LTDC, DSI and DMA2D
  24.   * - out of reset
  25.   * - clocked
  26.   * - NVIC IRQ related to IP blocks enabled
  27.   */
  28.   BSP_LCD_MspInit();
  29.   
  30. /*************************DSI Initialization***********************************/  
  31.   
  32.   /* Base address of DSI Host/Wrapper registers to be set before calling De-Init */
  33.   hdsi_eval.Instance = DSI;
  34.   
  35.   HAL_DSI_DeInit(&(hdsi_eval));
  36.   
  37. #if !defined(USE_STM32469I_DISCO_REVA)
  38.   dsiPllInit.PLLNDIV  = 125;
  39.   dsiPllInit.PLLIDF   = DSI_PLL_IN_DIV2;
  40.   dsiPllInit.PLLODF   = DSI_PLL_OUT_DIV1;
  41. #else  
  42.   dsiPllInit.PLLNDIV  = 100;
  43.   dsiPllInit.PLLIDF   = DSI_PLL_IN_DIV5;
  44.   dsiPllInit.PLLODF   = DSI_PLL_OUT_DIV1;
  45. #endif
  46.   laneByteClk_kHz = 62500; /* 500 MHz / 8 = 62.5 MHz = 62500 kHz */
  47.   
  48.   /* Set number of Lanes */
  49.   hdsi_eval.Init.NumberOfLanes = DSI_TWO_DATA_LANES;
  50.   
  51.   /* TXEscapeCkdiv = f(LaneByteClk)/15.62 = 4 */
  52.   hdsi_eval.Init.TXEscapeCkdiv = laneByteClk_kHz/15620;
  53.   
  54.   HAL_DSI_Init(&(hdsi_eval), &(dsiPllInit));
  55.   Clockratio = laneByteClk_kHz/LcdClock;
  56.   /* Timing parameters for all Video modes
  57.   * Set Timing parameters of LTDC depending on its chosen orientation
  58.   */
  59.   if(orientation == LCD_ORIENTATION_PORTRAIT)
  60.   {
  61.     VSA  = OTM8009A_480X800_VSYNC;        /* 12 */
  62.     VBP  = OTM8009A_480X800_VBP;          /* 12 */
  63.     VFP  = OTM8009A_480X800_VFP;          /* 12 */
  64.     HSA  = OTM8009A_480X800_HSYNC;        /* 120 */
  65.     HBP  = OTM8009A_480X800_HBP;          /* 120 */
  66.     HFP  = OTM8009A_480X800_HFP;          /* 120 */
  67.     lcd_x_size = OTM8009A_480X800_WIDTH;  /* 480 */
  68.     lcd_y_size = OTM8009A_480X800_HEIGHT; /* 800 */                                
  69.   }
  70.   else
  71.   {
  72.     /* lcd_orientation == LCD_ORIENTATION_LANDSCAPE */
  73.     VSA  = OTM8009A_800X480_VSYNC;        /* 12 */
  74.     VBP  = OTM8009A_800X480_VBP;          /* 12 */
  75.     VFP  = OTM8009A_800X480_VFP;          /* 12 */
  76.     HSA  = OTM8009A_800X480_HSYNC;        /* 120 */
  77.     HBP  = OTM8009A_800X480_HBP;          /* 120 */
  78.     HFP  = OTM8009A_800X480_HFP;          /* 120 */
  79.     lcd_x_size = OTM8009A_800X480_WIDTH;  /* 800 */
  80.     lcd_y_size = OTM8009A_800X480_HEIGHT; /* 480 */                                
  81.   }  
  82.   
  83.   HACT = lcd_x_size;
  84.   VACT = lcd_y_size;
  85.   
  86.   
  87.   hdsivideo_handle.VirtualChannelID = LCD_OTM8009A_ID;
  88.   hdsivideo_handle.ColorCoding = LCD_DSI_PIXEL_DATA_FMT_RBG888;
  89.   hdsivideo_handle.VSPolarity = DSI_VSYNC_ACTIVE_HIGH;
  90.   hdsivideo_handle.HSPolarity = DSI_HSYNC_ACTIVE_HIGH;
  91.   hdsivideo_handle.DEPolarity = DSI_DATA_ENABLE_ACTIVE_HIGH;  
  92.   hdsivideo_handle.Mode = DSI_VID_MODE_BURST; /* Mode Video burst ie : one LgP per line */
  93.   hdsivideo_handle.NullPacketSize = 0xFFF;
  94.   hdsivideo_handle.NumberOfChunks = 0;
  95.   hdsivideo_handle.PacketSize                = HACT; /* Value depending on display orientation choice portrait/landscape */
  96.   hdsivideo_handle.HorizontalSyncActive      = HSA*Clockratio;
  97.   hdsivideo_handle.HorizontalBackPorch       = HBP*Clockratio;
  98.   hdsivideo_handle.HorizontalLine            = (HACT + HSA + HBP + HFP)*Clockratio; /* Value depending on display orientation choice portrait/landscape */
  99.   hdsivideo_handle.VerticalSyncActive        = VSA;
  100.   hdsivideo_handle.VerticalBackPorch         = VBP;
  101.   hdsivideo_handle.VerticalFrontPorch        = VFP;
  102.   hdsivideo_handle.VerticalActive            = VACT; /* Value depending on display orientation choice portrait/landscape */
  103.   
  104.   /* Enable or disable sending LP command while streaming is active in video mode */
  105.   hdsivideo_handle.LPCommandEnable = DSI_LP_COMMAND_ENABLE; /* Enable sending commands in mode LP (Low Power) */
  106.   
  107.   /* Largest packet size possible to transmit in LP mode in VSA, VBP, VFP regions */
  108.   /* Only useful when sending LP packets is allowed while streaming is active in video mode */
  109.   hdsivideo_handle.LPLargestPacketSize = 64;
  110.   
  111.   /* Largest packet size possible to transmit in LP mode in HFP region during VACT period */
  112.   /* Only useful when sending LP packets is allowed while streaming is active in video mode */
  113.   hdsivideo_handle.LPVACTLargestPacketSize = 64;
  114.   
  115.   
  116.   /* Specify for each region of the video frame, if the transmission of command in LP mode is allowed in this region */
  117.   /* while streaming is active in video mode                                                                         */
  118.   hdsivideo_handle.LPHorizontalFrontPorchEnable = DSI_LP_HFP_ENABLE;   /* Allow sending LP commands during HFP period */
  119.   hdsivideo_handle.LPHorizontalBackPorchEnable  = DSI_LP_HBP_ENABLE;   /* Allow sending LP commands during HBP period */
  120.   hdsivideo_handle.LPVerticalActiveEnable = DSI_LP_VACT_ENABLE;  /* Allow sending LP commands during VACT period */
  121.   hdsivideo_handle.LPVerticalFrontPorchEnable = DSI_LP_VFP_ENABLE;   /* Allow sending LP commands during VFP period */
  122.   hdsivideo_handle.LPVerticalBackPorchEnable = DSI_LP_VBP_ENABLE;   /* Allow sending LP commands during VBP period */
  123.   hdsivideo_handle.LPVerticalSyncActiveEnable = DSI_LP_VSYNC_ENABLE; /* Allow sending LP commands during VSync = VSA period */
  124.   
  125.   /* Configure DSI Video mode timings with settings set above */
  126.   HAL_DSI_ConfigVideoMode(&(hdsi_eval), &(hdsivideo_handle));
  127.   /* Enable the DSI host and wrapper : but LTDC is not started yet at this stage */
  128.   HAL_DSI_Start(&(hdsi_eval));
  129. /*************************End DSI Initialization*******************************/
  130.   
  131.   
  132. /************************LTDC Initialization***********************************/  
  133.   
  134.   /* Timing Configuration */   
  135.   hltdc_eval.Init.HorizontalSync = (HSA - 1);
  136.   hltdc_eval.Init.AccumulatedHBP = (HSA + HBP - 1);
  137.   hltdc_eval.Init.AccumulatedActiveW = (lcd_x_size + HSA + HBP - 1);
  138.   hltdc_eval.Init.TotalWidth = (lcd_x_size + HSA + HBP + HFP - 1);
  139.   
  140.   /* Initialize the LCD pixel width and pixel height */
  141.   hltdc_eval.LayerCfg->ImageWidth  = lcd_x_size;
  142.   hltdc_eval.LayerCfg->ImageHeight = lcd_y_size;   
  143.   
  144.   
  145.   /* LCD clock configuration */
  146.   /* PLLSAI_VCO Input = HSE_VALUE/PLL_M = 1 Mhz */
  147.   /* PLLSAI_VCO Output = PLLSAI_VCO Input * PLLSAIN = 384 Mhz */
  148.   /* PLLLCDCLK = PLLSAI_VCO Output/PLLSAIR = 384 MHz / 7 = 54.857 MHz */
  149.   /* LTDC clock frequency = PLLLCDCLK / LTDC_PLLSAI_DIVR_2 = 54.857 MHz / 2 = 27.429 MHz */
  150.   PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_LTDC;
  151.   PeriphClkInitStruct.PLLSAI.PLLSAIN = 384;
  152.   PeriphClkInitStruct.PLLSAI.PLLSAIR = 7;
  153.   PeriphClkInitStruct.PLLSAIDivR = RCC_PLLSAIDIVR_2;
  154.   HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct);
  155.   
  156.   /* Background value */
  157.   hltdc_eval.Init.Backcolor.Blue = 0;
  158.   hltdc_eval.Init.Backcolor.Green = 0;
  159.   hltdc_eval.Init.Backcolor.Red = 0;
  160.   hltdc_eval.Init.PCPolarity = LTDC_PCPOLARITY_IPC;
  161.   hltdc_eval.Instance = LTDC;
  162.   
  163.   /* Get LTDC Configuration from DSI Configuration */
  164.   HAL_LTDC_StructInitFromVideoConfig(&(hltdc_eval), &(hdsivideo_handle));
  165.   
  166.   /* Initialize the LTDC */  
  167.   HAL_LTDC_Init(&hltdc_eval);
  168.   
  169. #if !defined(DATA_IN_ExtSDRAM)
  170.   /* Initialize the SDRAM */
  171.   BSP_SDRAM_Init();
  172. #endif /* DATA_IN_ExtSDRAM */
  173.   
  174.   /* Initialize the font */
  175.   BSP_LCD_SetFont(&LCD_DEFAULT_FONT);
  176.   
  177. /************************End LTDC Initialization*******************************/
  178.   
  179.   
  180. /***********************OTM8009A Initialization********************************/  
  181.   
  182.   /* Initialize the OTM8009A LCD Display IC Driver (KoD LCD IC Driver)
  183.   *  depending on configuration set in 'hdsivideo_handle'.
  184.   */
  185.   OTM8009A_Init(hdsivideo_handle.ColorCoding, orientation);
  186.   
  187. /***********************End OTM8009A Initialization****************************/

  188.        
  189.   return LCD_OK;
  190. }
然后实现一个简单的字符串滚动函数:
  1. unsigned int Colorbuff[] = {LCD_COLOR_BLUE,LCD_COLOR_GREEN,LCD_COLOR_RED,LCD_COLOR_CYAN,\
  2. LCD_COLOR_MAGENTA,LCD_COLOR_YELLOW,LCD_COLOR_LIGHTBLUE,LCD_COLOR_DARKBLUE,LCD_COLOR_ORANGE,\
  3. LCD_COLOR_ORANGE,LCD_COLOR_WHITE,LCD_COLOR_RED,LCD_COLOR_BLUE,LCD_COLOR_GREEN};

  4. //滚动显示一个字符串
  5. void BSP_LCD_SlideShow(uint16_t x,uint16_t y,uint16_t num)
  6. {       
  7.         BSP_LCD_ShowStr(x,y,LCD_COLOR_BLACK,LCD_COLOR_BLACK,TextBuff[num],0);
  8.         BSP_LCD_ShowStr(x+1,y,Colorbuff[num],LCD_COLOR_BLACK,TextBuff[num],0);
  9. }
最后就是在main函数中来滚动显示想要显示的字符串了:
  1. int main(void)
  2. {
  3.         uint8_t LedSta = LED_ON;
  4.         uint16_t x0,t;
  5.         HAL_Init();
  6.         SystemClock_Config();
  7.         LED_Init();
  8.         BSP_LCD_Init();
  9.         BSP_LCD_Layer();       
  10.         while(1)
  11.         {
  12.                 for(x0 = 0;x0 < 800;x0++)
  13.                 {
  14.                                 for(t = 0;t < 14;t++)
  15.                                 {
  16.                                         BSP_LCD_SlideShow(x0,10 + 30*t,t);
  17.                                 }
  18.                                 GREEN_STA(LedSta);ORANGE_STA(LedSta);RED_STA(LedSta);BLUE_STA(LedSta);
  19.                                 LedSta = !LedSta;
  20.                 }
  21.         }
  22. }
效果大概如下:
2.png
3.png
11.png
总体来说显示滚动还很流畅,但是可能是优化不是很好,有的字符串有轻微的闪烁。通过简单的“弹幕”测试,可以发现虽然整个LCD显示配置过程比较复杂,但是一旦配置就可以较为简单的使用,而且显示效果也较为理想。

绝影 发表于 2015-12-22 22:56 | 显示全部楼层
楼主有没有试过 竖屏显示?我试试了好像不行。
 楼主| hwl1023 发表于 2015-12-22 23:31 | 显示全部楼层
本帖最后由 hwl1023 于 2015-12-23 10:25 编辑
绝影 发表于 2015-12-22 22:56
楼主有没有试过 竖屏显示?我试试了好像不行。
没有试过,有空测试下竖屏显示。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

9

主题

158

帖子

6

粉丝
快速回复 在线客服 返回列表 返回顶部

9

主题

158

帖子

6

粉丝
快速回复 在线客服 返回列表 返回顶部