DBI-C

该示例演示LCDC外设中DBI-C接口的应用。 DBI-C也普遍被称为QSPI。

环境需求

该示例支持以下开发套件:

开发套件

硬件平台

设备名称

RTL87x2G HDK

RTL87x2G EVB

更多信息请参考快速入门

硬件连线

需要任意QSPI屏幕或逻辑分析仪。

  1. P3_6接到屏幕Reset。

  2. P4_2接到屏幕D0。

  3. P4_1接到屏幕D1。

  4. P3_2接到屏幕D2。

  5. P3_3接到屏幕D3。

  6. P4_3接到屏幕CS。

  7. P4_0接到屏幕CLK。

  8. P0_5接到屏幕TE。

或以上所有引脚连接至逻辑分析仪。

配置选项

编译和下载

该示例的工程路径如下:

Project file: samples\peripheral\lcdc\lcdc_qspi\proj\rtl87x2g\mdk

Project file: samples\peripheral\lcdc\lcdc_qspi\proj\rtl87x2g\gcc

请按照以下步骤操作构建并运行该示例:

  1. 打开工程文件。

  2. 按照 Quick Start编译APP Image 给出的步骤构建目标文件。

  3. 编译成功后,在路径 mdk\bin 下会生成 app bin app_MP_xxx.bin 文件。

  4. 按照 Quick StartMPTool下载 给出的步骤将app bin烧录至EVB内。

  5. 按下复位按键,开始运行。

测试验证

  1. 观察到屏幕点亮为绿色,或逻辑分析仪观察到正确波形。

代码介绍

该章节分为以下几个部分:

  1. 源码路径

  2. 初始化函数将在 初始化 章节介绍。

  3. 初始化后的功能实现将在 功能实现 章节介绍。

源码路径

  • 工程路径: sdk\samples\peripheral\lcdc\lcdc_qspi\proj

  • 源码路径: sdk\samples\peripheral\lcdc\lcdc_qspi\src

该工程的工程文件代码结构如下:

└── Project: qspi
    └── lcdc
        ├── config                       include project construct configuration
        ├── display                      include the peripheral drivers related with display
        └── Device                       includes startup code
            ├── startup_rtl.c
            └── system_rtl.c
        ├── CMSIS                        includes CMSIS header files
        ├── CMSE Library                 non-secure callable lib
        ├── lib                          includes all binary symbol files that user application is built on
        ├── peripheral                   includes all peripheral drivers and module code used by the application
        └── APP                          soucrce code of LCDC qspi sample
            ├── main_ns.c
            └── icna3311_280x456_qspi.c  driver of LCD screen

初始化

初始化流程包含在 rtk_lcd_hal_init() 中。

  1. 使能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 = 1; //div
  1. 初始化需要使用的引脚。

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. 选择需要的颜色格式,指定使用DBI-C接口。

LCDC_InitTypeDef lcdc_init = {0};
lcdc_init.LCDC_Interface = LCDC_IF_DBIC;
lcdc_init.LCDC_GroupSel = 1;
lcdc_init.LCDC_PixelInputFarmat = LCDC_INPUT_RGB565;
lcdc_init.LCDC_PixelOutpuFarmat = 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. 初始化DBI-C接口,指定分频系数与极性。

LCDC_DBICCfgTypeDef dbic_init = {0};
dbic_init.DBIC_SPEED_SEL         = 1;
dbic_init.DBIC_TxThr             = 0;
dbic_init.DBIC_RxThr             = 0;
dbic_init.SCPOL                  = DBIC_SCPOL_LOW;
dbic_init.SCPH                   = DBIC_SCPH_1Edge;
DBIC_Init(&dbic_init);
  1. 通过控制Reset引脚使屏幕完成Reset。

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. 如果使用的屏幕需要初始化,通过DBI-C接口向屏幕发送初始化命令和数据。

小技巧

通过DBIC向外发送命令的方式,详见 常见问题

功能实现

  1. 通过函数 rtk_lcd_hal_set_window() 指定更新屏幕RAM的区域,如下所示,将窗口设为起始点为(0,0), 宽度为280, 高度为456:

rtk_lcd_hal_set_window(0, 0, 280, 456);
  1. 通过函数 rtk_lcd_hal_start_transfer() 将指定长度的数据向屏幕发送。

  2. 该函数中,首先初始化了DMA的配置。

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                 = 4;
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_InitStruct.LCDC_DMA_SourceAddr          = (uint32_t)buf;
LCDC_DMA_InitStruct.LCDC_DMA_Multi_Block_En     = 0;
LCDC_DMA_Init(LCDC_DMA_CHANNEL_INDEX, &LCDC_DMA_InitStruct);
  1. 重置DMA寄存器,并设定当前需要的参数。

LCDC_ClearDmaFifo();
LCDC_ClearTxPixelCnt();

LCDC_SwitchMode(LCDC_AUTO_MODE);
LCDC_SwitchDirect(LCDC_TX_MODE);

LCDC_SetTxPixelLen(len);
  1. 使能DMA,若有TE信号,则通过TE信号开始DMA传输数据。

LCDC_Cmd(ENABLE);
LCDC_DMAChannelCmd(LCDC_DMA_CHANNEL_NUM, ENABLE);
LCDC_DmaCmd(ENABLE);
#if (TE_VALID == 1)
    LCDC_TeCmd(ENABLE);
#endif
#if (TE_VALID == 0)
    LCDC_AutoWriteCmd(ENABLE);
#endif
  1. 通过 rtk_lcd_hal_transfer_done() 等待DMA传输完成。

常见问题

通过DBIC发送数据,可以参考函数 qspi_write()

  1. 设定使用的数据线数量,以及数据的传输方向。

DBIC_Cmd(DISABLE);//disable DBIC
DBIC->CTRLR0 &= ~(BIT_CMD_CH(3) | BIT_ADDR_CH(3) | BIT_DATA_CH(3));//SET CHANNEL NUM
DBIC->CTRLR0 &= ~(BIT_TMOD(3)); //tx mode
  1. 设定向外发送的命令与地址的长度。

DBIC_CmdLength(1);
DBIC_AddrLength(3);
DBIC_TX_NDF(len - 4);
DBIC_Cmd(ENABLE);
  1. 向DR寄存器写书需要发送的数据,并等待其发送结束。

for (uint32_t i = 0; i < len; i++)
{
    DBIC->DR[0].byte = buf[i];
}
while (DBIC->SR & BIT0); // wait bus busy
DBIC_Cmd(DISABLE);//disable DBIC