AM335X-驱动RGB屏(HX8369A)

写在前面

本文使用的屏幕是一块3.97英寸480*800的TN屏,主控是HX8369A,有点老,主要用在10几年前的手机上,使用3-Wire SPI+RGB接口,RGB接口的时序配置由SPI初始化阶段决定。但是某宝卖家只提供了SPI初始化代码(提供的初始化代码还有点问题,坑爹...),并没有与初始化参数相对应的vsw,vfp,vbp和hsw,hfp,hbp参数。因此想要完美显示,就需要好好研究下HX8369-A01的手册了,经过几个晚上的倒腾,同时参考了网络上零星的驱动资料(这屏RGB资料比较少,大多数是MIPI的资料)与淘宝卖家的初始化参数,终于是完美显示了。不过这里还是推荐读者买通用的40PIN/50PIN屏幕,比较好驱动,下面是我使用的屏幕和通用屏的价格对比。。。(如果同样选择TN面板不带触摸,价格差32元)

本文所使用的屏幕

通用40PIN屏(驱动IC:ST7262),注意这个是800*480

效果展示

显示完全正常,只是手机摄像头有点径向畸变。。。

屏初始化相关

HX8369A的屏幕接口由几个引脚配置,LCM在面板出排线时候已经固定好了,用户没法自行修改,买屏幕时候需要注意即使屏控制器支持RGB/MCU/MIPI接口,但最终的可用接口还是LCM厂商决定的。

由卖家给的资料可以确定配置电阻接法对应的接口是DPI / DBI TYPE-C Option 1

打开HX8369A的手册,可以看到3线spi的接口时序。从图中可以看出:3线spi支持9bit Option 1模式和16bit Option 2模式,这里由于硬件接线决定了使用Option1模式,需要9个bit连续发送。对于只支持8Bit传输模式的SPI只能采用GPIO模拟SPI的实现了,需要注意的是每次传输的数据都需要带上控制位。

AM3352的McSPI支持4~32bit的传输,设置起来很方便,根据HX8369A手册最大SPI速率为10M(如果是GPIO模拟的SPI,这个就不用担心超了);下面给出的AM335X裸机SPI配置的关键部分,在接屏幕前建议使用逻辑分析仪将Reset,cs, mosi, sclk这几个脚的数据抓取看下,确定spi和屏复位部分信号波形ok了就基本就没啥问题了。

// GPIO模块配置
GPIO3ModuleClkConfig();
GPIOModuleEnable(SOC_GPIO_3_REGS);
GPIOModuleReset(SOC_GPIO_3_REGS);
// cs
HWREG(SOC_CONTROL_REGS + SPI1_CS0_GPIO_ADDR) = PAD_FS_RXD_PU_PUPDE(3);
// mosi
HWREG(SOC_CONTROL_REGS + SPI1_D0_GPIO_ADDR) = PAD_FS_RXD_PU_PUPDE(3);
// miso 单驱屏幕这个脚也可以不配置,如果显示屏的3线spi和其他4线spi设备复用的话就需要配置
HWREG(SOC_CONTROL_REGS + SPI1_D1_GPIO_ADDR) = PAD_FS_RXE_PU_PUPDE(3);
// sclk
HWREG(SOC_CONTROL_REGS + SPI1_SCLK_GPIO_ADDR) = PAD_FS_RXD_PU_PUPDE(3);

// SPI1模块配置
McSPI1ModuleClkConfig();

McSPIReset(SOC_SPI_1_REGS);
McSPICSEnable(SOC_SPI_1_REGS);

McSPIMasterModeEnable(SOC_SPI_1_REGS);
McSPIMasterModeConfig(SOC_SPI_1_REGS, MCSPI_SINGLE_CH, MCSPI_TX_RX_MODE, MCSPI_DATA_LINE_COMM_MODE_6, MCSPI_CHANNEL_0);

McSPIClkConfig(SOC_SPI_1_REGS, MCSPI_MODEL_CLK, MCSPI1_OUT_FREQ, MCSPI_CHANNEL_0, MCSPI_CLK_MODE_0);
// 3wire spi msb is data/c
McSPIWordLengthSet(SOC_SPI_1_REGS, MCSPI_WORD_LENGTH(9), MCSPI_CHANNEL_0);
McSPICSPolarityConfig(SOC_SPI_1_REGS, MCSPI_CS_POL_LOW, MCSPI_CHANNEL_0);

