SDI

Overview

This sample demonstrates the application of driving a ICNA3311 LCD panel through SDI interface of the LCDC peripheral.

Requirements

For requirements, please refer to the Requirements.

Wiring

  1. Connect P3_6 to the Reset pin.

  2. Connect P4_2 to D0 pin.

  3. Connect P4_1 to D1 pin.

  4. Connect P3_2 to D2 pin.

  5. Connect P3_3 to D3 pin.

  6. Connect P4_3 to CS pin.

  7. Connect P4_0 to CLK pin.

  8. Connect P0_5 to TE pin.

Configurations

The following parameter ABGR_color in function rtk_lcd_hal_init() can be modified to change the color displayed on LCD screen.

uint32_t ABGR_color = 0x0000FF00;
rtk_lcd_hal_rect_fill(0, 0, 280, 456, ABGR_color);

Current default value stands for pure green.

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_qspi\proj

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

Initialization

The initialization process is included in rtk_lcd_hal_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 = 1; //div
  1. Initialize all the pins to be used.

Pad_Config(LCD_QSPI_RST, PAD_PINMUX_MODE, PAD_IS_PWRON, PAD_PULL_UP, PAD_OUT_DISABLE, PAD_OUT_HIGH);
Pad_Config(LCD_QSPI_D0, PAD_PINMUX_MODE, PAD_IS_PWRON, PAD_PULL_UP, PAD_OUT_DISABLE, PAD_OUT_HIGH);
Pad_Config(LCD_QSPI_D1, PAD_PINMUX_MODE, PAD_IS_PWRON, PAD_PULL_UP, PAD_OUT_DISABLE, PAD_OUT_HIGH);
Pad_Config(LCD_QSPI_D2, PAD_PINMUX_MODE, PAD_IS_PWRON, PAD_PULL_UP, PAD_OUT_DISABLE, PAD_OUT_HIGH);
Pad_Config(LCD_QSPI_D3, PAD_PINMUX_MODE, PAD_IS_PWRON, PAD_PULL_UP, PAD_OUT_DISABLE, PAD_OUT_HIGH);
Pad_Config(LCD_QSPI_CS, PAD_PINMUX_MODE, PAD_IS_PWRON, PAD_PULL_UP, PAD_OUT_DISABLE, PAD_OUT_HIGH);
Pad_Config(LCD_QSPI_CLK, PAD_PINMUX_MODE, PAD_IS_PWRON, PAD_PULL_UP, PAD_OUT_DISABLE, PAD_OUT_HIGH);
Pad_Config(LCD_QSPI_TE, PAD_PINMUX_MODE, PAD_IS_PWRON, PAD_PULL_UP, PAD_OUT_DISABLE, PAD_OUT_HIGH);

Pad_Dedicated_Config(LCD_QSPI_RST, ENABLE);
Pad_Dedicated_Config(LCD_QSPI_D0, ENABLE);
Pad_Dedicated_Config(LCD_QSPI_D1, ENABLE);
Pad_Dedicated_Config(LCD_QSPI_D2, ENABLE);
Pad_Dedicated_Config(LCD_QSPI_D3, ENABLE);
Pad_Dedicated_Config(LCD_QSPI_CS, ENABLE);
Pad_Dedicated_Config(LCD_QSPI_CLK, ENABLE);
Pad_Dedicated_Config(LCD_QSPI_TE, ENABLE);
  1. Determine input and output color format, and select SDI interface. Enable TE signal.

LCDC_InitTypeDef lcdc_init = {0};
lcdc_init.LCDC_Interface = LCDC_IF_DBIC;
lcdc_init.LCDC_GroupSel = 1;
lcdc_init.LCDC_PixelInputFormat = LCDC_INPUT_RGB565;
lcdc_init.LCDC_PixelOutputFormat = LCDC_OUTPUT_RGB565;
lcdc_init.LCDC_PixelBitSwap = LCDC_SWAP_BYPASS;
lcdc_init.LCDC_TeEn = ENABLE;
lcdc_init.LCDC_TePolarity = LCDC_TE_EDGE_FALLING;
lcdc_init.LCDC_TeInputMux = LCDC_TE_LCD_INPUT;
lcdc_init.LCDC_DmaThreshold = 112;
LCDC_Init(&lcdc_init);
  1. Initialize SDI interface, select clock divider, polarity and phase.

