DPI

Overview

This sample demonstrates the application of driving a EK9716 LCD panel through DPI interface of the LCDC peripheral.

Requirements

For requirements, please refer to the Requirements.

Wiring

  1. Connect P0_2 to the WRCLK pin.

  2. Connect P1_5 to the HSYNC pin.

  3. Connect P0_1 to the VSYNC pin.

  4. Connect P0_0 to the DE pin.

  5. For other data pins, refer to EK9716_800480_rgb.h.

Configurations

The following parameter pixel[i] can be modified to change the color displayed on LCD screen.

for (uint32_t i = 0; i < EK9716_800480_LCD_WIDTH * EK9716_800480_LCD_HEIGHT; i++)
{
    pixel[i] = 0x001F;
}

Current default value is red in RGB565 format.

Building and Downloading

For building and downloading, please refer to the Building and Downloading.

Experimental Verification

Screen Refresh Successfully

The screen is refreshed with certain color determined in Configurations.

Code Overview

This section introduces the code and process description for initialization and corresponding function implementation in the sample.

Source Code Directory

The directories for project file and source code are as follows:

  • Project directory: sdk\samples\peripheral\lcdc\lcdc_dpi\proj

  • Source code directory: sdk\samples\peripheral\lcdc\lcdc_dpi\src

Initialization

The initialization process is included in lcd_pad_and_clk_init().

  1. Enable clock of LCDC and select suitable clock source.

/* 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
  1. Initialize all the pins to be used.

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);
  1. Determine input and output color format, and select DPI interface. Enable infinite mode to continuously transmit data to LCD panel.

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);
  1. Initialize DPI interface, including clock division and parameters of signals for synchronization.

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);
  1. Control Reset pin to finish reset procedure.

ek9716_reset_high();
platform_delay_ms(200);
ek9716_reset_low();
platform_delay_ms(200);
ek9716_reset_high();
platform_delay_ms(200);
  1. Initialize memory space for data to be displayed.

for (uint32_t i = 0; i < EK9716_800480_LCD_WIDTH * EK9716_800480_LCD_HEIGHT; i++)
{
    pixel[i] = 0x001F;
}
  1. Initialize DMA parameter, including data size, burst size and source increament, to transmit data to LCD panel through initialized DPI interface. In this sample, linklist mode is selected.

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);
  1. Initialize linklist for DMA configuration. In this sample, two buffers are used alternately, and their addresses increase gradually to fully cover the entire pixel buffer.

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);
  1. Each time an entire frame has been transmitted to LCD panel, source address will be reset as pixel buffer address preset by API LCDC_DMA_Infinite_Buf_Update(). DMA will read the linklist set in step 8 again and start transmitting data infinitely.

LCDC_DMA_Infinite_Buf_Update((uint8_t *)p_buffer,
                             (uint8_t *)p_buffer + EK9716_800480_LCD_WIDTH *
                             EK9716_DRV_PIXEL_BITS / 8);
  1. Determine how many pixels should be sent within each frame with API LCDC_SetTxPixelLen().

LCDC_SetTxPixelLen(EK9716_800480_LCD_WIDTH * EK9716_800480_LCD_HEIGHT);

Functional Implementation

The LCDC functional implementation is demonstrated in ek9716_dma_init.

  1. Determine direction of data stream by calling LCDC_SwitchDirect().

LCDC_SwitchDirect(LCDC_TX_MODE);
  1. Let LCDC transmit data automatically by setting parameter LCDC_AUTO_MODE in LCDC_SwitchMode().

LCDC_SwitchMode(LCDC_AUTO_MODE);
  1. Enable LCDC by calling LCDC_Cmd().

LCDC_Cmd(ENABLE);
  1. Use LCDC_DMA_MultiBlockCmd() to enable multiblock and LCDC_DMAChannelCmd() to enable internal DMA channel.

LCDC_DMA_MultiBlockCmd(ENABLE);
LCDC_DMAChannelCmd(LCDC_DMA_CHANNEL_NUM, ENABLE);
  1. Let DMA start to transmit data to internal FIFO with LCDC_DmaCmd().

LCDC_DmaCmd(ENABLE);
  1. Let LCDC start to transmit data from internal FIFO to selected interface by calling API LCDC_AutoWriteCmd().

LCDC_AutoWriteCmd(ENABLE);