McSPITxFIFOConfig(SOC_SPI_1_REGS, MCSPI_TX_FIFO_ENABLE, MCSPI_CHANNEL_0);
McSPIRxFIFOConfig(SOC_SPI_1_REGS, MCSPI_RX_FIFO_ENABLE, MCSPI_CHANNEL_0);

McSPIChannelEnable(SOC_SPI_1_REGS, MCSPI_CHANNEL_0);

卖家提供的初始化代码:https://files.cnblogs.com/files/yanye0xff/15-22511-30832初始化.zip
这份代码是有问题的,作为下面修改的参考模板,切勿完全照搬了。原始代码我将以截图形式展示,正确代码则以文本方式展示。

屏复位部分与手册的复位过程有出入,需要修改,原始代码如下:

手册配置的复位时序上并没有对CS脚做要求,且延时时间并不需要那么长

修改后

GPIOPinWrite(SOC_GPIO_0_REGS, HX8269A_RESET_GPIO_PIN, GPIO_PIN_LOW);
// tRESW min = 10 us
SysdelayUs(20);
GPIOPinWrite(SOC_GPIO_0_REGS, HX8269A_RESET_GPIO_PIN, GPIO_PIN_HIGH);
// there is H/W reset complete time (tREST) within 5ms after a rising edge of RESX
SysdelayMs(10);

// It resets the commands and parameters to their S/W Reset default values.
hx8369_write_cmd(0x01);
// it will be necessary to wait 120msec before sending Sleep out command(0x11)
SysdelayMs(120);

显示接口配置部分需要修改,HX8369A为了支持MCU口(DBI)内部是集成了GRAM的,卖家提供的代码"0x23"是将RGB接口数据写入到GRAM的异步模式,这样的好处是对RGB信号时序没啥要求,hbp,hfp,vbp,vfp这些参数随便填就行,但我测试下来,水平扫描始终是错位的,而且有些像素的颜色也不对...;所以这里我改为使用RGB直通模式,即数据直接送向屏幕的行列驱动器驱动液晶面板,一般的RGB屏都使用这种操作模式。
原来的'0x23'配置为"480RGBX800, DBI Interface (CPU), RGB data bypass GRAM mode",
需要改成"0x29","480RGBX800, DPI Interface (RGB), DPI signal (VSYNC+HSYNC)",
FPBP 需要根据显示屏顶部和底部是否缺扫描线来调整。
原始代码如下:

参照:

这里只放了需要修改的部分,其余的部分与原来一致

hx8369_write_data(0x00);
hx8369_write_data(0x29);
// Specify the amount of scan line for back porch(BP).
hx8369_write_data(0x07);
// Specify the amount of scan line for front porch (FP).
hx8369_write_data(0x08);

RGB接口电平配置部分,原始代码缺失,建议加上

//  Set RGB interface related register
hx8369_write_cmd(0xB3);
// DPL=0,HSPL=0,VSPL=0,EPL=1
// DPL=0, the data is read on the rising edge of PCLK signal.
// HSPL=0, the HS pin is Low active
// VSPL=0, the VS pin is Low active.
// EPL=1: DE = 0 Display:Disable, DE = 1 Display:Enable
hx8369_write_data(0x01);

设置屏幕显存起始地址,这里可以删掉,该配置只对MCU接口有效,在RGB模式下MPU内部控制器接管了屏逻辑部分,HX8369A只作为屏驱动IC。

"0x11"退出休眠指令后的延时不需要这么长,这里可以改小(如果sleep out后需要再次进sleep in才需要延时120ms,这里显然不需要了)

// EXIT SLEEP MODE
hx8369_write_cmd(0x11);
//  It will be necessary to wait 5msec before sending next command
SysdelayMs(10);

这里的设置显示区域的函数也可以去掉了,在RGB模式下并没有什么用。

至此初始化代码都已经修改配置完成了,RGB 时序参数如下
PCLK = Total Width * Total Hight * fps = (528 * 815 * 60)
VSW = 4, VFP = 6, VBP = 5
HSW = 16, HFP = 16, HBP = 16

