ART-PI开发记录----1、STM32CUBEMX创建LTDC显示工程

论坛 期权论坛 编程之家     
选择匿名的用户   2021-6-2 16:18   2655   0

一、前述

ART-PI是RTT官方退出的STM32H7系列的开发板,照理说用RTT开发即可,简洁易上手(如果已经熟悉RTT)。但也可基于STM32CUBEMX开发,生成带FreeRTOS以及FATFS文件系统的工程。相对来说,用ST官方工具生成的代码用起来跟原汁原味一些,但RTT则具有更多的中间件,代码使用起来也更加简洁。个人习惯于使用STM32CUBEMX,所以先记录一下基于CUBE的开发方式,后续会加入RTT。

二、硬件配置

如图的ART-PI + LCD转接板 + 野火5寸RGB屏

三、STM32CUBEMX的配置

进入正题,创建一个LTDC的显示工程。需要用到以下几个基本外设,FMC、MPU、DMA2D、LTDC。FMC用于驱动SDRAM,作为LTDC的缓存。如果是480*272的RGB显示屏,也可使用内部的AXI-SRAM以获得更大的数据带宽。但AXI-SRAM只有512KB,最多作双FB缓冲。有的GUI如AWTK需要作三FB缓冲才可流畅显示而不产生撕裂画面。MPU,字面上意思是用于保护内存单元。但实际上,MPU是用来协调芯片内部的I-Cashe、D-Cashe与存储设备的一个外设。具体自行搜索:“STM32F7 MPU Cache浅析”。具体作用就是可加速RAM、ROM数据的读写速度,当然,加速也是存在一定的局限性的。DMA2D与LTDC就不赘述了。

(1)时钟树

内核倍频到480M,LTDC时钟如下图红框,20M。FMC,则采用48M的HSI倍频到240M。所以SDRAM时钟频率是240M/2 = 120M

图3.1.1 时钟树的配置

(2)GPIO的配置

ART-PI还是进行了不少的GPIO映射的,估计是为了画板走线方便吧。LTDC的IO都进行了大量的映射,这里还需要注意背光控制引脚的初始化。

图3.2.1 GPIO的配置

(3)MPU的配置

如下图,配置了AXI-SRAM以及SDRAM的缓冲模式。SDRAM为读缓冲,写不缓冲。而AXI-SRAM则是读写缓冲。

图3.3.1 MPU的配置

(4)FMC的配置

SDRAM是使用FMC驱动的,我们找到SDRAM1处进行配置。具体的时序参考SDRAM的数据手册。ART-PI使用的是:W9825G6KH-6。

图 3.4.1 FMC配置

图 3.4.2 SDRAM时序

(5)LTDC的配置

我使用的是野火的800*480-5寸电容触摸显示模组,LTDC驱动RGB屏的参数也应自行参考屏的数据手册。

图 3.5.1 LTDC配置1

图 3.5.2 LTDC配置2

(6)DMA2D的配置

这个只需要在CUBE里面勾选这个选项就好,这样“main.h”就会包含DMA2D库的头文件。因为后续在使用DMA2D的时候,会先对DMA2D进行配置再使用,所以在CUBE里面的配置无意义。

四、代码

用stm32cubemx生成代码后,并不能直接烧录到ART-PI运行。还需要添加一些代码。

(1)SDRAM的初始化,参考了安富莱的教程。


#define SDRAM_TIMEOUT                    ((uint32_t)0xFFFF)
#define REFRESH_COUNT                    ((uint32_t)917)    /* SDRAM ReFlash Count */  


#define SDRAM_MODEREG_BURST_LENGTH_1             ((uint16_t)0x0000)
#define SDRAM_MODEREG_BURST_LENGTH_2             ((uint16_t)0x0001)
#define SDRAM_MODEREG_BURST_LENGTH_4             ((uint16_t)0x0002)
#define SDRAM_MODEREG_BURST_LENGTH_8             ((uint16_t)0x0004)
#define SDRAM_MODEREG_BURST_TYPE_SEQUENTIAL      ((uint16_t)0x0000)
#define SDRAM_MODEREG_BURST_TYPE_INTERLEAVED     ((uint16_t)0x0008)
#define SDRAM_MODEREG_CAS_LATENCY_2              ((uint16_t)0x0020)
#define SDRAM_MODEREG_CAS_LATENCY_3              ((uint16_t)0x0030)
#define SDRAM_MODEREG_OPERATING_MODE_STANDARD    ((uint16_t)0x0000)
#define SDRAM_MODEREG_WRITEBURST_MODE_PROGRAMMED ((uint16_t)0x0000)
#define SDRAM_MODEREG_WRITEBURST_MODE_SINGLE     ((uint16_t)0x0200)



