你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

查看: 5227|回复: 21

[STM32F769-DISC] 【F769IDISCOVERY评测】”弹幕“来了

  [复制链接]

60

主题

2051

回帖

31

蝴蝶豆

版主

最后登录
2020-12-9
发表于 2017-2-19 17:17:36 | 显示全部楼层 |阅读模式
本帖最后由 creep 于 2017-2-19 21:36 编辑

       虽然STM32F769-Discovery的论坛评测活动早就结束了,但是截止到目前STM32F769-Discovery 依然是ST的开发板中可玩性和综合性能比较高的,其中的独有或者新增的外设都值得好好学习一下,下面就简单看下板载的LCD相关的内容。

    1、DSI和LTDC

       STM32F769-Discovery上面的LCD是一个分辨率为800*480的电容触摸屏,驱动接口为DSI-MIPI模式,这种模式是手机行业比较常用的驱动模式,最近几年才出现在ST的高端MCU上面,其特点是接口简单占用IO口少但是速度非常快,但是配置可能比较复杂一些。在此之前ST的比较方便使用的LCD接口是以STM32F429上的LTDC接口为代表,现在的出现的DSI-MIPI是在LTDC的基础上增添了MIPI相关的协议,所以如果比较熟悉LTDC相关的使用对学习STM32D769上的DIS-MIPI有很大的帮助。

       DSI-MIPI接口驱动LCD主要涉及到了外设有DSIHOST、LTDC、FMC(SDRAM)、DMA2D等。前2个外设DSIHOST、LTDC主要是数据传输控制接口;FMC(SDRAM)主要用于LCD的缓存使用;DMA2D是一个LCD专用的DMA,可实现方便快速的图像图层显示控制,在不占用CPU的情况话显示图片、文字等功能。虽然看起来可能设置比较复杂但是好在ST的开发包里面提供很多详细的配置例子,除此之外使用CubeMX也能通过图形的界面进行LCD驱动的配置,这都给我们入门学习这些新的外设提供了很多便捷。


    通过下面的DSIHOST和LTDC的框图可以总体上对这个接口有个大致的了解:

                                                      ltdc_dsi_host.png

