LCDC
LCDC(LCD Controller) 是为屏提供一个统一的接口,而不需关心具体物理连接是SPI、并口或者其他物理连接,只需在初始化时配置需要使用的物理接口及参数,后续均使用统一的接口.
另外,它还可以支持图层的alpha混叠, 图层如下(按叠加排列):
- 单色背景 
- 图层0 
- 图层1 (54x 不支持) 
支持的物理接口:
| 名称 | 55X | 58X | 56X | 54X | 
|---|---|---|---|---|
| 3SPI (1/2 data line) | Y | Y | Y | Y | 
| 4SPI (1/2 data line) | Y | Y | Y | Y | 
| QAD-SPI | Y | Y | Y | Y | 
| DSI Command模式 | Y | Y | N | N | 
| DSI Video 模式 | N | Y | N | N | 
| AHB 输出到SRAM/PSRAM | Y | Y | Y | Y | 
| DBI 8080-8bit | Y | Y | Y | Y | 
| JDI | Y | Y | Y | Y | 
| DPI | Y | Y | Y | Y | 
支持的速度:
- SPI (包括3SPI、4SPI、QAD-SPI) 速度=HCLK/divider, 其中divider为2~255 
- DSI 只支持DSI_Clock_Freq配置的几种速度 
- DBI 同SPI 
支持的颜色输出格式
- RGB332 
- RGB565 
- RGB888 
- RGB565_SWAP (55x 不支持) 
图层支持的颜色格式
- RGB565 
- RGB888 
- ARGB888 
- ARGB565 
- A8 (55x 不支持) 
- L8 (55x 不支持) 
- RGB565_SWAP (55x 不支持) 
其他特性
- 支持指定绘图区域, 且该区域可以跟给定的输出buffer区域任意交叉 
- 支持帧同步和行同步 
- 支持同步&异步(中断模式)送数接口 

使用LCDC示例1
通过4SPI 1data接口驱动ST7789H2的屏幕
static LCDC_InitTypeDef lcdc_int_cfg =
{
    .lcd_itf = LCDC_INTF_SPI_DCX_1DATA,     //Choose 4SPI 1data interface
    .freq = 24000000,                       //SPI clock 24MHz
    .color_mode = LCDC_PIXEL_FORMAT_RGB565, //LCDC output color format RGB565
    .cfg = {
        .spi = {
            .dummy_clock = 1,                      //Dummy clock between cmd & data in read mode
            .syn_mode = HAL_LCDC_SYNC_VER,         //TE sychronization mode 
            .vsyn_polarity = 0,                    //TE pin polarity
            .vsyn_delay_us = 1000,                 //Delay 1ms to send frame buffer right after received TE signal
            .hsyn_num = 0,                         //Hsyn num if syn_mode is HAL_LCDC_SYNC_VERHOR
        },
    },
};
LCDC_HandleTypeDef hlcdc_st7789h2;
__ROM_USED void LCDC1_IRQHandler(void)
{
    rt_interrupt_enter();
    HAL_LCDC_IRQHandler(lcdc);
    
    rt_interrupt_leave();
}
void HAL_LCDC_SendLayerDataCpltCbk(LCDC_HandleTypeDef *lcdc)
{
    /*Send layer data completed*/
}
/**
  * @brief  Power on the LCD.
  * @param  None
  * @retval None
  */
void ST7789H2_Init(LCDC_HandleTypeDef *hlcdc)
{
    uint8_t   parameter[14];
    //Initalize interface
    memcpy(&hlcdc->Init, &lcdc_int_cfg, sizeof(LCDC_InitTypeDef));
    HAL_LCDC_Init(hlcdc);
    //Generate a reset pulse to reset ST7789H2
    HAL_LCDC_ResetLCD(hlcdc, LCDC_RESX_NEG_PULSE, 10);
    /************* ST7789H2 initialize sequence start ************************/
    /*Sleep In Command */
    HAL_LCDC_WriteU8Reg(hlcdc, ST7789H2_SLEEP_IN, (uint8_t *)NULL, 0);
    /* Wait for 10ms */
    HAL_Delay(10);
    /* SW Reset Command */
    HAL_LCDC_WriteU8Reg(hlcdc, 0x01, (uint8_t *)NULL, 0);
    /* Wait for 200ms */
    HAL_Delay(200);
    /* Sleep Out Command */
    HAL_LCDC_WriteU8Reg(hlcdc, ST7789H2_SLEEP_OUT, (uint8_t *)NULL, 0);
    /* Wait for 120ms */
    HAL_Delay(120);
    ...
    /************* ST7789H2 initialize sequence end ************************/
}
/**
  * @brief  ST7789H2 read mode should slow down SPI clock to 4MHz
  * @param  enable: false - write spi mode |  true - read spi mode
  * @retval None
  */