/* This function is used to initialize SDRAM */
void SDRAM_Initialization_Sequence(SDRAM_HandleTypeDef *hsdram)
{
 __IO uint32_t tmpmrd =0;
 FMC_SDRAM_CommandTypeDef command1 = {0},*Command = &command1;
 
 
    /*##-1- Clock enable command ##################################################*/
 Command->CommandMode = FMC_SDRAM_CMD_CLK_ENABLE;
 Command->CommandTarget = FMC_SDRAM_CMD_TARGET_BANK1;;
 Command->AutoRefreshNumber = 1;
 Command->ModeRegisterDefinition = 0;

 /* SendCommand */
 HAL_SDRAM_SendCommand(hsdram, Command, SDRAM_TIMEOUT);

    /*##-2- delay ##################################################*/
 HAL_Delay(1);

    /*##-3- SDRAM pre charging(precharge all) #############################*/
 Command->CommandMode = FMC_SDRAM_CMD_PALL;
 Command->CommandTarget = FMC_SDRAM_CMD_TARGET_BANK1;
 Command->AutoRefreshNumber = 1;
 Command->ModeRegisterDefinition = 0;

 /* SendCommand */
 HAL_SDRAM_SendCommand(hsdram, Command, SDRAM_TIMEOUT);

    /*##-4- Auto refresh command ##################################################*/
 Command->CommandMode = FMC_SDRAM_CMD_AUTOREFRESH_MODE;
 Command->CommandTarget = FMC_SDRAM_CMD_TARGET_BANK1;
 Command->AutoRefreshNumber = 8;
 Command->ModeRegisterDefinition = 0;

 /* SendCommand */
 HAL_SDRAM_SendCommand(hsdram, Command, SDRAM_TIMEOUT);

    /*##-5- Configure SDRAM mode register ######################################*/
 tmpmrd = (uint32_t)SDRAM_MODEREG_BURST_LENGTH_1          |
      SDRAM_MODEREG_BURST_TYPE_SEQUENTIAL   |
      SDRAM_MODEREG_CAS_LATENCY_3           |
      SDRAM_MODEREG_OPERATING_MODE_STANDARD |
      SDRAM_MODEREG_WRITEBURST_MODE_SINGLE;

 Command->CommandMode = FMC_SDRAM_CMD_LOAD_MODE;
 Command->CommandTarget = FMC_SDRAM_CMD_TARGET_BANK1;
 Command->AutoRefreshNumber = 1;
 Command->ModeRegisterDefinition = tmpmrd;

 /* SendCommand */
 HAL_SDRAM_SendCommand(hsdram, Command, SDRAM_TIMEOUT);

    /*##-6- Set self refresh rate ############################################*/
    /*
      = 64ms / 8192 *120MHz*1000 - 20
      = 917
    */
 HAL_SDRAM_ProgramRefreshRate(hsdram, REFRESH_COUNT); 
}

(2)DMA2D功能代码,这部分代码来自安富莱的教程


/*
*********************************************************************************************************
* 函 数 名: _DMA2D_Fill
* 功能说明: DMA2D颜色填充功能
* 形    参: pDst          颜色数据目的地址
*             xSize         色块X轴大小,即每行像素数
*             ySize         色块Y轴大小,即行数
*             OffLine       前景层图像的行偏移
*             ColorIndex    色块颜色值
*             PixelFormat   目标区颜色格式
* 返 回 值: 无
*********************************************************************************************************
*/
void _DMA2D_Fill(void * pDst, 
       uint32_t xSize, 
    uint32_t ySize, 
    uint32_t OffLine, 
    uint32_t ColorIndex, 
    uint32_t PixelFormat) 
{
 
 /* DMA2D采用寄存器到存储器模式, 这种模式用不到前景层和背景层 */  
 DMA2D->CR      = 0x00030000UL | (1 << 9);
 DMA2D->OCOLR   = ColorIndex;
 DMA2D->OMAR    = (uint32_t)pDst;
 DMA2D->OOR     = OffLine;
 DMA2D->OPFCCR  = PixelFormat;
 DMA2D->NLR     = (uint32_t)(xSize << 16) | (uint16_t)ySize;

 /* 启动传输 */
 DMA2D->CR   |= DMA2D_CR_START;   

 /* 等待DMA2D传输完成 */
 while (DMA2D->CR & DMA2D_CR_START) {} 
}