LCD的初始化就说对DSI、LTDC、SDRAM、DMA2D进行初始化的配置,大致如下:
1)DSI
  1. /*************************DSI Initialization***********************************/  

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

  4.   HAL_DSI_DeInit(&(hdsi_discovery));

  5.   dsiPllInit.PLLNDIV  = 100;
  6.   dsiPllInit.PLLIDF   = DSI_PLL_IN_DIV5;
  7.   dsiPllInit.PLLODF  = DSI_PLL_OUT_DIV1;
  8.   laneByteClk_kHz = 62500; /* 500 MHz / 8 = 62.5 MHz = 62500 kHz */

  9.   /* Set number of Lanes */
  10.   hdsi_discovery.Init.NumberOfLanes = DSI_TWO_DATA_LANES;

  11.   /* TXEscapeCkdiv = f(LaneByteClk)/15.62 = 4 */
  12.   hdsi_discovery.Init.TXEscapeCkdiv = laneByteClk_kHz/15620;

  13.   HAL_DSI_Init(&(hdsi_discovery), &(dsiPllInit));

  14.   /* Timing parameters for all Video modes
  15.   * Set Timing parameters of LTDC depending on its chosen orientation
  16.   */
  17.   if(orientation == LCD_ORIENTATION_PORTRAIT)
  18.   {
  19.     lcd_x_size = OTM8009A_480X800_WIDTH;  /* 480 */
  20.     lcd_y_size = OTM8009A_480X800_HEIGHT; /* 800 */                                
  21.   }
  22.   else
  23.   {
  24.     /* lcd_orientation == LCD_ORIENTATION_LANDSCAPE */
  25.     lcd_x_size = OTM8009A_800X480_WIDTH;  /* 800 */
  26.     lcd_y_size = OTM8009A_800X480_HEIGHT; /* 480 */                                
  27.   }

  28.   HACT = lcd_x_size;
  29.   VACT = lcd_y_size;

  30.   /* The following values are same for portrait and landscape orientations */
  31.   VSA  = OTM8009A_480X800_VSYNC;        /* 12  */
  32.   VBP  = OTM8009A_480X800_VBP;          /* 12  */
  33.   VFP  = OTM8009A_480X800_VFP;          /* 12  */
  34.   HSA  = OTM8009A_480X800_HSYNC;        /* 63  */
  35.   HBP  = OTM8009A_480X800_HBP;          /* 120 */
  36.   HFP  = OTM8009A_480X800_HFP;          /* 120 */   

  37.   hdsivideo_handle.VirtualChannelID = LCD_OTM8009A_ID;
  38.   hdsivideo_handle.ColorCoding = LCD_DSI_PIXEL_DATA_FMT_RBG888;
  39.   hdsivideo_handle.VSPolarity = DSI_VSYNC_ACTIVE_HIGH;
  40.   hdsivideo_handle.HSPolarity = DSI_HSYNC_ACTIVE_HIGH;
  41.   hdsivideo_handle.DEPolarity = DSI_DATA_ENABLE_ACTIVE_HIGH;  
  42.   hdsivideo_handle.Mode = DSI_VID_MODE_BURST; /* Mode Video burst ie : one LgP per line */
  43.   hdsivideo_handle.NullPacketSize = 0xFFF;
  44.   hdsivideo_handle.NumberOfChunks = 0;
  45.   hdsivideo_handle.PacketSize                = HACT; /* Value depending on display orientation choice portrait/landscape */
  46.   hdsivideo_handle.HorizontalSyncActive      = (HSA * laneByteClk_kHz)/LcdClock;
  47.   hdsivideo_handle.HorizontalBackPorch       = (HBP * laneByteClk_kHz)/LcdClock;
  48.   hdsivideo_handle.HorizontalLine            = ((HACT + HSA + HBP + HFP) * laneByteClk_kHz)/LcdClock; /* Value depending on display orientation choice portrait/landscape */
  49.   hdsivideo_handle.VerticalSyncActive        = VSA;
  50.   hdsivideo_handle.VerticalBackPorch         = VBP;
  51.   hdsivideo_handle.VerticalFrontPorch        = VFP;
  52.   hdsivideo_handle.VerticalActive            = VACT; /* Value depending on display orientation choice portrait/landscape */

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

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

  58.   /* Largest packet size possible to transmit in LP mode in HFP region during VACT period */
  59.   /* Only useful when sending LP packets is allowed while streaming is active in video mode */
  60.   hdsivideo_handle.LPVACTLargestPacketSize = 0;

  61.   /* Specify for each region of the video frame, if the transmission of command in LP mode is allowed in this region */
  62.   /* while streaming is active in video mode                                                                         */
  63.   hdsivideo_handle.LPHorizontalFrontPorchEnable = DSI_LP_HFP_ENABLE;   /* Allow sending LP commands during HFP period */
  64.   hdsivideo_handle.LPHorizontalBackPorchEnable  = DSI_LP_HBP_ENABLE;   /* Allow sending LP commands during HBP period */
  65.   hdsivideo_handle.LPVerticalActiveEnable = DSI_LP_VACT_ENABLE;  /* Allow sending LP commands during VACT period */
  66.   hdsivideo_handle.LPVerticalFrontPorchEnable = DSI_LP_VFP_ENABLE;   /* Allow sending LP commands during VFP period */
  67.   hdsivideo_handle.LPVerticalBackPorchEnable = DSI_LP_VBP_ENABLE;   /* Allow sending LP commands during VBP period */
  68.   hdsivideo_handle.LPVerticalSyncActiveEnable = DSI_LP_VSYNC_ENABLE; /* Allow sending LP commands during VSync = VSA period */

  69.   /* Configure DSI Video mode timings with settings set above */
  70.   HAL_DSI_ConfigVideoMode(&(hdsi_discovery), &(hdsivideo_handle));

  71. /*************************End DSI Initialization*******************************/