时钟有效边沿配置如下

RasterTiming2Configure(SOC_LCDC_0_REGS, RASTER_FRAME_CLOCK_LOW |
                                        RASTER_LINE_CLOCK_LOW  |
                                        RASTER_PIXEL_CLOCK_LOW|
                                        RASTER_SYNC_EDGE_RISING|
                                        RASTER_SYNC_CTRL_ACTIVE|
                                        RASTER_AC_BIAS_HIGH, 0, 255);

完整的初始化代码:

inline static void hx8369_write_cmd(uint8_t cmd);
inline static void hx8369_write_data(uint8_t data);

inline static void hx8369_write_cmd(uint8_t cmd) {
    uint32_t command = 0x000;
    command |= cmd;
    McSPI1Write(&command, 1);
}

inline static void hx8369_write_data(uint8_t data) {
    uint32_t outdata = 0x100;
    outdata |= data;
    McSPI1Write(&outdata, 1);
}

void HX8269AInit(void) {
    GPIOPinWrite(SOC_GPIO_0_REGS, HX8269A_RESET_GPIO_PIN, GPIO_PIN_LOW);
    // tRESW min = 10 us
    SysdelayUs(20);
    GPIOPinWrite(SOC_GPIO_0_REGS, HX8269A_RESET_GPIO_PIN, GPIO_PIN_HIGH);
    //  there is H/W reset complete time (tREST) within 5ms after a rising edge of RESX
    SysdelayMs(10);

    //  It resets the commands and parameters to their S/W Reset default values.
    hx8369_write_cmd(0x01);
    //  it will be necessary to wait 120msec before sending Sleep out command(0x11)
    SysdelayMs(120);

    // HX8369A+HSD3.97-RGB MODE'' Initial Code
    // set extended command set access enable
    hx8369_write_cmd(0xB9);
    hx8369_write_data(0xFF);
    hx8369_write_data(0x83);
    hx8369_write_data(0x69);

    // Set power
    hx8369_write_cmd(0xB1);
    hx8369_write_data(0x01);//0X01
    hx8369_write_data(0x00);
    hx8369_write_data(0x34);
    hx8369_write_data(0x07);
    hx8369_write_data(0x00);
    hx8369_write_data(0x0E);
    hx8369_write_data(0x0E);
    hx8369_write_data(0x21);// VSPR
    hx8369_write_data(0x29);// VSNR
    hx8369_write_data(0x3F);
    hx8369_write_data(0x3F);
    hx8369_write_data(0x01);
    hx8369_write_data(0x23);
    hx8369_write_data(0x01);
    hx8369_write_data(0xE6);
    hx8369_write_data(0xE6);
    hx8369_write_data(0xE6);
    hx8369_write_data(0xE6);
    hx8369_write_data(0xE6);

    // Set display related register
    hx8369_write_cmd(0xB2);
    hx8369_write_data(0x00);
    hx8369_write_data(0x29);
    // Specify the amount of scan line for back porch(BP).
    hx8369_write_data(0x07);
    // Specify the amount of scan line for front porch (FP).
    hx8369_write_data(0x08);
    hx8369_write_data(0x70);
    hx8369_write_data(0x00);
    hx8369_write_data(0xFF);
    hx8369_write_data(0x00);
    hx8369_write_data(0x00);
    hx8369_write_data(0x00);
    hx8369_write_data(0x00);
    hx8369_write_data(0x03);
    hx8369_write_data(0x03);
    hx8369_write_data(0x00);
    hx8369_write_data(0x01);

    //  Set RGB interface related register
    hx8369_write_cmd(0xB3);
    // DPL=0,HSPL=0,VSPL=0,EPL=1
    // DPL=0, the data is read on the rising edge of PCLK signal.
    // HSPL=0, the HS pin is Low active
    // VSPL=0, the VS pin is Low active.
    // EPL=1: DE = 0 Display:Disable, DE = 1 Display:Enable
    hx8369_write_data(0x01);

    // Set_address_mode
    hx8369_write_cmd(0x36);
    hx8369_write_data(0x00);

    // SETPANEL
    hx8369_write_cmd(0xCC);
    // SS_PANEL=0 source driver output from S1 to S1440
    // REV_PANEL = 0 normal-white panel
    // BGR_PANEL = 0 color filter of panel is <R><G><B> type
    hx8369_write_data(0x00);

    hx8369_write_cmd(0xB4);
    // 00: column, 05: 1dot, 0A: 2dot
    hx8369_write_data(0x0A);
    hx8369_write_data(0x0C);
    hx8369_write_data(0x84);
    hx8369_write_data(0x0C);
    hx8369_write_data(0x01);

    // SET VCOM -1.504V
    hx8369_write_cmd(0xB6);
    hx8369_write_data(0x1F);
    hx8369_write_data(0x1F);

    hx8369_write_cmd(0xD5);
    hx8369_write_data(0x00);//1,
    hx8369_write_data(0x03);//2,
    hx8369_write_data(0x00);//3,
    hx8369_write_data(0x00);//4,
    hx8369_write_data(0x01);//5,
    hx8369_write_data(0x06);//6,
    hx8369_write_data(0x10);//7,
    hx8369_write_data(0x80);//8,
    hx8369_write_data(0x33);//9,
    hx8369_write_data(0x37);//10,
    hx8369_write_data(0x23);//11,
    hx8369_write_data(0x01);//12,
    hx8369_write_data(0xB9);//13,
    hx8369_write_data(0x75);//14,
    hx8369_write_data(0xA8);//15,
    hx8369_write_data(0x64);//16,
    hx8369_write_data(0x00);//17,
    hx8369_write_data(0x00);//18,
    hx8369_write_data(0x41);//19,
    hx8369_write_data(0x06);//20,
    hx8369_write_data(0x50);//21,
    hx8369_write_data(0x07);//22,
    hx8369_write_data(0x07);//23,
    hx8369_write_data(0x0F);//24,
    hx8369_write_data(0x07);//25,
    hx8369_write_data(0x00);//26,

    hx8369_write_cmd(0xE0);
    hx8369_write_data(0x00);
    hx8369_write_data(0x03);
    hx8369_write_data(0x00);
    hx8369_write_data(0x09);
    hx8369_write_data(0x09);
    hx8369_write_data(0x21);
    hx8369_write_data(0x1B);
    hx8369_write_data(0x2D);
    hx8369_write_data(0x06);
    hx8369_write_data(0x0C);
    hx8369_write_data(0x10);
    hx8369_write_data(0x15);
    hx8369_write_data(0x16);
    hx8369_write_data(0x14);
    hx8369_write_data(0x16);
    hx8369_write_data(0x12);
    hx8369_write_data(0x18);
    hx8369_write_data(0x00);
    hx8369_write_data(0x03);
    hx8369_write_data(0x00);
    hx8369_write_data(0x09);
    hx8369_write_data(0x09);
    hx8369_write_data(0x21);
    hx8369_write_data(0x1B);
    hx8369_write_data(0x2D);
    hx8369_write_data(0x06);
    hx8369_write_data(0x0C);
    hx8369_write_data(0x10);
    hx8369_write_data(0x15);
    hx8369_write_data(0x16);
    hx8369_write_data(0x14);
    hx8369_write_data(0x16);
    hx8369_write_data(0x12);
    hx8369_write_data(0x18);

    // Set_pixel_forma
    hx8369_write_cmd(0x3A);
    // 0x77: 24bit, 0x66: 18bit, 0x55 16bit
    hx8369_write_data(0x77);

    // EXIT SLEEP MODE
    hx8369_write_cmd(0x11);
    //  It will be necessary to wait 5msec before sending next command
    SysdelayMs(10);

    // display on
    hx8369_write_cmd(0x29);
    // write RAM
    hx8369_write_cmd(0x2C);
}

AM335X LCD控制器结构

AM335X TFT-LCD控制器称为"raster",在AM335X_StarterWare找相关.c和.h文件即可。

其中FrameBuffer的数据是有格式的(并不是完全对应的屏幕显示的RGB数据)

对于不使用硬件调色板的场合,直接看下面红框内即可

posted @ 2021-08-15 15:31  Yanye  阅读(2689)  评论(0编辑  收藏  举报