查看: 3509|回复: 0

44..STM32F469I---LCD简单测试之“弹幕”

[复制链接]
  • TA的每日心情
    难过
    2021-2-27 22:16
  • 签到天数: 1568 天

    连续签到: 1 天

    [LV.Master]伴坛终老

    发表于 2018-1-12 22:54:53 | 显示全部楼层 |阅读模式
    分享到:
    【STM32F469I试用】LCD简单测试之“弹幕”【转】

    STM32F469有个分辨率很高的4寸屏幕,无论显示图片还是字体都很清晰细腻,下面的测试就模仿大家经常见到的“弹幕”效果进行测试。
    板载的LCD是使用MIPI接口(DSI)来实现的,配合LTDC和DMA2D使用更加功能强大。LCD驱动部分总的结构框图如下:

    1.jpg

    DSI接口配置较为复杂,还好的是ST给出了参考的配置过程,分别初始化SDRAM,DSI,LTDC这些接口即可,使用时直接写SDRAM用来更新显示。除此之外也可以使用CubeMX配置更加简单方便。
    主要的LCD初始化代码如下:
    uint8_t BSP_LCD_InitEx(LCD_OrientationTypeDef orientation)
    {
      DSI_PLLInitTypeDef dsiPllInit;
      static RCC_PeriphCLKInitTypeDef  PeriphClkInitStruct;
      uint32_t LcdClock  = 27429; /*!< LcdClk = 27429 kHz */
      uint32_t Clockratio  = 0;
      uint32_t laneByteClk_kHz = 0;
      uint32_t                   VSA; /*!< Vertical start active time in units of lines */
      uint32_t                   VBP; /*!< Vertical Back Porch time in units of lines */
      uint32_t                   VFP; /*!< Vertical Front Porch time in units of lines */
      uint32_t                   VACT; /*!< Vertical Active time in units of lines = imageSize Y in pixels to display */
      uint32_t                   HSA; /*!< Horizontal start active time in units of lcdClk */
      uint32_t                   HBP; /*!< Horizontal Back Porch time in units of lcdClk */
      uint32_t                   HFP; /*!< Horizontal Front Porch time in units of lcdClk */
      uint32_t                   HACT; /*!< Horizontal Active time in units of lcdClk = imageSize X in pixels to display */


      /* Toggle Hardware Reset of the DSI LCD using
      * its XRES signal (active low) */
      BSP_LCD_Reset();

      /* Call first MSP Initialize only in case of first initialization
      * This will set IP blocks LTDC, DSI and DMA2D
      * - out of reset
      * - clocked
      * - NVIC IRQ related to IP blocks enabled
      */
      BSP_LCD_MspInit();

    /*************************DSI Initialization***********************************/  

      /* Base address of DSI Host/Wrapper registers to be set before calling De-Init */
      hdsi_eval.Instance = DSI;

      HAL_DSI_DeInit(&(hdsi_eval));

    #if !defined(USE_STM32469I_DISCO_REVA)
      dsiPllInit.PLLNDIV  = 125;
      dsiPllInit.PLLIDF   = DSI_PLL_IN_DIV2;
      dsiPllInit.PLLODF   = DSI_PLL_OUT_DIV1;
    #else  
      dsiPllInit.PLLNDIV  = 100;
      dsiPllInit.PLLIDF   = DSI_PLL_IN_DIV5;
      dsiPllInit.PLLODF   = DSI_PLL_OUT_DIV1;
    #endif
      laneByteClk_kHz = 62500; /* 500 MHz / 8 = 62.5 MHz = 62500 kHz */

      /* Set number of Lanes */
      hdsi_eval.Init.NumberOfLanes = DSI_TWO_DATA_LANES;

      /* TXEscapeCkdiv = f(LaneByteClk)/15.62 = 4 */
      hdsi_eval.Init.TXEscapeCkdiv = laneByteClk_kHz/15620;

      HAL_DSI_Init(&(hdsi_eval), &(dsiPllInit));
      Clockratio = laneByteClk_kHz/LcdClock;
      /* Timing parameters for all Video modes
      * Set Timing parameters of LTDC depending on its chosen orientation
      */
      if(orientation == LCD_ORIENTATION_PORTRAIT)
      {
        VSA  = OTM8009A_480X800_VSYNC;        /* 12 */
        VBP  = OTM8009A_480X800_VBP;          /* 12 */
        VFP  = OTM8009A_480X800_VFP;          /* 12 */
        HSA  = OTM8009A_480X800_HSYNC;        /* 120 */
        HBP  = OTM8009A_480X800_HBP;          /* 120 */
        HFP  = OTM8009A_480X800_HFP;          /* 120 */
        lcd_x_size = OTM8009A_480X800_WIDTH;  /* 480 */
        lcd_y_size = OTM8009A_480X800_HEIGHT; /* 800 */                                
      }
      else
      {
        /* lcd_orientation == LCD_ORIENTATION_LANDSCAPE */
        VSA  = OTM8009A_800X480_VSYNC;        /* 12 */
        VBP  = OTM8009A_800X480_VBP;          /* 12 */
        VFP  = OTM8009A_800X480_VFP;          /* 12 */
        HSA  = OTM8009A_800X480_HSYNC;        /* 120 */
        HBP  = OTM8009A_800X480_HBP;          /* 120 */
        HFP  = OTM8009A_800X480_HFP;          /* 120 */
        lcd_x_size = OTM8009A_800X480_WIDTH;  /* 800 */
        lcd_y_size = OTM8009A_800X480_HEIGHT; /* 480 */                                
      }  

      HACT = lcd_x_size;
      VACT = lcd_y_size;


      hdsivideo_handle.VirtualChannelID = LCD_OTM8009A_ID;
      hdsivideo_handle.ColorCoding = LCD_DSI_PIXEL_DATA_FMT_RBG888;
      hdsivideo_handle.VSPolarity = DSI_VSYNC_ACTIVE_HIGH;
      hdsivideo_handle.HSPolarity = DSI_HSYNC_ACTIVE_HIGH;
      hdsivideo_handle.DEPolarity = DSI_DATA_ENABLE_ACTIVE_HIGH;  
      hdsivideo_handle.Mode = DSI_VID_MODE_BURST; /* Mode Video burst ie : one LgP per line */
      hdsivideo_handle.NullPacketSize = 0xFFF;
      hdsivideo_handle.NumberOfChunks = 0;
      hdsivideo_handle.PacketSize                = HACT; /* Value depending on display orientation choice portrait/landscape */
      hdsivideo_handle.HorizontalSyncActive      = HSA*Clockratio;
      hdsivideo_handle.HorizontalBackPorch       = HBP*Clockratio;
      hdsivideo_handle.HorizontalLine            = (HACT + HSA + HBP + HFP)*Clockratio; /* Value depending on display orientation choice portrait/landscape */
      hdsivideo_handle.VerticalSyncActive        = VSA;
      hdsivideo_handle.VerticalBackPorch         = VBP;
      hdsivideo_handle.VerticalFrontPorch        = VFP;
      hdsivideo_handle.VerticalActive            = VACT; /* Value depending on display orientation choice portrait/landscape */

      /* Enable or disable sending LP command while streaming is active in video mode */
      hdsivideo_handle.LPCommandEnable = DSI_LP_COMMAND_ENABLE; /* Enable sending commands in mode LP (Low Power) */

      /* Largest packet size possible to transmit in LP mode in VSA, VBP, VFP regions */
      /* Only useful when sending LP packets is allowed while streaming is active in video mode */
      hdsivideo_handle.LPLargestPacketSize = 64;

      /* Largest packet size possible to transmit in LP mode in HFP region during VACT period */
      /* Only useful when sending LP packets is allowed while streaming is active in video mode */
      hdsivideo_handle.LPVACTLargestPacketSize = 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                                                                         */
      hdsivideo_handle.LPHorizontalFrontPorchEnable = DSI_LP_HFP_ENABLE;   /* Allow sending LP commands during HFP period */
      hdsivideo_handle.LPHorizontalBackPorchEnable  = DSI_LP_HBP_ENABLE;   /* Allow sending LP commands during HBP period */
      hdsivideo_handle.LPVerticalActiveEnable = DSI_LP_VACT_ENABLE;  /* Allow sending LP commands during VACT period */
      hdsivideo_handle.LPVerticalFrontPorchEnable = DSI_LP_VFP_ENABLE;   /* Allow sending LP commands during VFP period */
      hdsivideo_handle.LPVerticalBackPorchEnable = DSI_LP_VBP_ENABLE;   /* Allow sending LP commands during VBP period */
      hdsivideo_handle.LPVerticalSyncActiveEnable = DSI_LP_VSYNC_ENABLE; /* Allow sending LP commands during VSync = VSA period */

      /* Configure DSI Video mode timings with settings set above */
      HAL_DSI_ConfigVideoMode(&(hdsi_eval), &(hdsivideo_handle));
      /* Enable the DSI host and wrapper : but LTDC is not started yet at this stage */
      HAL_DSI_Start(&(hdsi_eval));
    /*************************End DSI Initialization*******************************/


    /************************LTDC Initialization***********************************/  

      /* Timing Configuration */   
      hltdc_eval.Init.HorizontalSync = (HSA - 1);
      hltdc_eval.Init.AccumulatedHBP = (HSA + HBP - 1);
      hltdc_eval.Init.AccumulatedActiveW = (lcd_x_size + HSA + HBP - 1);
      hltdc_eval.Init.TotalWidth = (lcd_x_size + HSA + HBP + HFP - 1);

      /* Initialize the LCD pixel width and pixel height */
      hltdc_eval.LayerCfg->ImageWidth  = lcd_x_size;
      hltdc_eval.LayerCfg->ImageHeight = lcd_y_size;   


      /* LCD clock configuration */
      /* PLLSAI_VCO Input = HSE_VALUE/PLL_M = 1 Mhz */
      /* PLLSAI_VCO Output = PLLSAI_VCO Input * PLLSAIN = 384 Mhz */
      /* PLLLCDCLK = PLLSAI_VCO Output/PLLSAIR = 384 MHz / 7 = 54.857 MHz */
      /* LTDC clock frequency = PLLLCDCLK / LTDC_PLLSAI_DIVR_2 = 54.857 MHz / 2 = 27.429 MHz */
      PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_LTDC;
      PeriphClkInitStruct.PLLSAI.PLLSAIN = 384;
      PeriphClkInitStruct.PLLSAI.PLLSAIR = 7;
      PeriphClkInitStruct.PLLSAIDivR = RCC_PLLSAIDIVR_2;
      HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct);

      /* Background value */
      hltdc_eval.Init.Backcolor.Blue = 0;
      hltdc_eval.Init.Backcolor.Green = 0;
      hltdc_eval.Init.Backcolor.Red = 0;
      hltdc_eval.Init.PCPolarity = LTDC_PCPOLARITY_IPC;
      hltdc_eval.Instance = LTDC;

      /* Get LTDC Configuration from DSI Configuration */
      HAL_LTDC_StructInitFromVideoConfig(&(hltdc_eval), &(hdsivideo_handle));

      /* Initialize the LTDC */  
      HAL_LTDC_Init(&hltdc_eval);

    #if !defined(DATA_IN_ExtSDRAM)
      /* Initialize the SDRAM */
      BSP_SDRAM_Init();
    #endif /* DATA_IN_ExtSDRAM */

      /* Initialize the font */
      BSP_LCD_SetFont(&LCD_DEFAULT_FONT);

    /************************End LTDC Initialization*******************************/


    /***********************OTM8009A Initialization********************************/  

      /* Initialize the OTM8009A LCD Display IC Driver (KoD LCD IC Driver)
      *  depending on configuration set in 'hdsivideo_handle'.
      */
      OTM8009A_Init(hdsivideo_handle.ColorCoding, orientation);

    /***********************End OTM8009A Initialization****************************/


      return LCD_OK;
    }

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

    //滚动显示一个字符串
    void BSP_LCD_SlideShow(uint16_t x,uint16_t y,uint16_t num)
    {        
            BSP_LCD_ShowStr(x,y,LCD_COLOR_BLACK,LCD_COLOR_BLACK,TextBuff[num],0);
            BSP_LCD_ShowStr(x+1,y,Colorbuff[num],LCD_COLOR_BLACK,TextBuff[num],0);
    }

    最后就是在main函数中来滚动显示想要显示的字符串了:
    int main(void)
    {
            uint8_t LedSta = LED_ON;
            uint16_t x0,t;
            HAL_Init();
            SystemClock_Config();
            LED_Init();
            BSP_LCD_Init();
            BSP_LCD_Layer();        
            while(1)
            {
                    for(x0 = 0;x0 < 800;x0++)
                    {
                                    for(t = 0;t < 14;t++)
                                    {
                                            BSP_LCD_SlideShow(x0,10 + 30*t,t);
                                    }
                                    GREEN_STA(LedSta);ORANGE_STA(LedSta);RED_STA(LedSta);BLUE_STA(LedSta);
                                    LedSta = !LedSta;
                    }
            }
    }

    效果大概如下:

    2.jpg

    3.jpg

    4.jpg

    总体来说显示滚动还很流畅,但是可能是优化不是很好,有的字符串有轻微的闪烁。通过简单的“弹幕”测试,可以发现虽然整个LCD显示配置过程比较复杂,但是一旦配置就可以较为简单的使用,而且显示效果也较为理想。

    回复

    使用道具 举报

    您需要登录后才可以回帖 注册/登录

    本版积分规则

    关闭

    站长推荐上一条 /2 下一条



    手机版|小黑屋|与非网

    GMT+8, 2024-4-20 10:19 , Processed in 0.110830 second(s), 15 queries , MemCache On.

    ICP经营许可证 苏B2-20140176  苏ICP备14012660号-2   苏州灵动帧格网络科技有限公司 版权所有.

    苏公网安备 32059002001037号

    Powered by Discuz! X3.4

    Copyright © 2001-2020, Tencent Cloud.