复制代码
2)LTDC、SDRAM、驱动IC(OTM8009A)的初始化
  1. /************************LTDC Initialization***********************************/  

  2.   /* Timing Configuration */   
  3.   hltdc_discovery.Init.HorizontalSync = (HSA - 1);
  4.   hltdc_discovery.Init.AccumulatedHBP = (HSA + HBP - 1);
  5.   hltdc_discovery.Init.AccumulatedActiveW = (lcd_x_size + HSA + HBP - 1);
  6.   hltdc_discovery.Init.TotalWidth = (lcd_x_size + HSA + HBP + HFP - 1);

  7.   /* Initialize the LCD pixel width and pixel height */
  8.   hltdc_discovery.LayerCfg->ImageWidth  = lcd_x_size;
  9.   hltdc_discovery.LayerCfg->ImageHeight = lcd_y_size;   

  10.   /** LCD clock configuration
  11.     * Note: The following values should not be changed as the PLLSAI is also used
  12.     *      to clock the USB FS
  13.     * PLLSAI_VCO Input = HSE_VALUE/PLL_M = 1 Mhz
  14.     * PLLSAI_VCO Output = PLLSAI_VCO Input * PLLSAIN = 384 Mhz
  15.     * PLLLCDCLK = PLLSAI_VCO Output/PLLSAIR = 384 MHz / 7 = 54.85 MHz
  16.     * LTDC clock frequency = PLLLCDCLK / LTDC_PLLSAI_DIVR_2 = 54.85 MHz / 2 = 27.429 MHz
  17.     */
  18.   PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_LTDC;
  19.   PeriphClkInitStruct.PLLSAI.PLLSAIN = 384;
  20.   PeriphClkInitStruct.PLLSAI.PLLSAIR = 7;
  21.   PeriphClkInitStruct.PLLSAIDivR = RCC_PLLSAIDIVR_2;
  22.   HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct);

  23.   /* Background value */
  24.   hltdc_discovery.Init.Backcolor.Blue = 0;
  25.   hltdc_discovery.Init.Backcolor.Green = 0;
  26.   hltdc_discovery.Init.Backcolor.Red = 0;
  27.   hltdc_discovery.Init.PCPolarity = LTDC_PCPOLARITY_IPC;
  28.   hltdc_discovery.Instance = LTDC;

  29.   /* Get LTDC Configuration from DSI Configuration */
  30.   HAL_LTDC_StructInitFromVideoConfig(&(hltdc_discovery), &(hdsivideo_handle));

  31.   /* Initialize the LTDC */  
  32.   HAL_LTDC_Init(&hltdc_discovery);

  33.   /* Enable the DSI host and wrapper after the LTDC initialization
  34.      To avoid any synchronization issue, the DSI shall be started after enabling the LTDC */
  35.   HAL_DSI_Start(&hdsi_discovery);

  36. #if !defined(DATA_IN_ExtSDRAM)
  37.   /* Initialize the SDRAM */
  38.   BSP_SDRAM_Init();
  39. #endif /* DATA_IN_ExtSDRAM */

  40.   /* Initialize the font */
  41.   BSP_LCD_SetFont(&LCD_DEFAULT_FONT);

  42. /************************End LTDC Initialization*******************************/
  43.   
  44.   
  45. /***********************OTM8009A Initialization********************************/

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

  50. /***********************End OTM8009A Initialization****************************/