/*
*********************************************************************************************************
* 函 数 名: _DMA2D_Copy
* 功能说明: 通过DMA2D从前景层复制指定区域的颜色数据到目标区域
* 形    参: pSrc          颜色数据源地址
*             pDst          颜色数据目的地址
*             xSize         目的区域的X轴大小,即每行像素数
*             ySize         目的区域的Y轴大小,即行数
*             OffLineSrc    前景层图像的行偏移
*             OffLineDst    输出的行偏移
*             PixelFormat   目标区颜色格式
* 返 回 值: 无
*********************************************************************************************************
*/
void _DMA2D_Copy(void * pSrc, 
    void * pDst, 
    uint32_t xSize, 
    uint32_t ySize, 
    uint32_t OffLineSrc, 
    uint32_t OffLineDst, 
    uint32_t PixelFormat) 
{

 /* DMA2D采用存储器到存储器模式, 这种模式是前景层作为DMA2D输入 */  
 DMA2D->CR      = 0x00000000UL | (1 << 9);
 DMA2D->FGMAR   = (uint32_t)pSrc;
 DMA2D->OMAR    = (uint32_t)pDst;
 DMA2D->FGOR    = OffLineSrc;
 DMA2D->OOR     = OffLineDst;
 
 /* 前景层和输出区域都采用的RGB565颜色格式 */
 DMA2D->FGPFCCR = LTDC_PIXEL_FORMAT_RGB565;
 DMA2D->OPFCCR  = LTDC_PIXEL_FORMAT_RGB565;
 
 DMA2D->NLR     = (uint32_t)(xSize << 16) | (uint16_t)ySize;

 /* 启动传输 */
 DMA2D->CR   |= DMA2D_CR_START;   

 /* 等待DMA2D传输完成 */
 while (DMA2D->CR & DMA2D_CR_START) {} 
}

/*
*********************************************************************************************************
* 函 数 名: _DMA2D_MixColorsBulk
* 功能说明: 前景层和目标区域的颜色混合
* 形    参: pColorFG      前景层数据源地址
*             OffLineSrcFG  前景层图像的行偏移
*             pColorDst     目标区数据地址
*             OffLineDst    目标区的行偏移
*             xSize         目的区域的X轴大小,即每行像素数
*             ySize         目的区域的Y轴大小,即行数
*             Intens        设置前景层的透明度,255表示完全不透明,0表示完全透明
* 返 回 值: 无
*********************************************************************************************************
*/
 void _DMA2D_MixColorsBulk(uint32_t * pColorFG,  
       uint32_t OffLineSrcFG,
       uint32_t * pColorDst, 
       uint32_t OffLineDst,
       uint32_t xSize, 
       uint32_t ySize, 
       uint8_t Intens)
{
 /* DMA2D采用存储器到存储器模式, 这种模式前景层和背景层作为DMA2D输入,且支持颜色格式转换和颜色混合 */  
 DMA2D->CR      = 0x00020000UL | (1 << 9);
 DMA2D->FGMAR   = (uint32_t)pColorFG;
 DMA2D->BGMAR   = (uint32_t)pColorDst;
 DMA2D->OMAR    = (uint32_t)pColorDst;
 DMA2D->FGOR    = OffLineSrcFG;
 DMA2D->BGOR    = OffLineDst;
 DMA2D->OOR     = OffLineDst;

 /* 前景层,背景层和输出区都是用的RGB565格式 */
 DMA2D->FGPFCCR = LTDC_PIXEL_FORMAT_RGB565
     | (1UL << 16)
     | ((uint32_t)Intens << 24);
 DMA2D->BGPFCCR = LTDC_PIXEL_FORMAT_RGB565;
 DMA2D->OPFCCR  = LTDC_PIXEL_FORMAT_RGB565;

 DMA2D->NLR     = (uint32_t)(xSize << 16) | (uint16_t)ySize;
  
 /* 启动传输 */
 DMA2D->CR   |= DMA2D_CR_START;   

 /* 等待DMA2D传输完成 */
 while (DMA2D->CR & DMA2D_CR_START) {} 
}

/*
*********************************************************************************************************
* 函 数 名: _DMA2D_AlphaBlendingBulk
* 功能说明: 前景层和背景层的颜色混合
* 形    参: pColorFG      前景层源数据地址
*             OffLineSrcFG  前景层源数据行偏移
*             pColorBG      背景层源数据地址
*             OffLineSrcBG  背景层源数据行偏移
*             pColorDst     目标区地址
*             OffLineDst    目标区行偏移
*             xSize         目标区域的X轴大小,即每行像素数
*             ySize         目标区域的Y轴大小,即行数
* 返 回 值: 无
*********************************************************************************************************
*/
void _DMA2D_AlphaBlendingBulk(uint32_t * pColorFG,  
        uint32_t OffLineSrcFG,
        uint32_t * pColorBG,  
        uint32_t OffLineSrcBG,
        uint32_t * pColorDst, 
        uint32_t OffLineDst,
        uint32_t xSize, 
        uint32_t ySize) 
{  
 /* DMA2D采用存储器到存储器模式, 这种模式前景层和背景层作为DMA2D输入,且支持颜色格式转换和颜色混合 */  
 DMA2D->CR      = 0x00020000UL | (1 << 9);
 DMA2D->FGMAR   = (uint32_t)pColorFG;
 DMA2D->BGMAR   = (uint32_t)pColorBG;
 DMA2D->OMAR    = (uint32_t)pColorDst;
 DMA2D->FGOR    = OffLineSrcFG;
 DMA2D->BGOR    = OffLineSrcBG;
 DMA2D->OOR     = OffLineDst;

 /* 前景层,背景层采用ARGB8888格式,输出区采用RGB565格式 */
 DMA2D->FGPFCCR = LTDC_PIXEL_FORMAT_ARGB8888;
 DMA2D->BGPFCCR = LTDC_PIXEL_FORMAT_ARGB8888;
 DMA2D->OPFCCR  = LTDC_PIXEL_FORMAT_RGB565;
 DMA2D->NLR     = (uint32_t)(xSize << 16) | (uint16_t)ySize;

 /* 启动传输 */
 DMA2D->CR   |= DMA2D_CR_START;   

 /* 等待DMA2D传输完成 */
 while (DMA2D->CR & DMA2D_CR_START) {} 
}

