DPI
概述
环境需求
该示例的环境需求,可参考 环境需求。
硬件连线
将 P0_2 连接到 WRCLK 引脚。
将 P1_5 连接到 HSYNC 引脚。
将 P0_1 连接到 VSYNC 引脚。
将 P0_0 连接到 DE 引脚。
对于其他数据引脚,请参考
EK9716_800480_rgb.h
。
配置选项
可以通过修改以下参数 pixel[i]
来改变 LCD 屏幕上显示的颜色。
for (uint32_t i = 0; i < EK9716_800480_LCD_WIDTH * EK9716_800480_LCD_HEIGHT; i++) { pixel[i] = 0x001F; }
当前默认值在 RGB565 格式中为红色。
编译和下载
该示例的编译和下载流程,可参考 编译和下载。
测试验证
屏幕刷新成功
屏幕将以 配置选项 中确定的特定颜色刷新。
代码介绍
该章节主要介绍示例中的初始化和相应功能实现的代码和流程说明。
源码路径
工程文件和源码路径如下:
工程路径:
sdk\samples\peripheral\lcdc\lcdc_dpi\proj
源码路径:
sdk\samples\peripheral\lcdc\lcdc_dpi\src
初始化
初始化流程包含在 lcd_pad_and_clk_init() 中。
启用 LCDC 时钟并选择合适的时钟源。
/* config LCD dev info */
RCC_PeriphClockCmd(APBPeriph_DISP, APBPeriph_DISP_CLOCK, ENABLE);
//from XTAL SOURCE = 40M
PERIBLKCTRL_PERI_CLK->u_324.BITS_324.disp_ck_en = 1;
PERIBLKCTRL_PERI_CLK->u_324.BITS_324.disp_func_en = 1;
PERIBLKCTRL_PERI_CLK->u_324.BITS_324.r_disp_mux_clk_cg_en = 1;
//From PLL1, SOURCE = 100M
PERIBLKCTRL_PERI_CLK->u_324.BITS_324.r_disp_div_en = 1;
PERIBLKCTRL_PERI_CLK->u_324.BITS_324.r_disp_clk_src_sel0 = 0; //pll1_peri(0) or pll2(1, pll2 = 160M)
PERIBLKCTRL_PERI_CLK->u_324.BITS_324.r_disp_clk_src_sel1 = 1; //pll(1) or xtal(0)
PERIBLKCTRL_PERI_CLK->u_324.BITS_324.r_disp_div_sel = 0; //div
初始化所有将要使用的引脚。
Pad_Config(LCDC_RGB_WRCLK, PAD_PINMUX_MODE, PAD_IS_PWRON, PAD_PULL_UP, PAD_OUT_DISABLE,
PAD_OUT_HIGH);
Pad_Config(LCDC_HSYNC, PAD_PINMUX_MODE, PAD_IS_PWRON, PAD_PULL_UP, PAD_OUT_DISABLE, PAD_OUT_HIGH);
Pad_Config(LCDC_VSYNC, PAD_PINMUX_MODE, PAD_IS_PWRON, PAD_PULL_UP, PAD_OUT_DISABLE, PAD_OUT_HIGH);
Pad_Config(LCDC_CSN_DE, PAD_PINMUX_MODE, PAD_IS_PWRON, PAD_PULL_UP, PAD_OUT_DISABLE, PAD_OUT_HIGH);
Pad_Dedicated_Config(LCDC_RGB_WRCLK, ENABLE);
Pad_Dedicated_Config(LCDC_HSYNC, ENABLE);
Pad_Dedicated_Config(LCDC_VSYNC, ENABLE);
Pad_Dedicated_Config(LCDC_CSN_DE, ENABLE);
确定输入和输出颜色格式,并选择 DPI 接口。启用infinite模式以持续向 LCD 面板传输数据。
LCDC_InitTypeDef lcdc_init = {0};
lcdc_init.LCDC_Interface = LCDC_IF_DPI;
lcdc_init.LCDC_PixelInputFormat = LCDC_INPUT_RGB565;
lcdc_init.LCDC_PixelOutputFormat = LCDC_OUTPUT_RGB888;
lcdc_init.LCDC_PixelBitSwap = LCDC_SWAP_BYPASS; //lcdc_handler_cfg->LCDC_TeEn = LCDC_TE_DISABLE;
lcdc_init.LCDC_GroupSel = 1;
lcdc_init.LCDC_DmaThreshold = 64; //DMA MSize + Dma Threshold = 128
lcdc_init.LCDC_InfiniteModeEn = 1;
LCDC_Init(&lcdc_init);
初始化 DPI 接口,包括时钟分频和同步信号的参数。
uint32_t HSA = 48, HFP = 40, HBP = 40, HACT = EK9716_800480_LCD_WIDTH;
uint32_t VSA = 1, VFP = 13, VBP = 31, VACT = EK9716_800480_LCD_HEIGHT;
LCDC_eDPICfgTypeDef eDPICfg;
eDPICfg.eDPI_ClockDiv = 4;
eDPICfg.eDPI_HoriSyncWidth = HSA;
eDPICfg.eDPI_VeriSyncHeight = VSA;
eDPICfg.eDPI_AccumulatedHBP = HSA + HBP;
eDPICfg.eDPI_AccumulatedVBP = VSA + VBP;
eDPICfg.eDPI_AccumulatedActiveW = HSA + HBP + HACT;
eDPICfg.eDPI_AccumulatedActiveH = VSA + VBP + VACT;
eDPICfg.eDPI_TotalWidth = HSA + HBP + HACT + HFP;
eDPICfg.eDPI_TotalHeight = VSA + VBP + VACT + VFP;
eDPICfg.eDPI_DataEnPolarity = 1;
eDPICfg.eDPI_LineIntMask = 1; //Mask interrupt
eDPICfg.eDPI_ColorMap = EDPI_PIXELFORMAT_RGB888;//For RGB888
eDPICfg.eDPI_OperateMode = 0;//Video mode
eDPICfg.eDPI_LcdArc = 0; //Architecture 1,2,3
eDPICfg.eDPI_CmdMaxLatency = 0;
eDPICfg.eDPI_LineBufferPixelThreshold = eDPICfg.eDPI_TotalWidth / 2;
EDPI_Init(&eDPICfg);
控制复位引脚完成复位过程。
ek9716_reset_high();
platform_delay_ms(200);
ek9716_reset_low();
platform_delay_ms(200);
ek9716_reset_high();
platform_delay_ms(200);
初始化要显示的数据的内存空间。
for (uint32_t i = 0; i < EK9716_800480_LCD_WIDTH * EK9716_800480_LCD_HEIGHT; i++)
{
pixel[i] = 0x001F;
}
初始化 DMA 参数,包括数据大小、burst大小和源地址的增长方式,以通过初始化后的 DPI 接口向 LCD 面板传输数据。在本示例中,选择了DNA的linklist模式。
LCDC_DMA_InitTypeDef LCDC_DMA_InitStruct = {0};
LCDC_DMA_StructInit(&LCDC_DMA_InitStruct);
LCDC_DMA_InitStruct.LCDC_DMA_ChannelNum = LCDC_DMA_CHANNEL_NUM;
LCDC_DMA_InitStruct.LCDC_DMA_DIR = LCDC_DMA_DIR_PeripheralToMemory;
LCDC_DMA_InitStruct.LCDC_DMA_SourceInc = LCDC_DMA_SourceInc_Inc;
LCDC_DMA_InitStruct.LCDC_DMA_DestinationInc = LCDC_DMA_DestinationInc_Fix;
LCDC_DMA_InitStruct.LCDC_DMA_SourceDataSize = LCDC_DMA_DataSize_Word;
LCDC_DMA_InitStruct.LCDC_DMA_DestinationDataSize = LCDC_DMA_DataSize_Word;
LCDC_DMA_InitStruct.LCDC_DMA_SourceMsize = LCDC_DMA_Msize_64;
LCDC_DMA_InitStruct.LCDC_DMA_DestinationMsize = LCDC_DMA_Msize_64;
LCDC_DMA_InitStruct.LCDC_DMA_Multi_Block_Mode = LLI_TRANSFER;
LCDC_DMA_InitStruct.LCDC_DMA_Multi_Block_En = ENABLE;
LCDC_DMA_InitStruct.LCDC_DMA_Multi_Block_Struct = LCDC_DMA_LINKLIST_REG_BASE + 0x50;
LCDC_DMA_Init(LCDC_DMA_CHANNEL_INDEX, &LCDC_DMA_InitStruct);
初始化 DMA 配置的链表。在本示例中,两个缓冲区交替使用,它们的地址逐渐增加以完全覆盖整个显示区域。
LCDC_DMALLI_InitTypeDef LCDC_DMA_LLI_Init = {0};
LCDC_DMA_LLI_Init.g1_source_addr = (uint32_t)p_buffer;
LCDC_DMA_LLI_Init.g2_source_addr = (uint32_t)((uint32_t)p_buffer + EK9716_800480_LCD_WIDTH *
EK9716_DRV_PIXEL_BITS / 8);
LCDC_DMA_LLI_Init.g1_sar_offset = EK9716_800480_LCD_WIDTH * EK9716_DRV_PIXEL_BITS / 8 * 2;
LCDC_DMA_LLI_Init.g2_sar_offset = EK9716_800480_LCD_WIDTH * EK9716_DRV_PIXEL_BITS / 8 * 2;
LCDC_DMA_LinkList_Init(&LCDC_DMA_LLI_Init, &LCDC_DMA_InitStruct);
每当整个帧传输到 LCD 面板后,源地址将重置为由 API
LCDC_DMA_Infinite_Buf_Update()
预设的像素缓冲区地址。DMA 将再次读取步骤 8 中设置的链表,并开始无限传输数据。
LCDC_DMA_Infinite_Buf_Update((uint8_t *)p_buffer,
(uint8_t *)p_buffer + EK9716_800480_LCD_WIDTH *
EK9716_DRV_PIXEL_BITS / 8);
使用 API
LCDC_SetTxPixelLen()
确定每帧内应发送多少像素。
LCDC_SetTxPixelLen(EK9716_800480_LCD_WIDTH * EK9716_800480_LCD_HEIGHT);
功能实现
LCDC的功能实现在函数 ek9716_dma_init
中展示。
通过调用
LCDC_SwitchDirect()
确定数据流的方向。
LCDC_SwitchDirect(LCDC_TX_MODE);
通过在
LCDC_SwitchMode()
中设置参数LCDC_AUTO_MODE
让 LCDC 自动传输数据。
LCDC_SwitchMode(LCDC_AUTO_MODE);
通过调用
LCDC_Cmd()
启用 LCDC。
LCDC_Cmd(ENABLE);
使用
LCDC_DMA_MultiBlockCmd()
启用multi-block传输,并使用LCDC_DMAChannelCmd()
启用内部 DMA 通道。
LCDC_DMA_MultiBlockCmd(ENABLE);
LCDC_DMAChannelCmd(LCDC_DMA_CHANNEL_NUM, ENABLE);
使用
LCDC_DmaCmd()
让 DMA 开始向内部 FIFO 搬运数据。
LCDC_DmaCmd(ENABLE);
通过调用 API
LCDC_AutoWriteCmd()
让 LCDC 开始从内部 FIFO 向选定的接口传输数据。
LCDC_AutoWriteCmd(ENABLE);