这篇测试下开发板上的LCD显示屏,显示缓存使用上篇测试的SDRAM存储器。
一、电路硬件部分
LCD显示屏硬件电路图部分
看到显示部分电路有很多跳线帽,是显示屏引脚复用功能选择。板卡默认调试是显示屏功能。
二、TFT-LCD (TLI)接口介绍
2.1、简介
TLI(TFT-LCD接口)连接同步的LCD接口,并且为无源LCD显示屏提供像素数据,时钟以及时序信号。它支持不同的完全可编程的时序参数显示。一个内嵌的DMA不断的从系统存储器搬移数据到TLI然后输出到外部的LCD显示。 TLI支持两个独立的显示层,并支持层窗口和层混叠功能。
2.2、特点
每像素最多24位并行数据输出;
支持高达2048*2048的分辨率;
完全可编程的时序参数;
内嵌DMA处理像素数据拷贝;
带有窗口和混合功能的两个独立的层;
支持多种像素格式: ARGB8888, RGB888, RGB565等;
支持CLUT(颜色查找表)和色键格式;
像素低位的抖动操作。
2.3、结构框图
2.4、显示时序图
2.5、混合过程框图
TLI每层都支持窗口功能以及两层的混合功能,可将两层混合成一帧。
三、程序部分
3.1、lcd.c
#include "gd32h7xx.h"
#include "lcd/tli_lcd.h"
#include "exmc/exmc_sdram.h"
#include "lcd/font.h"
#define BACK_FRAME_START_ADDR SDRAM_DEVICE0_ADDR
#define FORE_FRAME_START_ADDR ((u32)(BACK_FRAME_START_ADDR + (LCD_PIXEL_WIDTH + 1) * LCD_PIXEL_HEIGHT * 2))
static u16 s_arrBackgroundFrame[(LCD_PIXEL_WIDTH + 1) * LCD_PIXEL_HEIGHT] __attribute__((at(BACK_FRAME_START_ADDR)));
static u16 s_arrForegroundFrame[(LCD_PIXEL_WIDTH + 1) * LCD_PIXEL_HEIGHT] __attribute__((at(FORE_FRAME_START_ADDR)));
StructTLILCDDev g_structTLILCDDev;
//设置层窗口
void LCDLayerWindowSet(EnumTLILCDLayer layer, u32 x, u32 y, u32 width, u32 height)
{
tli_layer_parameter_struct tli_layer_init_struct;
u32 swap, x0, y0;
tli_layer_struct_para_init(&tli_layer_init_struct);
if(LCD_SCREEN_VERTICAL == g_structTLILCDDev.dir)
{
x0 = x;
y0 = y + height - 1;
y = x0;
x = LCD_PIXEL_WIDTH - 1 - y0;
if(x >= LCD_PIXEL_WIDTH){return;}
if(y >= LCD_PIXEL_HEIGHT){return;}
swap = width;
width = height;
height = swap;
}
if((x + width) > LCD_PIXEL_WIDTH)
{
width = LCD_PIXEL_WIDTH - x;
}
if((y + height) > LCD_PIXEL_HEIGHT)
{
height = LCD_PIXEL_HEIGHT - y;
}
if(LCD_LAYER_BACKGROUND == layer)
{
tli_layer_init_struct.layer_window_leftpos = (x + HORIZONTAL_SYNCHRONOUS_PULSE + HORIZONTAL_BACK_PORCH);
tli_layer_init_struct.layer_window_rightpos = (x + width + HORIZONTAL_SYNCHRONOUS_PULSE + HORIZONTAL_BACK_PORCH - 1);
tli_layer_init_struct.layer_window_toppos = (y + VERTICAL_SYNCHRONOUS_PULSE + VERTICAL_BACK_PORCH);
tli_layer_init_struct.layer_window_bottompos = (y + height + VERTICAL_SYNCHRONOUS_PULSE + VERTICAL_BACK_PORCH - 1);
tli_layer_init_struct.layer_ppf = LAYER_PPF_RGB565;
tli_layer_init_struct.layer_sa = 0xFF;
tli_layer_init_struct.layer_default_blue = 0xFF;
tli_layer_init_struct.layer_default_green = 0xFF;
tli_layer_init_struct.layer_default_red = 0xFF;
tli_layer_init_struct.layer_default_alpha = 0xFF;
tli_layer_init_struct.layer_acf1 = LAYER_ACF1_PASA;
tli_layer_init_struct.layer_acf2 = LAYER_ACF2_PASA;
tli_layer_init_struct.layer_frame_bufaddr = (u32)s_arrBackgroundFrame;
tli_layer_init_struct.layer_frame_line_length = ((width * 2) + 3);
tli_layer_init_struct.layer_frame_buf_stride_offset = (width * 2);
tli_layer_init_struct.layer_frame_total_line_number = height;
tli_layer_init(LAYER0, &tli_layer_init_struct);
tli_color_key_disable(LAYER0);
tli_lut_disable(LAYER0);
if(LCD_SCREEN_HORIZONTAL == g_structTLILCDDev.dir)
{
g_structTLILCDDev.width[LCD_LAYER_BACKGROUND] = width;
g_structTLILCDDev.height[LCD_LAYER_BACKGROUND] = height;
}
else if(LCD_SCREEN_VERTICAL == g_structTLILCDDev.dir)
{
g_structTLILCDDev.width[LCD_LAYER_BACKGROUND] = height;
g_structTLILCDDev.height[LCD_LAYER_BACKGROUND] = width;
}
}
else if(LCD_LAYER_FOREGROUND == layer)
{
tli_layer_init_struct.layer_window_leftpos = (x + HORIZONTAL_SYNCHRONOUS_PULSE + HORIZONTAL_BACK_PORCH);
tli_layer_init_struct.layer_window_rightpos = (x + width + HORIZONTAL_SYNCHRONOUS_PULSE + HORIZONTAL_BACK_PORCH - 1);
tli_layer_init_struct.layer_window_toppos = (y + VERTICAL_SYNCHRONOUS_PULSE + VERTICAL_BACK_PORCH);
tli_layer_init_struct.layer_window_bottompos = (y + height + VERTICAL_SYNCHRONOUS_PULSE + VERTICAL_BACK_PORCH - 1);
tli_layer_init_struct.layer_ppf = LAYER_PPF_RGB565;
tli_layer_init_struct.layer_sa = 0xFF;
tli_layer_init_struct.layer_default_blue = 0xFF;
tli_layer_init_struct.layer_default_green = 0xFF;
tli_layer_init_struct.layer_default_red = 0xFF;
tli_layer_init_struct.layer_default_alpha = 0x00;
tli_layer_init_struct.layer_acf1 = LAYER_ACF1_PASA;
tli_layer_init_struct.layer_acf2 = LAYER_ACF2_PASA;
tli_layer_init_struct.layer_frame_bufaddr = (u32)s_arrForegroundFrame;
tli_layer_init_struct.layer_frame_line_length = ((width * 2) + 3);
tli_layer_init_struct.layer_frame_buf_stride_offset = (width * 2);
tli_layer_init_struct.layer_frame_total_line_number = height;
tli_layer_init(LAYER1, &tli_layer_init_struct);
tli_color_key_disable(LAYER1);
tli_lut_disable(LAYER1);
if(LCD_SCREEN_HORIZONTAL == g_structTLILCDDev.dir)
{
g_structTLILCDDev.width[LCD_LAYER_FOREGROUND] = width;
g_structTLILCDDev.height[LCD_LAYER_FOREGROUND] = height;
}
else if(LCD_SCREEN_VERTICAL == g_structTLILCDDev.dir)
{
g_structTLILCDDev.width[LCD_LAYER_FOREGROUND] = height;
g_structTLILCDDev.height[LCD_LAYER_FOREGROUND] = width;
}
}
tli_reload_config(TLI_REQUEST_RELOAD_EN);
}
//使能背景或前景层
void LCDLayerEnable(EnumTLILCDLayer layer)
{
if(LCD_LAYER_BACKGROUND == layer)
{
tli_layer_enable(LAYER0);
}
else if(LCD_LAYER_FOREGROUND == layer)
{
tli_layer_enable(LAYER1);
}
tli_reload_config(TLI_REQUEST_RELOAD_EN);
}
//禁用背景或前景层
void LCDLayerDisable(EnumTLILCDLayer layer)
{
if(LCD_LAYER_BACKGROUND == layer)
{
tli_layer_disable(LAYER0);
}
else if(LCD_LAYER_FOREGROUND == layer)
{
tli_layer_disable(LAYER1);
}
tli_reload_config(TLI_REQUEST_RELOAD_EN);
}
//切换层
void LCDLayerSwitch(EnumTLILCDLayer layer)
{
if(LCD_LAYER_BACKGROUND == layer)
{
g_structTLILCDDev.frameBuf = s_arrBackgroundFrame;
g_structTLILCDDev.currentLayer = LCD_LAYER_BACKGROUND;
}
else
{
g_structTLILCDDev.frameBuf = s_arrForegroundFrame;
g_structTLILCDDev.currentLayer = LCD_LAYER_FOREGROUND;
}
}
//设置当前层的透明度
void LCDTransparencySet(EnumTLILCDLayer layer, u8 trans)
{
if (LCD_LAYER_BACKGROUND == layer)
{
TLI_LXSA(LAYER0) &= ~(TLI_LXSA_SA);
TLI_LXSA(LAYER0) = trans;
}
else
{
TLI_LXSA(LAYER1) &= ~(TLI_LXSA_SA);
TLI_LXSA(LAYER1) = trans;
}
tli_reload_config(TLI_REQUEST_RELOAD_EN);
}
//开启LCD显示
void LCDDisplayOn(void)
{
tli_enable();
}
//关闭LCD显示
void LCDDisplayOff(void)
{
tli_disable();
}
//等待LCD行传输空闲
void LCDWaitHIdle(void)
{
while(RESET == tli_flag_get(TLI_FLAG_HDE));
while(SET == tli_flag_get(TLI_FLAG_HDE));
}
//等待LCD场传输空闲
void LCDWaitVIdle(void)
{
while(RESET == tli_flag_get(TLI_FLAG_VDE));
while(SET == tli_flag_get(TLI_FLAG_VDE));
}
//设置LCD显示方向
void LCDDisplayDir(EnumTLILCDDir dir)
{
u32 swap;
if(g_structTLILCDDev.dir != dir)
{
g_structTLILCDDev.dir = dir;
swap = g_structTLILCDDev.width[LCD_LAYER_BACKGROUND];
g_structTLILCDDev.width[LCD_LAYER_BACKGROUND] = g_structTLILCDDev.height[LCD_LAYER_BACKGROUND];
g_structTLILCDDev.height[LCD_LAYER_BACKGROUND] = swap;
swap = g_structTLILCDDev.width[LCD_LAYER_FOREGROUND];
g_structTLILCDDev.width[LCD_LAYER_FOREGROUND] = g_structTLILCDDev.height[LCD_LAYER_FOREGROUND];
g_structTLILCDDev.height[LCD_LAYER_FOREGROUND] = swap;
}
}
//清屏
void LCDClear(u32 color)
{
ipa_destination_parameter_struct ipa_destination_init_struct;
u8 red, green, blue;
RGB565ToRGB888A(color, &red, &green, &blue);
rcu_periph_clock_enable(RCU_IPA);
ipa_deinit();
ipa_pixel_format_convert_mode_set(IPA_FILL_UP_DE);
//设置目标图像参数
ipa_destination_struct_para_init(&ipa_destination_init_struct);
ipa_destination_init_struct.destination_pf = IPA_DPF_RGB565;
ipa_destination_init_struct.destination_memaddr = (u32)g_structTLILCDDev.frameBuf;
ipa_destination_init_struct.destination_lineoff = 0;
ipa_destination_init_struct.destination_prealpha = 0xFF;
ipa_destination_init_struct.destination_prered = red;
ipa_destination_init_struct.destination_pregreen = green;
ipa_destination_init_struct.destination_preblue = blue;
ipa_destination_init_struct.image_width = LCD_PIXEL_WIDTH;
ipa_destination_init_struct.image_height = LCD_PIXEL_HEIGHT;
ipa_destination_init(&ipa_destination_init_struct);
// //使能IPA内部定时器
// ipa_interval_clock_num_config(0);
// ipa_inter_timer_config(IPA_INTER_TIMER_ENABLE);
ipa_transfer_enable();
while(RESET == ipa_interrupt_flag_get(IPA_INT_FLAG_FTF));
ipa_interrupt_flag_clear(IPA_INT_FLAG_FTF);
ipa_deinit();
}
//画点
void LCDDrawPoint(u32 x, u32 y, u32 color)
{
u32 width, height;
width = g_structTLILCDDev.width[g_structTLILCDDev.currentLayer];
height = g_structTLILCDDev.height[g_structTLILCDDev.currentLayer];
if(x >= width || y >= height)
{
return;
}
if(LCD_SCREEN_HORIZONTAL == g_structTLILCDDev.dir)
{
g_structTLILCDDev.frameBuf[width * y + x] = color;
}
else
{
g_structTLILCDDev.frameBuf[height * x + (height - 1 - y)] = color;
}
}
//读点
u32 LCDReadPoint(u32 x, u32 y)
{
u32 width, height;
width = g_structTLILCDDev.width[g_structTLILCDDev.currentLayer];
height = g_structTLILCDDev.height[g_structTLILCDDev.currentLayer];
if(x >= width || y >= height)
{
return 0;
}
if(LCD_SCREEN_HORIZONTAL == g_structTLILCDDev.dir)
{
return g_structTLILCDDev.frameBuf[width * y + x];
}
else
{
return g_structTLILCDDev.frameBuf[height * x + (height - 1 - y)];
}
}
//LCD填充
void LCDFill(u32 x, u32 y, u32 width, u32 height, u32 color)
{
ipa_destination_parameter_struct ipa_destination_init_struct;
u32 destStartAddr;
u32 phyWidth, phyHeight;
u32 phyX, phyY;
u32 lineOff;
u32 swap;
u8 red, green, blue;
u32 x1, y1, x2, y2, color1, color2;
if(LCD_SCREEN_HORIZONTAL == g_structTLILCDDev.dir)
{
phyWidth = g_structTLILCDDev.width[g_structTLILCDDev.currentLayer];
phyHeight = g_structTLILCDDev.height[g_structTLILCDDev.currentLayer];
phyX = x;
phyY = y;
}
else if(LCD_SCREEN_VERTICAL == g_structTLILCDDev.dir)
{
phyWidth = g_structTLILCDDev.width[g_structTLILCDDev.currentLayer];
phyHeight = g_structTLILCDDev.height[g_structTLILCDDev.currentLayer];
swap = phyWidth;
phyWidth = phyHeight;
phyHeight = swap;
swap = width;
width = height;
height = swap;
phyX = phyWidth - y - width;
phyY = x;
}
if((phyX + width) > LCD_PIXEL_WIDTH)
{
width = LCD_PIXEL_WIDTH - phyX;
}
if((phyY + height) > LCD_PIXEL_HEIGHT)
{
height = LCD_PIXEL_HEIGHT - phyY;
}
if(LCD_SCREEN_HORIZONTAL == g_structTLILCDDev.dir)
{
x1 = phyX;
x2 = x1 + 1;
y1 = phyY + height;
y2 = y1;
}
else if(LCD_SCREEN_VERTICAL == g_structTLILCDDev.dir)
{
x1 = x + height;
x2 = x1;
y1 = y + width - 1;
y2 = y1 - 1;
}
color1 = LCDReadPoint(x1, y1);
color2 = LCDReadPoint(x2, y2);
destStartAddr = (u32)g_structTLILCDDev.frameBuf + g_structTLILCDDev.pixelSize * (phyWidth * phyY + phyX);
lineOff = phyWidth - width;
RGB565ToRGB888A(color, &red, &green, &blue);
rcu_periph_clock_enable(RCU_IPA);
ipa_deinit();
ipa_pixel_format_convert_mode_set(IPA_FILL_UP_DE);
//设置目标图像参数
ipa_destination_struct_para_init(&ipa_destination_init_struct);
ipa_destination_init_struct.destination_pf = IPA_DPF_RGB565;
ipa_destination_init_struct.destination_memaddr = destStartAddr;
ipa_destination_init_struct.destination_lineoff = lineOff;
ipa_destination_init_struct.destination_prealpha = 0xFF;
ipa_destination_init_struct.destination_prered = red;
ipa_destination_init_struct.destination_pregreen = green;
ipa_destination_init_struct.destination_preblue = blue;
ipa_destination_init_struct.image_width = width;
ipa_destination_init_struct.image_height = height;
ipa_destination_init(&ipa_destination_init_struct);
// //使能IPA内部定时器
// ipa_interval_clock_num_config(0);
// ipa_inter_timer_config(IPA_INTER_TIMER_ENABLE);
ipa_transfer_enable();
while(RESET == ipa_interrupt_flag_get(IPA_INT_FLAG_FTF));
ipa_interrupt_flag_clear(IPA_INT_FLAG_FTF);
ipa_deinit();
LCDDrawPoint(x1, y1, color1);
LCDDrawPoint(x2, y2, color2);
}
//LCD填充
void LCDFillPixel(u32 x0, u32 y0, u32 x1, u32 y1, u32 color)
{
u32 swap, width, height;
if(x0 > x1)
{
swap = x0;
x0 = x1;
x1 = swap;
}
if(y0 > y1)
{
swap = y0;
y0 = y1;
y1 = swap;
}
width = x1 - x0 + 1;
height = y1 - y0 + 1;
LCDFill(x0, y0, width, height, color);
}
void LCDColorFill(u32 x, u32 y, u32 width, u32 height, u16* color)
{
u32 x0, y0, i;
x0 = x;
y0 = y;
i = 0;
for(y = y0; y < y0 + height; y++)
{
for(x = x0; x < x0 + width; x++)
{
LCDDrawPoint(x, y, color[i]);
i++;
}
}
}
void LCDColorFillPixel(u32 x0, u32 y0, u32 x1, u32 y1, u16* color)
{
u32 x, y, swap, i;
if(x0 > x1)
{
swap = x0;
x0 = x1;
x1 = swap;
}
if(y0 > y1)
{
swap = y0;
y0 = y1;
y1 = swap;
}
i = 0;
for(y = y0; y <= y1; y++)
{
for(x = x0; x <= x1; x++)
{
LCDDrawPoint(x, y, color[i]);
i++;
}
}
}
void LCDDrawLine(u32 x0, u32 y0, u32 x1, u32 y1, u32 color)
{
int x, y, dx, dy, dx2, dy2, xStep, yStep, swap, sum;
dx = x1 - x0;
dy = y1 - y0;
if(dx < 0){dx = -dx;}
if(dy < 0){dy = -dy;}
dx2 = dx << 1;
dy2 = dy << 1;
if(dx >= dy)
{
if(x0 > x1)
{
swap = x0; x0 = x1; x1 = swap;
swap = y0; y0 = y1; y1 = swap;
}
if(y1 > y0){yStep = 1;}else{yStep = -1;}
x = x0;
y = y0;
sum = -dx;
while(x <= x1)
{
LCDDrawPoint(x, y, color);
x = x + 1;
sum = sum + dy2;
if(sum >= 0)
{
sum = sum - dx2;
y = y + yStep;
}
}
}
else
{
if(y0 > y1)
{
swap = x0; x0 = x1; x1 = swap;
swap = y0; y0 = y1; y1 = swap;
}
if(x1 > x0){xStep = 1;}else{xStep = -1;}
x = x0;
y = y0;
sum = -dy;
while(y <= y1)
{
LCDDrawPoint(x, y, color);
y = y + 1;
sum = sum + dx2;
if(sum >= 0)
{
sum = sum - dy2;
x = x + xStep;
}
}
}
}
void LCDDrawRectangle(u32 x1, u32 y1, u32 x2, u32 y2, u32 color)
{
LCDDrawLine(x1, y1, x2, y1, color);
LCDDrawLine(x1, y1, x1, y2, color);
LCDDrawLine(x1, y2, x2, y2, color);
LCDDrawLine(x2, y1, x2, y2, color);
}
void LCDDrawCircle(u32 x0, u32 y0, u32 r, u32 color)
{
int x, y, d;
x = 0;
y = r;
d = 5 - (r << 2);
while(x <= y)
{
LCDDrawPoint(x0 + x, y0 + y, color);
LCDDrawPoint(x0 + x, y0 - y, color);
LCDDrawPoint(x0 - x, y0 + y, color);
LCDDrawPoint(x0 - x, y0 - y, color);
LCDDrawPoint(x0 + y, y0 + x, color);
LCDDrawPoint(x0 - y, y0 + x, color);
LCDDrawPoint(x0 + y, y0 - x, color);
LCDDrawPoint(x0 - y, y0 - x, color);
x++;
if(d < 0)
{
d = d + (x << 3) + 12;
}
else
{
d = d + ((x - y) << 3) + 20;
y--;
}
}
}
void LCDShowChar(u32 x, u32 y, EnumTLILCDFont font, EnumTLILCDTextMode mode, u32 textColor, u32 backColor, u32 code)
{
u8 byte;
u32 i, j;
u32 y0;
u32 height;
u32 bufSize;
u8* enBuf;
u8* codeBuf;
switch (font)
{
case LCD_FONT_12: height = 12; break;
case LCD_FONT_16: height = 16; break;
case LCD_FONT_24: height = 24; break;
default: return;
}
switch (font)
{
case LCD_FONT_12: bufSize = 12; break;
case LCD_FONT_16: bufSize = 16; break;
case LCD_FONT_24: bufSize = 36; break;
default: return;
}
switch (font)
{
case LCD_FONT_12: enBuf = (u8*)asc2_1206[code - ' ']; break;
case LCD_FONT_16: enBuf = (u8*)asc2_1608[code - ' ']; break;
case LCD_FONT_24: enBuf = (u8*)asc2_2412[code - ' ']; break;
default: return;
}
codeBuf = enBuf;
y0 = y;
for(i = 0; i < bufSize; i++)
{
byte = codeBuf[i];
for(j = 0; j < 8; j++)
{
if(byte & 0x80)
{
LCDDrawPoint(x, y, textColor);
}
else if(LCD_TEXT_NORMAL == mode)
{
LCDDrawPoint(x, y, backColor);
}
byte <<= 1;
y++;
if(y >= g_structTLILCDDev.height[g_structTLILCDDev.currentLayer])
{
return;
}
if((y - y0) >= height)
{
y = y0;
x++;
if(x >= g_structTLILCDDev.width[g_structTLILCDDev.currentLayer])
{
return;
}
break;
}
}
}
}
void LCDShowString(u32 x, u32 y, u32 width, u32 height, EnumTLILCDFont font, EnumTLILCDTextMode mode, u32 textColor, u32 backColor, char* string)
{
u32 x0, x1, y1, cWidth, i, code;
x0 = x;
x1 = x0 + width - 1;
y1 = x1 + height - 1;
switch (font)
{
case LCD_FONT_12: cWidth = 6; break;
case LCD_FONT_16: cWidth = 8; break;
case LCD_FONT_24: cWidth = 12; break;
default: return;
}
i = 0;
while(0 != string[i])
{
if((u8)string[i] < 0x80) //ASCII码
{
LCDShowChar(x, y, font, mode, textColor, backColor, string[i]);
if((x + cWidth) > x1)
{
x = x0;
y = y + height;
if(y > y1)
{
return;
}
}
else
{
x = x + cWidth;
}
i = i + 1;
}
else
{
code = (string[i] << 8) | string[i + 1];
LCDShowChar(x, y, font, mode, textColor, backColor, code);
if((x + cWidth * 2) > x1)
{
x = x0;
y = y + height;
if(y > y1)
{
return;
}
}
else
{
x = x + cWidth * 2;
}
i = i + 2;
}
}
}
void LCDWindowSave(u32 x, u32 y, u32 width, u32 height, void* saveBuf)
{
ipa_foreground_parameter_struct ipa_fg_init_struct;
ipa_destination_parameter_struct ipa_destination_init_struct;
u32 foreStartAddr;
u32 phyWidth, phyHeight;
u32 phyX, phyY;
u32 lineOff;
u32 swap;
if(LCD_SCREEN_HORIZONTAL == g_structTLILCDDev.dir)
{
phyWidth = g_structTLILCDDev.width[g_structTLILCDDev.currentLayer];
phyHeight = g_structTLILCDDev.height[g_structTLILCDDev.currentLayer];
phyX = x;
phyY = y;
}
else if(LCD_SCREEN_VERTICAL == g_structTLILCDDev.dir)
{
phyWidth = g_structTLILCDDev.width[g_structTLILCDDev.currentLayer];
phyHeight = g_structTLILCDDev.height[g_structTLILCDDev.currentLayer];
swap = phyWidth;
phyWidth = phyHeight;
phyHeight = swap;
swap = width;
width = height;
height = swap;
phyX = phyWidth - y - width;
phyY = x;
}
if((phyX + width) > LCD_PIXEL_WIDTH)
{
width = LCD_PIXEL_WIDTH - phyX;
}
if((phyY + height) > LCD_PIXEL_HEIGHT)
{
height = LCD_PIXEL_HEIGHT - phyY;
}
foreStartAddr = (u32)g_structTLILCDDev.frameBuf + g_structTLILCDDev.pixelSize * (phyWidth * phyY + phyX);
lineOff = phyWidth - width;
rcu_periph_clock_enable(RCU_IPA);
ipa_deinit();
ipa_pixel_format_convert_mode_set(IPA_FGTODE);
//设置前景图像参数
ipa_foreground_struct_para_init(&ipa_fg_init_struct);
ipa_fg_init_struct.foreground_pf = FOREGROUND_PPF_RGB565;
ipa_fg_init_struct.foreground_memaddr = foreStartAddr;
ipa_fg_init_struct.foreground_lineoff = lineOff;
ipa_fg_init_struct.foreground_alpha_algorithm = IPA_FG_ALPHA_MODE_0;
ipa_fg_init_struct.foreground_prealpha = 0xFF;
ipa_fg_init_struct.foreground_prered = 0x00;
ipa_fg_init_struct.foreground_pregreen = 0x00;
ipa_fg_init_struct.foreground_preblue = 0x00;
ipa_foreground_init(&ipa_fg_init_struct);
//设置目标图像参数
ipa_destination_struct_para_init(&ipa_destination_init_struct);
ipa_destination_init_struct.destination_pf = IPA_DPF_RGB565;
ipa_destination_init_struct.destination_memaddr = (u32)saveBuf;
ipa_destination_init_struct.destination_lineoff = 0;
ipa_destination_init_struct.destination_prealpha = 0xFF;
ipa_destination_init_struct.destination_prered = 0x00;
ipa_destination_init_struct.destination_pregreen = 0x00;
ipa_destination_init_struct.destination_preblue = 0x00;
ipa_destination_init_struct.image_width = width;
ipa_destination_init_struct.image_height = height;
ipa_destination_init(&ipa_destination_init_struct);
// //使能IPA内部定时器
// ipa_interval_clock_num_config(0);
// ipa_inter_timer_config(IPA_INTER_TIMER_ENABLE);
ipa_transfer_enable();
while(RESET == ipa_interrupt_flag_get(IPA_INT_FLAG_FTF));
ipa_interrupt_flag_clear(IPA_INT_FLAG_FTF);
ipa_deinit();
}
void LCDWindowFill(u32 x, u32 y, u32 width, u32 height, void* imageBuf)
{
ipa_foreground_parameter_struct ipa_fg_init_struct;
ipa_destination_parameter_struct ipa_destination_init_struct;
u32 destStartAddr;
u32 phyWidth, phyHeight;
u32 phyX, phyY;
u32 lineOff;
u32 swap;
if(LCD_SCREEN_HORIZONTAL == g_structTLILCDDev.dir)
{
phyWidth = g_structTLILCDDev.width[g_structTLILCDDev.currentLayer];
phyHeight = g_structTLILCDDev.height[g_structTLILCDDev.currentLayer];
phyX = x;
phyY = y;
}
else if(LCD_SCREEN_VERTICAL == g_structTLILCDDev.dir)
{
phyWidth = g_structTLILCDDev.width[g_structTLILCDDev.currentLayer];
phyHeight = g_structTLILCDDev.height[g_structTLILCDDev.currentLayer];
swap = phyWidth;
phyWidth = phyHeight;
phyHeight = swap;
swap = width;
width = height;
height = swap;
phyX = phyWidth - y - width;
phyY = x;
}
if((phyX + width) > LCD_PIXEL_WIDTH)
{
width = LCD_PIXEL_WIDTH - phyX;
}
if((phyY + height) > LCD_PIXEL_HEIGHT)
{
height = LCD_PIXEL_HEIGHT - phyY;
}
destStartAddr = (u32)g_structTLILCDDev.frameBuf + g_structTLILCDDev.pixelSize * (phyWidth * phyY + phyX);
lineOff = phyWidth - width;
rcu_periph_clock_enable(RCU_IPA);
ipa_deinit();
ipa_pixel_format_convert_mode_set(IPA_FGTODE);
//设置前景图像参数
ipa_foreground_struct_para_init(&ipa_fg_init_struct);
ipa_fg_init_struct.foreground_pf = FOREGROUND_PPF_RGB565;
ipa_fg_init_struct.foreground_memaddr = (u32)imageBuf;
ipa_fg_init_struct.foreground_lineoff = 0;
ipa_fg_init_struct.foreground_alpha_algorithm = IPA_FG_ALPHA_MODE_0;
ipa_fg_init_struct.foreground_prealpha = 0xFF;
ipa_fg_init_struct.foreground_prered = 0x00;
ipa_fg_init_struct.foreground_pregreen = 0x00;
ipa_fg_init_struct.foreground_preblue = 0x00;
ipa_foreground_init(&ipa_fg_init_struct);
//设置目标图像参数
ipa_destination_struct_para_init(&ipa_destination_init_struct);
ipa_destination_init_struct.destination_pf = IPA_DPF_RGB565;
ipa_destination_init_struct.destination_memaddr = (u32)destStartAddr;
ipa_destination_init_struct.destination_lineoff = lineOff;
ipa_destination_init_struct.destination_prealpha = 0xFF;
ipa_destination_init_struct.destination_prered = 0x00;
ipa_destination_init_struct.destination_pregreen = 0x00;
ipa_destination_init_struct.destination_preblue = 0x00;
ipa_destination_init_struct.image_width = width;
ipa_destination_init_struct.image_height = height;
ipa_destination_init(&ipa_destination_init_struct);
// //使能IPA内部定时器
// ipa_interval_clock_num_config(0);
// ipa_inter_timer_config(IPA_INTER_TIMER_ENABLE);
ipa_transfer_enable();
while(RESET == ipa_interrupt_flag_get(IPA_INT_FLAG_FTF));
ipa_interrupt_flag_clear(IPA_INT_FLAG_FTF);
ipa_deinit();
}
void RGB565ToRGB888A(u16 rgb565, u8* r, u8* g, u8* b)
{
*r = ((0xF800 & rgb565) >> 11) & 0xFF;
*g = ((0x07E0 & rgb565) >> 5 ) & 0xFF;
*b = ((0x001F & rgb565) >> 0 ) & 0xFF;
}
u32 RGB565ToRGB888B(u16 rgb565)
{
u8 r, g, b;
r = ((0xF800 & rgb565) >> 11) & 0xFF;
g = ((0x07E0 & rgb565) >> 5 ) & 0xFF;
b = ((0x001F & rgb565) >> 0 ) & 0xFF;
return ((r << 16) | (g << 8) | (b << 0));
}
u32 RGB888ToRGB565A(u8 r, u8 g, u8 b)
{
r = r >> 3;
g = g >> 2;
b = b >> 3;
return ((r << 11) | (g << 5) | (b << 0));
}
u32 RGB888ToRGB565B(u32 rgb888)
{
u8 r, g, b;
r = (rgb888 >> 16) & 0xFF;
g = (rgb888 >> 8 ) & 0xFF;
b = (rgb888 >> 0 ) & 0xFF;
return RGB888ToRGB565A(r, g, b);
}
void init_lcd(void)
{
u32 i;
tli_parameter_struct tli_init_struct;
g_structTLILCDDev.pWidth = LCD_PIXEL_WIDTH;
g_structTLILCDDev.pHeight = LCD_PIXEL_HEIGHT;
g_structTLILCDDev.dir = LCD_SCREEN_HORIZONTAL;
g_structTLILCDDev.currentLayer = LCD_LAYER_BACKGROUND;
g_structTLILCDDev.frameBuf = s_arrBackgroundFrame;
g_structTLILCDDev.backFrameAddr = BACK_FRAME_START_ADDR;
g_structTLILCDDev.foreFrameAddr = FORE_FRAME_START_ADDR;
g_structTLILCDDev.pixelSize = 2;
for(i = 0; i < LCD_LAYER_MAX; i++)
{
g_structTLILCDDev.width[i] = g_structTLILCDDev.pWidth;
g_structTLILCDDev.height[i] = g_structTLILCDDev.pHeight;
}
rcu_periph_clock_enable(RCU_TLI);
rcu_periph_clock_enable(RCU_GPIOA);
rcu_periph_clock_enable(RCU_GPIOB);
rcu_periph_clock_enable(RCU_GPIOC);
rcu_periph_clock_enable(RCU_GPIOD);
rcu_periph_clock_enable(RCU_GPIOE);
rcu_periph_clock_enable(RCU_GPIOF);
rcu_periph_clock_enable(RCU_GPIOH);
rcu_periph_clock_enable(RCU_GPIOG);
/* configure HSYNC(PE15), VSYNC(PA7), PCLK(PG7) */
gpio_af_set(GPIOE, GPIO_AF_14, GPIO_PIN_15);
gpio_af_set(GPIOA, GPIO_AF_14, GPIO_PIN_7);
gpio_af_set(GPIOG, GPIO_AF_14, GPIO_PIN_7);
gpio_mode_set(GPIOE, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_15);
gpio_output_options_set(GPIOE, GPIO_OTYPE_PP, GPIO_OSPEED_60MHZ, GPIO_PIN_15);
gpio_mode_set(GPIOA, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_7);
gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_60MHZ, GPIO_PIN_7);
gpio_mode_set(GPIOG, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_7);
gpio_output_options_set(GPIOG, GPIO_OTYPE_PP, GPIO_OSPEED_60MHZ, GPIO_PIN_7);
/* configure LCD_R7(PG6), LCD_R6(PH12), LCD_R5(PH11), LCD_R4(PA5), LCD_R3(PH9),LCD_R2(PH8),
LCD_R1(PH3), LCD_R0(PH2) */
gpio_af_set(GPIOG, GPIO_AF_14, GPIO_PIN_6);
gpio_af_set(GPIOH, GPIO_AF_14, GPIO_PIN_12);
gpio_af_set(GPIOH, GPIO_AF_14, GPIO_PIN_11);
gpio_af_set(GPIOA, GPIO_AF_14, GPIO_PIN_5);
gpio_af_set(GPIOH, GPIO_AF_14, GPIO_PIN_9);
gpio_af_set(GPIOH, GPIO_AF_14, GPIO_PIN_8);
gpio_af_set(GPIOH, GPIO_AF_14, GPIO_PIN_3);
gpio_af_set(GPIOH, GPIO_AF_14, GPIO_PIN_2);
gpio_mode_set(GPIOG, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_6);
gpio_output_options_set(GPIOG, GPIO_OTYPE_PP, GPIO_OSPEED_60MHZ, GPIO_PIN_6);
gpio_mode_set(GPIOH, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_12);
gpio_output_options_set(GPIOH, GPIO_OTYPE_PP, GPIO_OSPEED_60MHZ, GPIO_PIN_12);
gpio_mode_set(GPIOH, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_11);
gpio_output_options_set(GPIOH, GPIO_OTYPE_PP, GPIO_OSPEED_60MHZ, GPIO_PIN_11);
gpio_mode_set(GPIOA, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_5);
gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_60MHZ, GPIO_PIN_5);
gpio_mode_set(GPIOH, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_9);
gpio_output_options_set(GPIOH, GPIO_OTYPE_PP, GPIO_OSPEED_60MHZ, GPIO_PIN_9);
gpio_mode_set(GPIOH, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_8);
gpio_output_options_set(GPIOH, GPIO_OTYPE_PP, GPIO_OSPEED_60MHZ, GPIO_PIN_8);
gpio_mode_set(GPIOH, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_3);
gpio_output_options_set(GPIOH, GPIO_OTYPE_PP, GPIO_OSPEED_60MHZ, GPIO_PIN_3);
gpio_mode_set(GPIOH, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_2);
gpio_output_options_set(GPIOH, GPIO_OTYPE_PP, GPIO_OSPEED_60MHZ, GPIO_PIN_2);
/* configure LCD_G7(PD3), LCD_G6(PC7), LCD_G5(PC1), LCD_G4(PH15), LCD_G3(PH14), LCD_G2(PH13),LCD_G1(PB0), LCD_G0(PB1) */
gpio_af_set(GPIOD, GPIO_AF_14, GPIO_PIN_3);
gpio_af_set(GPIOC, GPIO_AF_14, GPIO_PIN_7);
gpio_af_set(GPIOC, GPIO_AF_14, GPIO_PIN_1);
gpio_af_set(GPIOH, GPIO_AF_14, GPIO_PIN_15);
gpio_af_set(GPIOH, GPIO_AF_14, GPIO_PIN_14);
gpio_af_set(GPIOH, GPIO_AF_14, GPIO_PIN_13);
gpio_af_set(GPIOB, GPIO_AF_14, GPIO_PIN_0);
gpio_af_set(GPIOB, GPIO_AF_14, GPIO_PIN_1);
gpio_mode_set(GPIOD, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_3);
gpio_output_options_set(GPIOD, GPIO_OTYPE_PP, GPIO_OSPEED_60MHZ, GPIO_PIN_3);
gpio_mode_set(GPIOC, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_7);
gpio_output_options_set(GPIOC, GPIO_OTYPE_PP, GPIO_OSPEED_60MHZ, GPIO_PIN_7);
gpio_mode_set(GPIOC, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_1);
gpio_output_options_set(GPIOC, GPIO_OTYPE_PP, GPIO_OSPEED_60MHZ, GPIO_PIN_1);
gpio_mode_set(GPIOH, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_15);
gpio_output_options_set(GPIOH, GPIO_OTYPE_PP, GPIO_OSPEED_60MHZ, GPIO_PIN_15);
gpio_mode_set(GPIOH, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_14);
gpio_output_options_set(GPIOH, GPIO_OTYPE_PP, GPIO_OSPEED_60MHZ, GPIO_PIN_14);
gpio_mode_set(GPIOH, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_13);
gpio_output_options_set(GPIOH, GPIO_OTYPE_PP, GPIO_OSPEED_60MHZ, GPIO_PIN_13);
gpio_mode_set(GPIOB, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_0);
gpio_output_options_set(GPIOB, GPIO_OTYPE_PP, GPIO_OSPEED_60MHZ, GPIO_PIN_0);
gpio_mode_set(GPIOB, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_1);
gpio_output_options_set(GPIOB, GPIO_OTYPE_PP, GPIO_OSPEED_60MHZ, GPIO_PIN_1);
/* configure LCD_B7(PB9), LCD_B6(PB8), LCD_B5(PB5), LCD_B4(PC11), LCD_B3(PG11),LCD_B2(PG10), LCD_B1(PG12), LCD_B0(PG14) */
gpio_af_set(GPIOB, GPIO_AF_14, GPIO_PIN_9);
gpio_af_set(GPIOB, GPIO_AF_14, GPIO_PIN_8);
gpio_af_set(GPIOB, GPIO_AF_3, GPIO_PIN_5);
gpio_af_set(GPIOC, GPIO_AF_14, GPIO_PIN_11);
gpio_af_set(GPIOG, GPIO_AF_14, GPIO_PIN_11);
gpio_af_set(GPIOG, GPIO_AF_14, GPIO_PIN_10);
gpio_af_set(GPIOG, GPIO_AF_14, GPIO_PIN_12);
gpio_af_set(GPIOG, GPIO_AF_14, GPIO_PIN_14);
gpio_mode_set(GPIOB, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_9);
gpio_output_options_set(GPIOB, GPIO_OTYPE_PP, GPIO_OSPEED_60MHZ, GPIO_PIN_9);
gpio_mode_set(GPIOB, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_8);
gpio_output_options_set(GPIOB, GPIO_OTYPE_PP, GPIO_OSPEED_60MHZ, GPIO_PIN_8);
gpio_mode_set(GPIOB, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_5);
gpio_output_options_set(GPIOB, GPIO_OTYPE_PP, GPIO_OSPEED_60MHZ, GPIO_PIN_5);
gpio_mode_set(GPIOC, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_11);
gpio_output_options_set(GPIOC, GPIO_OTYPE_PP, GPIO_OSPEED_60MHZ, GPIO_PIN_11);
gpio_mode_set(GPIOG, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_11);
gpio_output_options_set(GPIOG, GPIO_OTYPE_PP, GPIO_OSPEED_60MHZ, GPIO_PIN_11);
gpio_mode_set(GPIOG, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_10);
gpio_output_options_set(GPIOG, GPIO_OTYPE_PP, GPIO_OSPEED_60MHZ, GPIO_PIN_10);
gpio_mode_set(GPIOG, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_12);
gpio_output_options_set(GPIOG, GPIO_OTYPE_PP, GPIO_OSPEED_60MHZ, GPIO_PIN_12);
gpio_mode_set(GPIOG, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_14);
gpio_output_options_set(GPIOG, GPIO_OTYPE_PP, GPIO_OSPEED_60MHZ, GPIO_PIN_14);
/* configure LCD_DE(PF10) */
gpio_af_set(GPIOF, GPIO_AF_14, GPIO_PIN_10);
gpio_mode_set(GPIOF, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_10);
gpio_output_options_set(GPIOF, GPIO_OTYPE_PP, GPIO_OSPEED_60MHZ, GPIO_PIN_10);
/* LCD PWM BackLight(PG13) */
gpio_mode_set(GPIOG, GPIO_MODE_OUTPUT, GPIO_PUPD_PULLUP, GPIO_PIN_13);
gpio_output_options_set(GPIOG, GPIO_OTYPE_PP, GPIO_OSPEED_60MHZ, GPIO_PIN_13);
gpio_bit_set(GPIOG, GPIO_PIN_13);
//复位TLI
tli_deinit();
tli_struct_para_init(&tli_init_struct);
//配置TLI时钟
rcu_pll_input_output_clock_range_config(IDX_PLL2, RCU_PLL2RNG_1M_2M, RCU_PLL2VCO_150M_420M);
/* configure the PLL2 clock: CK_PLL2P/CK_PLL2Q/CK_PLL2R = HXTAL_VALUE / 25 * 150 / 3 */
if(ERROR == rcu_pll2_config(25, 150, 3, 3, 3)) {
while(1) {
}
}
rcu_pll_clock_output_enable(RCU_PLL2R);
rcu_tli_clock_div_config(RCU_PLL2R_DIV8);
rcu_osci_on(RCU_PLL2_CK);
if(ERROR == rcu_osci_stab_wait(RCU_PLL2_CK)) {
while(1) {
}
}
/* configure TLI parameter struct */
tli_init_struct.signalpolarity_hs = TLI_HSYN_ACTLIVE_LOW;
tli_init_struct.signalpolarity_vs = TLI_VSYN_ACTLIVE_LOW;
tli_init_struct.signalpolarity_de = TLI_DE_ACTLIVE_LOW;
tli_init_struct.signalpolarity_pixelck = TLI_PIXEL_CLOCK_TLI;
//LCD显示时序配置
tli_init_struct.synpsz_hpsz = HORIZONTAL_SYNCHRONOUS_PULSE - 1;
tli_init_struct.synpsz_vpsz = VERTICAL_SYNCHRONOUS_PULSE - 1;
tli_init_struct.backpsz_hbpsz = HORIZONTAL_SYNCHRONOUS_PULSE + HORIZONTAL_BACK_PORCH - 1;
tli_init_struct.backpsz_vbpsz = VERTICAL_SYNCHRONOUS_PULSE + VERTICAL_BACK_PORCH - 1;
tli_init_struct.activesz_hasz = HORIZONTAL_SYNCHRONOUS_PULSE + HORIZONTAL_BACK_PORCH + ACTIVE_WIDTH - 1;
tli_init_struct.activesz_vasz = VERTICAL_SYNCHRONOUS_PULSE + VERTICAL_BACK_PORCH + ACTIVE_HEIGHT - 1;
tli_init_struct.totalsz_htsz = HORIZONTAL_SYNCHRONOUS_PULSE + HORIZONTAL_BACK_PORCH + ACTIVE_WIDTH + HORIZONTAL_FRONT_PORCH - 1;
tli_init_struct.totalsz_vtsz = VERTICAL_SYNCHRONOUS_PULSE + VERTICAL_BACK_PORCH + ACTIVE_HEIGHT + VERTICAL_FRONT_PORCH - 1;
//配置背景色RGB值
tli_init_struct.backcolor_red = 0x00;
tli_init_struct.backcolor_green = 0x00;
tli_init_struct.backcolor_blue = 0x00;
tli_init(&tli_init_struct);
LCDLayerWindowSet(LCD_LAYER_BACKGROUND, 0, 0, LCD_PIXEL_WIDTH, LCD_PIXEL_HEIGHT);
LCDLayerWindowSet(LCD_LAYER_FOREGROUND, 0, 0, LCD_PIXEL_WIDTH, LCD_PIXEL_HEIGHT);
LCDLayerEnable(LCD_LAYER_BACKGROUND);
LCDLayerDisable(LCD_LAYER_FOREGROUND);
LCDTransparencySet(LCD_LAYER_BACKGROUND, 0xFF);
LCDTransparencySet(LCD_LAYER_FOREGROUND, 0xFF);
tli_dither_config(TLI_DITHER_ENABLE);
// tli_dither_config(TLI_DITHER_DISABLE);
tli_reload_config(TLI_REQUEST_RELOAD_EN);
tli_enable();
LCDLayerSwitch(LCD_LAYER_BACKGROUND);
LCDDisplayDir(LCD_SCREEN_HORIZONTAL);
LCDClear(LCD_COLOR_BLACK);
}
3.2、main.c
#include "main.h"
void cache_enable(void);
int main(void)
{
uint8_t x=0;
uint32_t sd=0;
cache_enable();
systick_config();
init_usart(115200);
init_led();
exmc_synchronous_dynamic_ram_init(EXMC_SDRAM_DEVICE0);
init_lcd();
LCDDisplayDir(LCD_SCREEN_HORIZONTAL);
LCDClear(LCD_COLOR_WHITE);
while(1)
{
switch(x)
{
case 0: LCDClear(LCD_COLOR_WHITE); break;
case 1: LCDClear(LCD_COLOR_RED ); break;
case 2: LCDClear(LCD_COLOR_GREEN); break;
case 3: LCDClear(LCD_COLOR_BLUE); break;
case 4: LCDClear(LCD_COLOR_YELLOW); break;
case 5: LCDClear(LCD_COLOR_MAGENTA); break;
case 6: LCDClear(LCD_COLOR_BLACK); break;
}
x++;
if(x>6)
{
x=0;
}
LCDShowString(10, 20, 300, 24, LCD_FONT_24, LCD_TEXT_TRANS, LCD_COLOR_RED, NULL, "GD32H759 TLI LCD TEST!");
delay_1ms(500);
}
}
void cache_enable(void)
{
/* enable i-cache */
SCB_EnableICache();
/* enable d-cache */
SCB_EnableDCache();
}
四、运行
下载程序后,运行视频如下: