| **银杏科技有限公司旗下技术文档发布平台** |||| |技术支持电话|**0379-69926675-801**||| |技术支持邮件|Gingko@vip.163.com||| ^ 版本 ^ 日期 ^ 作者 ^ 修改内容 ^ | V1.0 | 2020-09-23 | gingko | 初次建立 | \\ \\ \\ ===== STM32CubeMX教程六十——LCD实验驱动4.3寸液晶屏 ===== \\ \\ 1.在主界面选择File-->New Project 或者直接点击ACCEE TO MCU SELECTOR {{ :icore4t:icore4t_cube_60_1.png?direct |}} 2.出现芯片型号选择,搜索自己芯片的型号,双击型号,或者点击Start Project进入配置 在搜索栏的下面,提供的各 种查找方式,可以选择芯片内核,型号,等等,可以帮助你查找芯片。本实验选取的芯片型号为:STM32H750IBKx。 {{ :icore4t:icore4t_cube_60_2.png?direct |}} 3.配置RCC,使用外部时钟源 {{ :icore4t:icore4t_cube_60_3.png?direct |}} 4.时基源选择SysTick {{ :icore4t:icore4t_cube_60_4.png?direct |}} 5.配置GPIO和引脚模式,引脚为PA10,PB4,PB7,PB8,PF6,PI1,PI2,PI3。 {{ :icore4t:icore4t_cube_60_5.png?direct |}} 6.配置LTDC,引脚为PA8,PC7,PD3,PF10,PG6,PG7,PG10,PG12,PH9,PH10,PH11,PH12,PH13,PH15,PI0,PI5,PI6,PI7,PI9,PI10。 {{ :icore4t:icore4t_cube_60_6.png?direct |}} {{ :icore4t:icore4t_cube_60_7.png?direct |}} {{ :icore4t:icore4t_cube_60_8.png?direct |}} 7.配置TIM12。 {{ :icore4t:icore4t_cube_60_9.png?direct |}} {{ :icore4t:icore4t_cube_60_10.png?direct |}} 8.配置FMC,引脚为PD0,PD1,PD8,PD9,PD10,PD14,PD15,PE0,PE1,PE7,PE8,PE9,PE10,PE11,PE12,PE13,PE14,PE15,PF0,PF1,PF2,PF3,PF4,PF5,PF11,PF12,PF13,PF14,PF15,PG0,PG1,PG2,PG4,PG5,PG8,PG15,PH2,PH3,PH5。 {{ :icore4t:icore4t_cube_60_11.png?direct |}} 9.时钟源设置,选择外部高速时钟源,配置为最大主频。 {{ :icore4t:icore4t_cube_60_12.png?direct |}} {{ :icore4t:icore4t_cube_60_13.png?direct |}} 10.工程文件的设置, 这里就是工程的各种配置 我们只用到有限几个,其他的默认即可 IDE我们使用的是 MDK V5.27 {{ :icore4t:icore4t_cube_60_14.png?direct |}} 11.点击Code Generator,进行进一步配置 {{ :icore4t:icore4t_cube_60_15.png?direct |}} * **Copy all used libraries into the project folder** * 将HAL库的所有.C和.H都复制到所建工程中 * 优点:这样如果后续需要新增其他外设又可能不再用STM32CubeMX的时候便会很方便 * 缺点:体积大,编译时间很长 * **Copy only the necessary library files** * 只复制所需要的.C和.H(推荐) * 优点:体积相对小,编译时间短,并且工程可复制拷贝 * 缺点:新增外设时需要重新用STM32CubeMX导入 * **Add necessary library files as reference in the toolchain project configuration file** * 不复制文件,直接从软件包存放位置导入.C和.H * 优点:体积小,比较节约硬盘空间 * 缺点:复制到其他电脑上或者软件包位置改变,就需要修改相对应的路径 * 自行选择方式即可 12.然后点击GENERATE CODE 创建工程 {{ :icore4t:icore4t_cube_60_16.png?direct |}} 创建成功,打开工程。 \\ \\ \\ ===== 实验六十:LCD实验驱动4.3寸液晶屏 ===== ==== 一、 实验目的与意义 ==== - 了解STM32 LTDC结构 - 了解STM32 LTDC特征 - 掌握LCD液晶屏的使用方法 - 掌握STM32 HAL库中LTDC属性的配置方法 - 掌握KEIL MDK 集成开发环境使用方法 ==== 二、 实验设备及平台 ==== - iCore4T 双核心板 - iCore4T 扩展底板 - iCore 4.3寸液晶屏底板 - JLINK(或相同功能)仿真器 - Micro USB线缆 - Keil MDK 开发平台 - STM32CubeMX开发平台 - 装有WIN XP(及更高版本)系统的计算机 ==== 三、 实验原理 ==== === LCD-TFT显示控制器(LTDC) 简介 === LCD-TFT(液晶显示器——薄膜晶体管)显示器控制器提供并行数字 RGB(红色、绿色、 蓝色)以及水平同步、垂直同步、像素时钟和数据使能信号,这些信号直接输出到不同 LCD 和 TFT 面板的接口。STM32H750xx 的 LTDC 主要特性如下: * 24 位 RGB 并行像素输出;每像素 8 位数据(RGB888) * 2 个带有专用 FIFO 的显示层(FIFO 深度 64x64 位) * 支持查色表 (CLUT),每层高达 256 种颜色(256x24 位) * 可针对不同显示面板编程时序 * 可编程背景色 * 可编程 HSync、VSync 和数据使能(DE)信号的极性 * 每层有多达 8 种颜色格式可供选择:ARGB8888、RGB888、RGB565、ARGB1555、ARGB4444、L8(8 位 Luminance 或 CLUT)、AL44(4 位 alpha+4 位 luminance)和 AL88(8 位 alpha+8位 luminance) * 每通道的低位采用伪随机抖动输出(红色、绿色、蓝色的抖动宽度为 2 位) * 使用 alpha 值(每像素或常数)在两层之间灵活混合 * 色键(透明颜色) * 可编程窗口位置和大小 * 支持薄膜晶体管 (TFT) 彩色显示器 * AXI 主接口支持 16 个双字的突发 * 高达 4 个可编程中断事件 LTDC 控制器主要包含:信号线、图像处理单元、AXI 接口、配置和状态寄存器以及时钟部分,其框图如下所示: {{ :icore4t:iCore4T_ARM_HAL_60_1.png?direct |}} === 2.LCD的DE同步模式和HV同步模式 === 通常,STM32H7都是用SDRAM作为LCD的显存,LTDC控制器会从SDRAM读取数据刷新到LCD显示屏上。刷新模式有DE同步模式和HV同步模式两种。一般大分辨率显示屏用DE同步模式,小分辨率的显示屏用HV同步模式。 * DE同步模式 DE模式需要LCD_DE和LCD_CLK信号来控制刷新。比如一个800x480分辨率的裸屏,在DE有效信号的时候(高电平或低电平),就有800个LCD_CLK输出时钟来确认行中800个点。每个时钟有效的时候,从显存读取一次RGB数据。因为存在回扫信号,所以DE是个方波。一个周期的LCD_DE信号,裸屏就扫描一行。扫描480行后,又从第一行扫描开始。这个规律由裸屏的驱动IC所决定的。 * HV同步模式 HV模式需要LCD_CLK时钟信号,行同步信号LCD_HSYNC和场同步信号LCD_VSYNC来控制刷新。比如一个480x272分辨率的裸屏,有一个行同步信号LCD_HSYNC产生时(高电平或者低电平脉冲),就有480个LCD_CLK输出时钟来确认行中480个点。每个时钟有效的时候,从显存读取一次RGB数据。再来一个行同步信号LCD_HSYNC产生时(高电平或者低电平脉冲),切换到下一行,继续行同步和时钟输出,扫描272行后,发送一个场同步信号LCD_VSYNC,又重新从第一行扫描开始。 === 3.LTDC的时序配置 === {{ :icore4t:iCore4T_ARM_HAL_60_2.png?direct |}} LTDC的时序控制就是下面几个参数的设置,这几个参数都可以通过寄存器进行配置。 * HSYNC width水平同步宽度设置,以LCD_CLK的像素时钟输出为单位。 * HBP(horizontal back porch period)水平后沿周期设置,以LCD_CLK的像素时钟输出为单位。 * Active width有效宽度设置,以LCD_CLK的像素时钟输出为单位。以480*272分辨率为例,Active width = 480。 * HFP(horizontal front porch period)水平前沿周期设置,以LCD_CLK的像素时钟输出为单位。 * VSYNC width垂直同步宽度设置,以LCD_CLK的像素时钟输出为单位。 * VBP(vertical back porch period)垂直后沿周期设置,以LCD_CLK的像素时钟输出为单位。 * Active height有效高度设置,以LCD_CLK的像素时钟输出为单位。以480*272分辨率为例,Active height = 272。 * VFP(vertical front porch period)垂直前沿周期设置,以LCD_CLK的像素时钟输出为单位。 === 4.窗口 === 可为每个层定位和调整大小,各个层必须位于有效显示区域内。 窗口位置和大小通过左上和右下的 X/Y 位置以及包含同步、后沿大小和有效数据区域的内部时序发生器配置。 可编程层位置和大小定义了一行中的第一个/最后一个可见像素和窗口中的第一个/最后一个可见行。它允许显示完整的图像帧,也允许只显示图像帧的一部分。 * 层中的第一个和最后一个可见像素通过配置 LTDC_LxWHPCR 寄存器中WHSTPOS[11:0] 和WHSPPOS[11:0] 进行设置。 * 层中的第一个和最后一个可见行通过配置 LTDC_LxWVPCR 寄存器中的 WVSTPOS[10:0] 和 WVSPPOS[10:0] 进行设置。 {{ :icore4t:iCore4T_ARM_HAL_60_3.png?direct |}} === 5.LTDC层混合 === LTDC除了图层1和图层2两个硬件图层以外,还有一个背景层。由于背景层的刷新不需要显存空间,所以可以用这个图层验证LTDC时序配置是否有问题。 {{ :icore4t:iCore4T_ARM_HAL_60_4.png?direct |}} 背景层仅支持单色设置,固定颜色格式RGB888(LTDC_HandleTypeDef hltdc)我们这里将背景设置为白色: hltdc.Init.Backcolor.Blue = 255 hltdc.Init.Backcolor.Green = 255 hltdc.Init.Backcolor.Red = 255 对于图层1和图层2来说,支持如下8种颜色格式: - ARGB8888 - RGB888 - RGB565 - ARGB1555 - ARGB4444 - L8(8 位 Luminance 或 CLUT) - AL44(4 位 alpha + 4 位 luminance) - AL88(8 位 alpha + 8 位 luminance) 实现Alpha混合的关键是要有一个变量可以设置各种透明度。对此,STM32H7准备了两个Alpha供使用: * 一个是常数Alpha(0x00表示完全透明,0xFF表示完全不透明),所有颜色格式都可以使用。 * 另一个是像素Alpha,也就是ARGB8888,ARGB1555,ARGB4444等颜色格式的Alpha通道数值,也就是我们为图层每个位置绘制的实际颜色值。 STM32H7的参考手册给出了具体的混合公式: BC = BF1 x C + BF2 x Cs 混合后的颜色= 混合系数1 x 当前层颜色 + 混合系数2 x 底层混合后的颜色 ==== 四、 实验程序 ==== === 1.主函数 === int main(void) { int i; HAL_Init(); /* Configure the system clock */ SystemClock_Config(); /* USER CODE BEGIN SysInit */ i2c.initialize(); //I2C初始化 axp152.initialize(); //电源芯片配置 axp152.set_dcdc1(3500);//[ARM & FPGA BK1/2/6 &OTHER] axp152.set_dcdc2(1200);//[FPGA INT & PLL D] axp152.set_aldo1(2500);//[FPGA PLL A] axp152.set_dcdc4(3300);//[POWER_OUTPUT] axp152.set_dcdc3(3300);//[FPGA BK4][Adjustable] axp152.set_aldo2(3300);//[FPGA BK3][Adjustable] axp152.set_dldo1(3300);//[FPGA BK7][Adjustable] axp152.set_dldo2(3300);//[FPGA BK5][Adjustable] HAL_Delay(500); /* USER CODE END SysInit */ /* Initialize all configured peripherals */ MX_GPIO_Init(); //GPIO初始化 MX_FMC_Init(); //FMC初始化 MX_LTDC_Init(); //LTDC初始化 MX_TIM12_Init(); //TIM12初始化 BSP_SDRAM_Init(); //SDRAM初始化 HAL_TIM_PWM_Start(&htim12,TIM_CHANNEL_1); //定时器使能,通道1 LED_ON; //帧缓冲区地址映射二维数组 for(i = 0;i < LCD_HEIGHT;i ++)address_sdram[i] = LCD_SDRAM_ADDRESS + (i * LCD_WIDTH) * 2; demo(); //运行弹球demo LCD_ON; while (1) { } } === 2.弹球demo函数 === void demo(void){ int bg = WHITE; //背景色 int colo[7] = {RED,BLUE,YELLOW,GREEN,0x7BEF,0x0000,0x03E0};//颜色列表 int x=35,y=35,xs=1,ys=2; //圆心起始坐标,速度的xy分量 int oldx,oldy,co=0,i,j; int r=30; //圆半径 clear_screen(bg); draw_circle(x, y, r, RED, 1); while(1){ oldx = x; oldy = y; x = x + xs; y = y + ys; if((x+r)>=480 || (x-r)<=0){ xs=-1*xs; x = x + 2*xs; co++; if(co==7)co=0; } if((y+r)>=272 || (y-r)<=0){ ys=-1*ys; y = y + 2*ys; co++; if(co==7)co=0; } draw_circle(x, y, r, colo[co], 1); //画圆 for(j = oldx-r-2;j < oldx+r+2;j ++){ for(i = oldy-r-2;i < oldy+r+2;i ++){ if(j<1 || j>479 || i<1 || i>271)continue; if( (int)(x-j)*(x-j) + (int)(y-i)*(y-i) > (int)r*r ){ *(volatile unsigned short int *) (address_sdram[i] + (j << 1)) = bg; }}} HAL_Delay(6); //延时 } } === 3.LTDC驱动配置 === void MX_LTDC_Init(void) { LTDC_LayerCfgTypeDef pLayerCfg = {0}; LTDC_LayerCfgTypeDef pLayerCfg1 = {0}; hltdc.Instance = LTDC; hltdc.Init.HSPolarity = LTDC_HSPOLARITY_AL; //水平同步极性 hltdc.Init.VSPolarity = LTDC_VSPOLARITY_AL; //垂直同步极性 hltdc.Init.DEPolarity = LTDC_DEPOLARITY_AL; //数据使能极性 hltdc.Init.PCPolarity = LTDC_PCPOLARITY_IPC; //像素时钟极性 hltdc.Init.HorizontalSync = 0; //水平同步宽度 hltdc.Init.VerticalSync = 0; //垂直同步宽度 hltdc.Init.AccumulatedHBP = 20; //水平同步后沿宽度 hltdc.Init.AccumulatedVBP = 9; //垂直同步后沿高度 hltdc.Init.AccumulatedActiveW = 500;//有效宽度 hltdc.Init.AccumulatedActiveH = 281;//有效高度 hltdc.Init.TotalWidth = 524; //总宽度 hltdc.Init.TotalHeigh = 287; //总高度 hltdc.Init.Backcolor.Blue = 255; //背景RGB数值,白色 hltdc.Init.Backcolor.Green = 255; hltdc.Init.Backcolor.Red = 255; if (HAL_LTDC_Init(&hltdc) != HAL_OK) {Error_Handler();} pLayerCfg.WindowX0 = 0; //屏幕像素宽 pLayerCfg.WindowX1 = 480; pLayerCfg.WindowY0 = 0; //屏幕像素高 pLayerCfg.WindowY1 = 272; pLayerCfg.PixelFormat = LTDC_PIXEL_FORMAT_RGB565; //屏幕格式 pLayerCfg.Alpha = 0xff; //透明度,不透明 pLayerCfg.Alpha0 = 0; //默认透明度 pLayerCfg.BlendingFactor1 = LTDC_BLENDING_FACTOR1_CA; pLayerCfg.BlendingFactor2 = LTDC_BLENDING_FACTOR2_CA; pLayerCfg.FBStartAdress = 0xC0000000; //帧缓冲区起始地址 pLayerCfg.ImageWidth = 480; //图层宽 pLayerCfg.ImageHeight = 272; //图层高 pLayerCfg.Backcolor.Blue = 255; //图层背景RGB数值,白色 pLayerCfg.Backcolor.Green = 255; pLayerCfg.Backcolor.Red = 255; if (HAL_LTDC_ConfigLayer(&hltdc, &pLayerCfg, 0) != HAL_OK) { Error_Handler();} } === 4.画点函数 === int set_pixel(int x, int y, int color) { if(x<0 || x>480 || y<0 || y>272)return 0; *(volatile unsigned short int *) (address_sdram[y] + (x << 1)) = color; return 1; } === 5.清屏函数 === void clear_screen(int color) { int i,j; for(j = 0;j < LCD_WIDTH;j ++){ for(i = 0;i < LCD_HEIGHT;i ++){ *(volatile unsigned short int *) (address_sdram[i] + (j << 1)) = color; }}} === 6.画圆函数 === int draw_circle(int x, int y, int r, int color, int fill) { int i,j; if(x<0 || x>480 || y<0 || y>272)return 0; for(j = x-r;j < x+r;j ++){ for(i = y-r;i < y+r;i ++){ if(fill == 1){ if( (int)(x-j)*(x-j) + (int)(y-i)*(y-i) <= (int)r*r ){ *(volatile unsigned short int *) (address_sdram[i] + (j << 1)) = color; } } else{ if( (x-i)*(x-i) + (y-j)*(y-j) >= (r-2)*(r) && (x-i)*(x-i) + (y-j)*(y-j) <= (r+1)*(r) ){ *(volatile unsigned short int *) (address_sdram[i] + (j << 1)) = color; } } } } return 1; } ==== 五、 实验步骤 ==== - 把仿真器与iCore4T的SWD调试口相连(直接相连或者通过转接器相连); - 把iCore4T通过Micro USB线与计算机相连,为iCore4T供电; - 将屏幕连接到4.3寸液晶屏底板上,并将液晶屏底板与iCore4T底板通过排线相连。 - 打开Keil MDK 开发环境,并打开本实验工程; - 烧写程序到iCore4T上; - 也可以进入Debug 模式,单步运行或设置断点验证程序逻辑。 ==== 六、 实验现象 ==== 有一个小球在屏幕中来回弹,触碰到边界时小球颜色改变。