LCDC_DBICCfgTypeDef dbic_init = {0};
dbic_init.DBIC_SPEED_SEL         = 1;
dbic_init.SCPOL                  = DBIC_SCPOL_LOW;
dbic_init.SCPH                   = DBIC_SCPH_1Edge;
DBIC_Init(&dbic_init);
  1. Control Reset pin to finish LCD panel reset procedure.

LCDC_LCD_SET_RST(false);
platform_delay_ms(100);
LCDC_LCD_SET_RST(true);
platform_delay_ms(120);
LCDC_LCD_SET_RST(false);
platform_delay_ms(50);
  1. Send command and data with basic SPI protocol, these commands and data should refer to LCD producer’s guide book.

incna3311_cmd_param1(0xFE, 0x00);
incna3311_cmd_param1(0xC4, 0x80);           /*set quad SPI mode*/
incna3311_cmd_param1(0x35, 0x00);           /*set tear on*/
incna3311_cmd_param1(0x51, 0xff);           /*write display brightness*/
incna3311_cmd_param1(0x53, 0x20);           /*write display ctrl ,dimming*/
incna3311_cmd_param1(0x63, 0xFF);           /*write HBM display brightness*/

Functional Implementation

Set Update Window

Function rtk_lcd_hal_set_window is used to set the window of screen that is to be updated. This example demonstrates a window starting from point (0,0) with a width of 280 and a height of 456:

  1. Set the window by sending commands to LCD panel. Using the range of window to construct data packet together with command.

//Horizontal Range
data[0] = xStart >> 8;
data[1] = xStart & 0xff;
data[2] = xEnd >> 8;
data[3] = xEnd & 0xff;
incna3311_cmd_param4(0x2A, data);
//Vertical Range
data[0] = yStart >> 8;
data[1] = yStart & 0xff;
data[2] = yEnd >> 8;
data[3] = yEnd & 0xff;
incna3311_cmd_param4(0x2B, data);
  1. Switch AXI mode of LCDC to LCDC_FW_MODE to allow writing modification to SDI by API LCDC_AXIMUXMode().

LCDC_AXIMUXMode(LCDC_FW_MODE);
  1. Set data size, address and commands for frame data transmission, after which switch LCDC back to LCDC_HW_MODE.

DBIC_CmdLength(1);
DBIC_AddrLength(3);
DBIC_TX_NDF(len_byte);
/* must push cmd and address to handler before SDI enable */
LCDC_SPICCmd(0x32);
LCDC_SPICAddr(0x002c00);
LCDC_AXIMUXMode(LCDC_HW_MODE);

DMA Configurations

After SDI interface is initialized, DMA should also be initialized to enable data transmission. The procedure is demonstrated in rtk_lcd_hal_clear_screen.

  1. Initialize DMA parameter, including data size, burst size and source increament, to transmit data to LCD panel through initialized SDI interface. In this sample, single block mode is used.

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_8;
LCDC_DMA_InitStruct.LCDC_DMA_DestinationMsize    = LCDC_DMA_Msize_8;
LCDC_DMA_Init(LCDC_DMA_CHANNEL_INDEX, &LCDC_DMA_InitStruct);

Data Transmission

After internal DMA is intialized, data transmission is prepared. The procedure is demonstrated in rtk_lcd_hal_clear_screen.

  1. Determine how many pixels should be sent within each frame with API LCDC_SetTxPixelLen().

LCDC_SetTxPixelLen(280 * 456);
  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);
  1. Polling status of LCDC. After DMA and SDI return to idle status, disable LCDC function.

while ((LCDC_HANDLER->DMA_FIFO_CTRL & LCDC_DMA_ENABLE) != RESET);//wait dma idle
LCDC_HANDLER_OPERATE_CTR_t handler_reg_0x14;
do
{
    handler_reg_0x14.d32 = LCDC_HANDLER->OPERATE_CTR;
}
while (handler_reg_0x14.b.auto_write_start != RESET);
LCDC_Cmd(DISABLE);
LCDC_ClearDmaFifo();
LCDC_ClearTxPixelCnt();
LCDC_AXIMUXMode(LCDC_FW_MODE);