| **银杏科技有限公司旗下技术文档发布平台** ||||
|技术支持电话|**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 模式,单步运行或设置断点验证程序逻辑。
==== 六、 实验现象 ====
有一个小球在屏幕中来回弹,触碰到边界时小球颜色改变。