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

【F769IDISCOVERY评测】”弹幕“来了  

[复制链接]
creep 提问时间:2017-2-19 17:17 /
本帖最后由 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, 下载次数: 68)

评分

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

查看全部评分

1 收藏 8 评论22 发布时间:2017-2-19 17:17

举报

22个回答
jackten 回答时间:2017-2-19 22:30:42
厉害厉害                              
creep 回答时间:2017-2-21 13:35:32
队长shiwo 发表于 2017-2-21 09:33
收藏着学习先,仰慕大神

队长好         
creep 回答时间:2017-2-20 08:36:54
freeelectron 发表于 2017-2-19 22:19
厉害,不错哦,
gif动画怎么弄的?

ios客户端

Windows客户端
Stm32McuLover 回答时间:2017-2-19 17:35:09
沙发,顶大神
netlhx 回答时间:2017-2-19 20:14:00
牛X,下载下来慢慢学习
zoomdy 回答时间:2017-2-19 20:52:54
很棒的分享,谢谢
Paderboy 回答时间:2017-2-19 21:48:27
Niubility。。。支持支持。。。
ALTIUM2 回答时间:2017-2-19 21:53:41
  厉害,赞一个
anobodykey 回答时间:2017-2-19 22:11:04
 这个挺不错的,给楼主一个赞
freeelectron 回答时间:2017-2-19 22:19:29
厉害,不错哦,
gif动画怎么弄的?
人之颠 回答时间:2017-2-20 08:31:18
不错哦,收藏了
霹雳之火 回答时间:2017-2-20 08:47:47
谢谢分享
请叫我小张张 回答时间:2017-2-20 08:53:45
CREEP哥哥 这个好高端 收藏慢慢研究  感觉好好玩啊
风子 回答时间:2017-2-20 08:56:03
膜拜大神
Xinfeng 回答时间:2017-2-21 09:10:49
非常棒
12下一页

所属标签

相似问题

关于意法半导体
我们是谁
投资者关系
意法半导体可持续发展举措
创新和工艺
招聘信息
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
关注我们
st-img 微信公众号
st-img 手机版