/*
*********************************************************************************************************
* 函 数 名: _DMA2D_DrawAlphaBitmap
* 功能说明: ARGB8888格式位图显示
* 形    参: pDst        目标区地址
*             pSrc        源数据地址,即位图首地址
*             xSize       目标区域的X轴大小,即每行像素数
*             ySize       目标区域的Y轴大小,即行数
*             OffLineSrc  源数据行偏移
*             OffLineDst  目标区行偏移
*             PixelFormat 目标区颜色格式
* 返 回 值: 无
*********************************************************************************************************
*/
 void _DMA2D_DrawAlphaBitmap(void  * pDst, 
        void  * pSrc, 
        uint32_t xSize, 
        uint32_t ySize, 
        uint32_t OffLineSrc, 
        uint32_t OffLineDst, 
        uint32_t PixelFormat) 
{
 /* DMA2D采用存储器到存储器模式, 这种模式前景层和背景层作为DMA2D输入,且支持颜色格式转换和颜色混合 */  
 DMA2D->CR      = 0x00020000UL | (1 << 9);
 DMA2D->FGMAR   = (uint32_t)pSrc;
 DMA2D->BGMAR   = (uint32_t)pDst;
 DMA2D->OMAR    = (uint32_t)pDst;
 DMA2D->FGOR    = OffLineSrc;
 DMA2D->BGOR    = OffLineDst;
 DMA2D->OOR     = OffLineDst;
 
 /* 前景层颜色格式是LTDC_PIXEL_FORMAT_ARGB8888,即位图的颜色格式,背景层和输出区颜色格式可配置 */
 DMA2D->FGPFCCR = LTDC_PIXEL_FORMAT_ARGB8888;
 DMA2D->BGPFCCR = PixelFormat;
 DMA2D->OPFCCR  = PixelFormat;
 DMA2D->NLR     = (uint32_t)(xSize << 16) | (uint16_t)ySize;

 /* 启动传输 */
 DMA2D->CR   |= DMA2D_CR_START;   

 /* 等待DMA2D传输完成 */
 while (DMA2D->CR & DMA2D_CR_START) {} 
}

(3)主函数

int main(void)
{
  /* USER CODE BEGIN 1 */

  /* USER CODE END 1 */

  /* MPU Configuration--------------------------------------------------------*/
  MPU_Config();

  /* Enable I-Cache---------------------------------------------------------*/
  SCB_EnableICache();

  /* Enable D-Cache---------------------------------------------------------*/
  SCB_EnableDCache();

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_FMC_Init();
  MX_LPUART1_UART_Init();
  MX_TIM6_Init();
  MX_LTDC_Init();
  MX_DMA2D_Init();
  /* USER CODE BEGIN 2 */
  SDRAM_Initialization_Sequence(&hsdram1);
 
 _DMA2D_Fill((uint16_t*)0xc0000000, 
          800, 
    480, 
    0, 
    0x07e0, 
    LTDC_PIXEL_FORMAT_RGB565) ; 
 
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}

五、效果展示

(1) 主函数中使用DMA2D刷了全屏的绿色,显存位置如LTDC的设置,地址为:0xC0000000。这里屏幕没亮的话注意检查一下背光是否有打开。

(2)移植了LittleVGL7.9版本到板子上,并跑了一个例程。需要代码的可自行去下载:https://download.csdn.net/download/a3748622/14039358

(3)LittleVGL双帧缓冲代码

上述工程里默认是使用AXI RAM做240ROW的缓冲区。也可以使用SDRAM作双帧缓冲,通过“lv_port_disp.c”的一个宏定义更改:

#define TWO_SCREEN_SIZE   0

分享到 :
0 人收藏
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

积分:3875789
帖子:775174
精华:0
期权论坛 期权论坛
发布
内容

下载期权论坛手机APP