void ST7789H2_ReadMode(LCDC_HandleTypeDef *hlcdc, bool enable)
{
    if (HAL_LCDC_IS_SPI_IF(lcdc_int_cfg.lcd_itf))
    {
        if (enable)
        {
            HAL_LCDC_SetFreq(hlcdc, 4000000); //SPI clock is 4MHz on Read mode
        }
        else
        {
            HAL_LCDC_SetFreq(hlcdc, lcdc_int_cfg.freq); //Restore normal frequency
        }
    }
}
/**
  * @brief  Reads the selected LCD Register.
  * @param  RegValue: Address of the register to read
  * @param  ReadSize: Number of bytes to read
  * @retval LCD Register Value.
  */
uint32_t ST7789H2_ReadData(LCDC_HandleTypeDef *hlcdc, uint16_t RegValue, uint8_t ReadSize)
{
    uint32_t rd_data = 0;
    //Entry read mode
    ST7789H2_ReadMode(hlcdc, true);
    HAL_LCDC_ReadU8Reg(hlcdc, RegValue, (uint8_t *)&rd_data, ReadSize);
    //Recovery to normal mode
    ST7789H2_ReadMode(hlcdc, false);
    return rd_data;
}
/**
 * @brief Set LCD & LCDC clip area
 * @param hlcdc LCD controller handle
 * @param Xpos0 - Clip area left coordinate, base on LCD top-left, same as below.
 * @param Ypos0 - Clip area top coordinate
 * @param Xpos1 - Clip area right coordinate
 * @param Ypos1 - Clip area bottom coordinate
 */
void ST7789H2_SetRegion(LCDC_HandleTypeDef *hlcdc, uint16_t Xpos0, uint16_t Ypos0, uint16_t Xpos1, uint16_t Ypos1)
{
    uint8_t   parameter[4];
    //Set LCDC clip area
    HAL_LCDC_SetROIArea(hlcdc, Xpos0, Ypos0, Xpos1, Ypos1);
    //Set LCD clip area
    parameter[0] = (Xpos0) >> 8;
    parameter[1] = (Xpos0) & 0xFF;
    parameter[2] = (Xpos1) >> 8;
    parameter[3] = (Xpos1) & 0xFF;
    HAL_LCDC_WriteU8Reg(hlcdc, ST7789H2_CASET, parameter, 4);
    parameter[0] = (Ypos0) >> 8;
    parameter[1] = (Ypos0) & 0xFF;
    parameter[2] = (Ypos1) >> 8;
    parameter[3] = (Ypos1) & 0xFF;
    HAL_LCDC_WriteU8Reg(hlcdc, ST7789H2_RASET, parameter, 4);
}
/**
 * @brief Send layer data to LCD
 * @param hlcdc LCD controller handle
 * @param RGBCode - Pointer to layer data 
 * @param Xpos0 - Layer data left coordinate, base on LCD top-left, same as below.
 * @param Ypos0 - Layer data top coordinate
 * @param Xpos1 - Layer data right coordinate
 * @param Ypos1 - Layer data bottom coordinate
 */
void ST7789H2_WriteMultiplePixels(LCDC_HandleTypeDef *hlcdc, const uint8_t *RGBCode, uint16_t Xpos0, uint16_t Ypos0, uint16_t Xpos1, uint16_t Ypos1)
{
    uint32_t size;
    if ((Xpos0 > Xpos1) || (Ypos0 > Ypos1))
    {
        //Invalid coordinates
        return;
    }
    //Set default layer data
    HAL_LCDC_LayerSetData(hlcdc, HAL_LCDC_LAYER_DEFAULT, (uint8_t *)RGBCode, Xpos0, Ypos0, Xpos1, Ypos1);
    //Write datas to LCD register
    HAL_LCDC_SendLayerData2Reg_IT(hlcdc, 0x2c, 1);
}