复制代码
一旦LCD初始化之后,对LCD的操作就说对其缓存SDRAM的操作,比如下面的下一个点到LCD上的函数,这样的操作非常的简单方便:
  1. /**
  2.   * @brief  Draws a pixel on LCD.
  3.   * @param  Xpos: X position
  4.   * @param  Ypos: Y position
  5.   * @param  RGB_Code: Pixel color in ARGB mode (8-8-8-8)
  6.   */
  7. void BSP_LCD_DrawPixel(uint16_t Xpos, uint16_t Ypos, uint32_t RGB_Code)
  8. {
  9.   /* Write data value to all SDRAM memory */
  10.   *(__IO uint32_t*) (hltdc_discovery.LayerCfg[ActiveLayer].FBStartAdress + (4*(Ypos*BSP_LCD_GetXSize() + Xpos))) = RGB_Code;
  11. }
复制代码
我们的测试是在LCD上滚动显示一些字符,这些字符可以通过串口发送进行修改,类似“弹幕”一样,下面是初始化后显示的滚动字符

IMG_2126.GIF
我们通过串口发送2个“弹幕”试下:分别为  “2017-02-19 16:17:33”   “Hi,this message is from sscom...”   
串口的接收函数使用的是前面帖子介绍的 超时中断接收不定长字符串。

IMG_2128.GIF

  2、QUADSPI 和中文字库

    板载上有个NorFlash使用QUADSPI 接口可用于汉字库和图片的存储,我们将汉字库存在Norflash总然后利用QUADSPI 接口的memory-map 功能可以直接读取汉字进行显示,在程序中初始化后NorFlash之后通过内部的FLASH将汉字库写入到NorFlash之中然后在进行验证字库是否正确。
  1. BSP_QSPI_Init();
  2.         CopyFont2NorFlash();
  3.         BSP_QSPI_EnableMemoryMappedMode();
  4.         CheckGBKFont4NorFlash();
复制代码
其中memory-map 如下:
  1. uint8_t BSP_QSPI_EnableMemoryMappedMode(void)
  2. {
  3.     QSPI_CommandTypeDef      s_command;
  4.     QSPI_MemoryMappedTypeDef s_mem_mapped_cfg;
  5.     /* Configure the command for the read instruction */
  6.     s_command.InstructionMode   = QSPI_INSTRUCTION_4_LINES;
  7.     s_command.Instruction       = QPI_READ_4_BYTE_ADDR_CMD;
  8.     s_command.AddressMode       = QSPI_ADDRESS_4_LINES;
  9.     s_command.AddressSize       = QSPI_ADDRESS_32_BITS;
  10.     s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;
  11.     s_command.DataMode          = QSPI_DATA_4_LINES;
  12.     s_command.DummyCycles       = MX25L512_DUMMY_CYCLES_READ_QUAD_IO;
  13.     s_command.DdrMode           = QSPI_DDR_MODE_DISABLE;
  14.     s_command.DdrHoldHalfCycle  = QSPI_DDR_HHC_ANALOG_DELAY;
  15.     s_command.SIOOMode          = QSPI_SIOO_INST_EVERY_CMD;
  16.     /* Configure the memory mapped mode */
  17.     s_mem_mapped_cfg.TimeOutActivation = QSPI_TIMEOUT_COUNTER_DISABLE;
  18.     s_mem_mapped_cfg.TimeOutPeriod     = 0;

  19.     if(HAL_QSPI_MemoryMapped(&QSPIHandle, &s_command, &s_mem_mapped_cfg) != HAL_OK)
  20.     {
  21.         return QSPI_ERROR;
  22.     }

  23.     return QSPI_OK;
  24. }
复制代码
烧写和验证:

IMG_2129.GIF

我们发送2个中文字符串试下:


IMG_2132.GIF

3、手机发送“弹幕”

    如果只能用电脑发送不能用手机发送弹幕,那绝对不是一个好弹幕,之前的帖子里面我们介绍了板载有个wifi模块的接口,通过这个接口我们
可以发送数据到LCD显示,我是通过建立一个UDP连接进行数据通信的。关于esp8266的AT命令和使用方法可以参考前面的帖子 。同样wifi接口的串口也是使用超时中断完成的。具体代码如下;
  1. void WIFI_ReceiverTimeOut_Callback(UART_HandleTypeDef *huart)
  2. {
  3.     uint16_t len;
  4.     uint32_t tmp1 = 0;
  5.     tmp1 = __HAL_UART_GET_FLAG(huart, UART_FLAG_RTOF);
  6.     if((tmp1 != RESET))
  7.     {
  8.         __HAL_UART_CLEAR_IT(huart, UART_CLEAR_RTOF);
  9.         /* set uart state  ready*/
  10.         huart->RxState = HAL_UART_STATE_READY;
  11.         /* Disable the rx  DMA peripheral */
  12.         __HAL_DMA_DISABLE(huart->hdmarx);
  13.         /*Clear the DMA Stream pending flags.*/
  14.         __HAL_DMA_CLEAR_FLAG(huart->hdmarx, __HAL_DMA_GET_TC_FLAG_INDEX(huart->hdmarx));
  15.         /* get rx data len */
  16.         len = huart->hdmarx->Instance->NDTR;
  17.         WIFI_Rxlen = RXBUFFLENGTH - len;
  18.                           if(WIFI_Rxlen && WIFI_Init_Sta)
  19.                                 {
  20.                                         if(strlen((char*)WIFI_RxBuff))
  21.                                         {
  22.                                                 if(WIFI_Rxlen > RXASCIIMAX) WIFI_Rxlen = RXBUFFLENGTH;
  23.                                                 if(Display_pos_dn == 0)Display_pos_dn = 14;        
  24.                                                 Display_pos_dn--;
  25.                                                 memset(Display_Buff[Display_pos_dn],0,101);
  26.                                                 memcpy(Display_Buff[Display_pos_dn],WIFI_RxBuff,WIFI_Rxlen);        
  27.                                         }                                                
  28.                                 }
  29.         /* Process Unlocked */
  30.         __HAL_UNLOCK(huart->hdmarx);
  31.         
  32.        huart->hdmarx->State = HAL_DMA_STATE_READY;

  33.       HAL_UART_Receive_DMA(huart, WIFI_RxBuff, RXBUFFLENGTH);
  34.                         WIFI_CMD_Response_Sta = ENABLE;
  35.     }
  36. }
复制代码

手机发送的“弹幕“如下;

C6782412921255C840141DE26CD743FE.png

LCD 显示如下:
IMG_2136.GIF


  当然截止到目前这还不算是个好的弹幕,这只能一个人自娱自乐,好的弹幕应该是很多人都能发。其实这样也不是很难,如果有个公网IP然后在路由器中做个端口映射那就在外面直接连上wiif模块发送弹幕了。上面有些GIF图片可能较大会加载较慢。
      4、总结

    最后我们看下main 函数:

  1. int main(void)
  2. {
  3.         uint16_t x0,t;
  4.   CPU_CACHE_Enable();
  5.   HAL_Init();
  6.   SystemClock_Config();
  7.         USART1_Init();
  8.         My_ESP8266_Init();
  9.         HAL_Delay(200);
  10.         ESP8266_Establish_UDP();
  11.         ResetReciverBuff();
  12.   BSP_LCD_Init();   
  13.   BSP_LCD_LayerDefaultInit(0, LCD_FB_START_ADDRESS);  
  14.   BSP_LCD_SetTextColor(LCD_COLOR_RED);
  15.         BSP_LCD_Clear(LCD_COLOR_BLACK);
  16.         BSP_LCD_SetBackColor(LCD_COLOR_BLACK);
  17.         BSP_QSPI_Init();
  18.         CopyFont2NorFlash();
  19.         BSP_QSPI_EnableMemoryMappedMode();
  20.         CheckGBKFont4NorFlash();
  21.         HAL_Delay(500);
  22.         BSP_LCD_Clear(LCD_COLOR_BLACK);
  23.        
  24.         for(t = 0;t < 14;t++)
  25.         {
  26.                 memcpy(Display_Buff[t],TextBuff[t],strlen((const char*)TextBuff[t]));
  27.         }
  28.   while (1)
  29.   {
  30.                 for(x0 = 0;x0 < 800;x0++)
  31.                 {
  32.                                 for(t = 0;t < 14;t++)
  33.                                 {
  34.                                         BSP_LCD_SlideShow(x0,10 + 30*t,t);
  35.                                 }
  36.                 }

  37.   }
  38. }
复制代码
          在上面的main函数中我们先初始化了串口1用于在电脑上进行发送“弹幕”,然后又初始化了串口WIFI模块ESP8266模块,初始化了WIFI模块和手机建立一个UDP连接,此时首先你应该知道自己的手机的IP地址和WIFI的IP地址,在用wifi模块建立UDP连接的时候我省略了输入路由器的SSID和密码的步骤如果你的模块也配置连接过路由器,这个也能省略否则要自己添加上这个步骤。然后就说初始化LCD的模块部分,最后就是将汉字库通过内部FLASH烧写到NORFALSH中,因为烧写字库要下载很大的BIN文件比较浪费时间,所以烧写字库进行一次即可,代码中我通过宏定义来设置要不要进行字库的烧写,限于时间和篇幅限制还有很多细节帖子中没法详细描述,具体可以测试参考代码,代码写的比较简陋只用于演示验证作用。
   帖子中用到的2个串口超时中断以及WIFI模块的AT命令可以参考下面的推荐阅读中详细内容。


    推荐阅读:
           串口接收超时中断和字符匹配中断

           ESP8266简单上手

测试代码:
Bullset screen_WIFI.rar (2.32 MB, 下载次数: 66)

评分

参与人数 3ST金币 +45 收起 理由
努力的人 + 5 楼主再接再厉,做一个炫酷的UI.
MrJiu + 10 真的很不错!!!!
zero99 + 30

查看全部评分

<
回复

使用道具 举报

64

主题

744

回帖

23

蝴蝶豆

实习版主

最后登录
2020-12-8
发表于 2017-2-19 17:35:09 | 显示全部楼层
沙发,顶大神
回复 支持 反对

使用道具 举报

107

主题

812

回帖

5

蝴蝶豆

论坛元老

最后登录
2019-8-28
发表于 2017-2-19 20:14:00 | 显示全部楼层
牛X,下载下来慢慢学习
回复 支持 反对

使用道具 举报

14

主题

293

回帖

17

蝴蝶豆

金牌会员

最后登录
2019-5-9
发表于 2017-2-19 20:52:54 | 显示全部楼层
很棒的分享,谢谢
回复 支持 反对

使用道具 举报

47

主题

3404

回帖

30

蝴蝶豆

版主

最后登录
2020-12-7
发表于 2017-2-19 21:48:27 | 显示全部楼层
Niubility。。。支持支持。。。
回复 支持 反对

使用道具 举报

2

主题

135

回帖

0

蝴蝶豆

金牌会员

最后登录
2020-12-7
发表于 2017-2-19 21:53:41 | 显示全部楼层
  厉害,赞一个
回复 支持 反对

使用道具 举报

20

主题

1110

回帖

125

蝴蝶豆

论坛元老

最后登录
2019-5-4
发表于 2017-2-19 22:11:04 | 显示全部楼层
 这个挺不错的,给楼主一个赞
回复 支持 反对

使用道具 举报

69

主题

1691

回帖

124

蝴蝶豆

版主

最后登录
2020-12-8
发表于 2017-2-19 22:19:29 | 显示全部楼层
厉害,不错哦,
gif动画怎么弄的?
回复 支持 反对

使用道具 举报

10

主题

693

回帖

0

蝴蝶豆

金牌会员

最后登录
2018-6-15
发表于 2017-2-19 22:30:42 | 显示全部楼层
厉害厉害                              
回复 支持 反对

使用道具 举报

2

主题

94

回帖

2

蝴蝶豆

金牌会员

最后登录
2020-6-5
发表于 2017-2-20 08:31:18 | 显示全部楼层
不错哦,收藏了
回复 支持 反对

使用道具 举报

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版