由于板子LCD旧屏是ili9335型号的,旧屏有时候会断货,如果断货则使用一个st7789v型号的LCD
它们两个屏的区别在于初始化屏的参数不同,引脚都一样,也就是说需要使板子同时支持ili9335型号和st7789v型号
思路:
1.uboot在显示LOG初始化屏参数)之前,通过命令来读LCD型号,来检测LCD型号,然后来修改初始化屏的参数.
2.如果屏是新屏,则设置bootargs,向内核传递参数lcd_type=new
3.当kernel收到参数lcd_type=new时,则在初始化LCD之前,修改屏的参数.
改uboot
首先来看单板配置信息,根据配置找到哪个文件是初始化LCD屏的
根据make ap60pro_uImage_sfc_nand命令,找ap60pro_uImage_sfc_nand单板信息
vi ./u-boot/boards.cfg
找到:
# Target ARCH CPU Board name Vendor SoC Options
##############################################################
ap60pro_uImage_sfc_nand mips xburst ap60pro ingenic x1000 ap60pro:SPL_SFC_NAND,LIBSLEEP,GET_BT_MAC
从上面看到board name为ap60pro,所以最终通过下面几个来初始化:
./arch/mips/cpu/xburstx1000start.S //启动代码
./include/configs/ap60pro.h //各种define配置
./board/ingenic/ap60pro //单板配置源文件
查看ap60pro.h,查看LCD相关的define配置
查找CONFIG_ILI9335_240X320,找到在./board/ingenic/ap60pro/Makefile里调用:
COBJS-$CONFIG_ILI9335_240X320) += lcd-ili9335_240x320.o //保存LCD初始化参数的信息
查找CONFIG_ILI9335_240X320,找到在./drivers/video/Makefile里调用:
COBJS-$CONFIG_JZ_LCD_V13) += jz_lcd/jz_lcd_v13.o //根据lcd-ili9335_240*320.c来初始化LCD
修改lcd-ili9335_240x320.c
添加st7789v初始化的数组表在代码中以New_ili9335_data_table数组表示):
struct smart_lcd_data_table ili9335_data_table[] = { //旧屏的初始化参数表
{SMART_CONFIG_CMD,0x00},
{SMART_CONFIG_CMD,0xec},
{SMART_CONFIG_DATA,0x1e},
{SMART_CONFIG_DATA,0x8f},
{SMART_CONFIG_CMD,0x00},
{SMART_CONFIG_CMD,0x01},
{SMART_CONFIG_DATA,0x01},
{SMART_CONFIG_DATA,0x00},
{SMART_CONFIG_CMD,0x00},
{SMART_CONFIG_CMD,0x02},
{SMART_CONFIG_DATA,0x02},
{SMART_CONFIG_DATA,0x00},
{SMART_CONFIG_CMD,0x00},
{SMART_CONFIG_CMD,0x03},
{SMART_CONFIG_DATA,0x10},
{SMART_CONFIG_DATA,0x30},
{SMART_CONFIG_UDELAY,10000},
{SMART_CONFIG_CMD,0x00},
{SMART_CONFIG_CMD,0x08},
{SMART_CONFIG_DATA,0x02},
{SMART_CONFIG_DATA,0x02},
{SMART_CONFIG_CMD,0x00},
{SMART_CONFIG_CMD,0x09},
{SMART_CONFIG_DATA,0x00},
{SMART_CONFIG_DATA,0x00},
{SMART_CONFIG_CMD,0x00},
{SMART_CONFIG_CMD,0x0a},
{SMART_CONFIG_DATA,0x00},
{SMART_CONFIG_DATA,0x08}, //enable te
{SMART_CONFIG_CMD,0x00},
{SMART_CONFIG_CMD,0x0d},
{SMART_CONFIG_DATA,0x00},
{SMART_CONFIG_DATA,0x00},
{SMART_CONFIG_CMD,0x00},
{SMART_CONFIG_CMD,0x0f},
{SMART_CONFIG_DATA,0x00},
{SMART_CONFIG_DATA,0x00},
{SMART_CONFIG_CMD,0x00},
{SMART_CONFIG_CMD,0x60},
{SMART_CONFIG_DATA,0x27},
{SMART_CONFIG_DATA,0x00},
{SMART_CONFIG_CMD,0x00},
{SMART_CONFIG_CMD,0x61},
{SMART_CONFIG_DATA,0x00},
{SMART_CONFIG_DATA,0x00},
{SMART_CONFIG_CMD,0x00},
{SMART_CONFIG_CMD,0x6a},
{SMART_CONFIG_DATA,0x00},
{SMART_CONFIG_DATA,0x00},
{SMART_CONFIG_UDELAY,10000},
{SMART_CONFIG_CMD,0x00},
{SMART_CONFIG_CMD,0x10},
{SMART_CONFIG_DATA,0x16},
{SMART_CONFIG_DATA,0x90},
{SMART_CONFIG_CMD,0x00},
{SMART_CONFIG_CMD,0x11},
{SMART_CONFIG_DATA,0x02},
{SMART_CONFIG_DATA,0x27},
{SMART_CONFIG_UDELAY,10000},
{SMART_CONFIG_CMD,0x00},
{SMART_CONFIG_CMD,0x12},
{SMART_CONFIG_DATA,0x00},
{SMART_CONFIG_DATA,0x0d},
{SMART_CONFIG_UDELAY,10000},
{SMART_CONFIG_CMD,0x00},
{SMART_CONFIG_CMD,0x21},
{SMART_CONFIG_DATA,0x16},
{SMART_CONFIG_DATA,0x00},
{SMART_CONFIG_CMD,0x00},
{SMART_CONFIG_CMD,0x29},
{SMART_CONFIG_DATA,0x00},
{SMART_CONFIG_DATA,0x18},
{SMART_CONFIG_CMD,0x00},
{SMART_CONFIG_CMD,0x2b},
{SMART_CONFIG_DATA,0x00},
{SMART_CONFIG_DATA,0x0a},
{SMART_CONFIG_UDELAY,10000},
{SMART_CONFIG_CMD,0x00},
{SMART_CONFIG_CMD,0x20},
{SMART_CONFIG_DATA,0x00},
{SMART_CONFIG_DATA,0x00},
{SMART_CONFIG_CMD,0x00},
{SMART_CONFIG_CMD,0x21},
{SMART_CONFIG_DATA,0x00},
{SMART_CONFIG_DATA,0x00},
//============Gamma============
{SMART_CONFIG_CMD,0x00},
{SMART_CONFIG_CMD,0x30},
{SMART_CONFIG_DATA,0x04},
{SMART_CONFIG_DATA,0x03},
{SMART_CONFIG_CMD,0x00},
{SMART_CONFIG_CMD,0x31},
{SMART_CONFIG_DATA,0x00},
{SMART_CONFIG_DATA,0x07},
{SMART_CONFIG_CMD,0x00},
{SMART_CONFIG_CMD,0x32},
{SMART_CONFIG_DATA,0x04},
{SMART_CONFIG_DATA,0x04},
{SMART_CONFIG_CMD,0x00},
{SMART_CONFIG_CMD,0x35},
{SMART_CONFIG_DATA,0x00},
{SMART_CONFIG_DATA,0x02},
{SMART_CONFIG_CMD,0x00},
{SMART_CONFIG_CMD,0x36},
{SMART_CONFIG_DATA,0x00},
{SMART_CONFIG_DATA,0x0f},
{SMART_CONFIG_CMD,0x00},
{SMART_CONFIG_CMD,0x37},
{SMART_CONFIG_DATA,0x00},
{SMART_CONFIG_DATA,0x03},
{SMART_CONFIG_CMD,0x00},
{SMART_CONFIG_CMD,0x38},
{SMART_CONFIG_DATA,0x00},
{SMART_CONFIG_DATA,0x00},
{SMART_CONFIG_CMD,0x00},
{SMART_CONFIG_CMD,0x39},
{SMART_CONFIG_DATA,0x03},
{SMART_CONFIG_DATA,0x02},
{SMART_CONFIG_CMD,0x00},
{SMART_CONFIG_CMD,0x3c},
{SMART_CONFIG_DATA,0x02},
{SMART_CONFIG_DATA,0x00},
{SMART_CONFIG_CMD,0x00},
{SMART_CONFIG_CMD,0x3d},
{SMART_CONFIG_DATA,0x0f},
{SMART_CONFIG_DATA,0x00},
//=============================
// set RAM address
{SMART_CONFIG_CMD,0x00},
{SMART_CONFIG_CMD,0x50},
{SMART_CONFIG_DATA,0x00},
{SMART_CONFIG_DATA,0x00},
{SMART_CONFIG_CMD,0x00},
{SMART_CONFIG_CMD,0x51},
{SMART_CONFIG_DATA,0x00},
{SMART_CONFIG_DATA,0xef},
{SMART_CONFIG_CMD,0x00},
{SMART_CONFIG_CMD,0x52},
{SMART_CONFIG_DATA,0x00},
{SMART_CONFIG_DATA,0x00},
{SMART_CONFIG_CMD,0x00},
{SMART_CONFIG_CMD,0x53},
{SMART_CONFIG_DATA,0x01},
{SMART_CONFIG_DATA,0x3f},
{SMART_CONFIG_UDELAY,10000},
{SMART_CONFIG_CMD,0x00},
{SMART_CONFIG_CMD,0x80},
{SMART_CONFIG_DATA,0x00},
{SMART_CONFIG_DATA,0x00},
{SMART_CONFIG_CMD,0x00},
{SMART_CONFIG_CMD,0x81},
{SMART_CONFIG_DATA,0x00},
{SMART_CONFIG_DATA,0x00},
{SMART_CONFIG_CMD,0x00},
{SMART_CONFIG_CMD,0x82},
{SMART_CONFIG_DATA,0x00},
{SMART_CONFIG_DATA,0x00},
{SMART_CONFIG_CMD,0x00},
{SMART_CONFIG_CMD,0x83},
{SMART_CONFIG_DATA,0x00},
{SMART_CONFIG_DATA,0x00},
{SMART_CONFIG_CMD,0x00},
{SMART_CONFIG_CMD,0x84},
{SMART_CONFIG_DATA,0x00},
{SMART_CONFIG_DATA,0x00},
{SMART_CONFIG_CMD,0x00},
{SMART_CONFIG_CMD,0x85},
{SMART_CONFIG_DATA,0x00},
{SMART_CONFIG_DATA,0x00},
{SMART_CONFIG_CMD,0x00},
{SMART_CONFIG_CMD,0x90},
{SMART_CONFIG_DATA,0x00},
{SMART_CONFIG_DATA,0x10},
{SMART_CONFIG_CMD,0x00},
{SMART_CONFIG_CMD,0x91},
{SMART_CONFIG_DATA,0x06},
{SMART_CONFIG_DATA,0x00},
//display on
{SMART_CONFIG_CMD,0x00},
{SMART_CONFIG_CMD,0x07},
{SMART_CONFIG_DATA,0x01},
{SMART_CONFIG_DATA,0x33},
{SMART_CONFIG_CMD,0x00},
{SMART_CONFIG_CMD,0x22},
};
unsigned long truly_cmd_buf[]= {
0x22002200,
};
struct jzfb_config_info jzfb1_init_data = {
.num_modes = 1,
.modes = &jzfb1_videomode,
.lcd_type = LCD_TYPE_SLCD,
.bpp = 24, //R8G8B8
.pinmd = 0,
.smart_config.rsply_cmd_high = 0,
.smart_config.csply_active_high = 0,
/* write graphic ram command, in word, for example 8-bit bus, write_gram_cmd=C3C2C1C0. */
.smart_config.newcfg_fmt_conv = 0,
.smart_config.clkply_active_rising = 1,
.smart_config.data_times = 2,
.smart_config.write_gram_cmd = truly_cmd_buf,
.smart_config.length_cmd = ARRAY_SIZEtruly_cmd_buf),
.smart_config.bus_width = 8, //总线8位的
.smart_config.length_data_table = ARRAY_SIZEili9335_data_table),
.smart_config.data_table = ili9335_data_table,
.dither_enable = 1,
};
//新屏的初始化参数表
static struct smart_lcd_data_table New_ili9335_data_table[] = {
{SMART_CONFIG_CMD,0x11},
{SMART_CONFIG_UDELAY,120000}, //Sleep out
{SMART_CONFIG_CMD,0x36}, //控制
{SMART_CONFIG_DATA,0x00},
{SMART_CONFIG_CMD,0x21}, //0x13显示不反转 ,21h 反显
{SMART_CONFIG_CMD,0x3A},
{SMART_CONFIG_DATA,0x05},
{SMART_CONFIG_CMD,0x2A},
{SMART_CONFIG_DATA,0x00},
{SMART_CONFIG_DATA,0x00},
{SMART_CONFIG_DATA,0x00},
{SMART_CONFIG_DATA,0xEF},
{SMART_CONFIG_CMD,0x2B},
{SMART_CONFIG_DATA,0x00},
{SMART_CONFIG_DATA,0x00},
{SMART_CONFIG_DATA,0x01},
{SMART_CONFIG_DATA,0x3F},
{SMART_CONFIG_CMD,0xB2}, //前后肩
{SMART_CONFIG_DATA,0x0C},
{SMART_CONFIG_DATA,0x0C},
{SMART_CONFIG_DATA,0x00},
{SMART_CONFIG_DATA,0x33},
{SMART_CONFIG_DATA,0x33},
{SMART_CONFIG_CMD,0xB7}, //VGH VGL
{SMART_CONFIG_DATA,0x35},
{SMART_CONFIG_CMD,0xBB}, //VCOM
{SMART_CONFIG_DATA,0x1E},
{SMART_CONFIG_CMD,0xC0}, //LCM
{SMART_CONFIG_DATA,0x2C},
{SMART_CONFIG_CMD,0xC2},
{SMART_CONFIG_DATA,0x01},
{SMART_CONFIG_CMD,0xC3}, //VRH vcom+vcom offset+vdv)
{SMART_CONFIG_DATA,0x27},
{SMART_CONFIG_CMD,0xC4}, //vdv
{SMART_CONFIG_DATA,0x20},
{SMART_CONFIG_CMD,0xC6}, //帧率
{SMART_CONFIG_DATA,0x0F},
{SMART_CONFIG_CMD,0xD0}, //功率控制模式
{SMART_CONFIG_DATA,0xA4},
{SMART_CONFIG_DATA,0xA1},
{SMART_CONFIG_CMD,0xE0}, //正GAMMA
{SMART_CONFIG_DATA,0xD0},
{SMART_CONFIG_DATA,0x00},
{SMART_CONFIG_DATA,0x05},
{SMART_CONFIG_DATA,0x03},
{SMART_CONFIG_DATA,0x02},
{SMART_CONFIG_DATA,0x07},
{SMART_CONFIG_DATA,0x3F},
{SMART_CONFIG_DATA,0x55},
{SMART_CONFIG_DATA,0x50},
{SMART_CONFIG_DATA,0x09},
{SMART_CONFIG_DATA,0x14},
{SMART_CONFIG_DATA,0x15},
{SMART_CONFIG_DATA,0x22},
{SMART_CONFIG_DATA,0x25},
{SMART_CONFIG_CMD,0xE1}, //负GAMMA
{SMART_CONFIG_DATA,0xD0},
{SMART_CONFIG_DATA,0x00},
{SMART_CONFIG_DATA,0x05},
{SMART_CONFIG_DATA,0x03},
{SMART_CONFIG_DATA,0x02},
{SMART_CONFIG_DATA,0x07},
{SMART_CONFIG_DATA,0x3F},
{SMART_CONFIG_DATA,0x55},
{SMART_CONFIG_DATA,0x54},
{SMART_CONFIG_DATA,0x0C},
{SMART_CONFIG_DATA,0x18},
{SMART_CONFIG_DATA,0x14},
{SMART_CONFIG_DATA,0x22},
{SMART_CONFIG_DATA,0x25},
{SMART_CONFIG_CMD,0x11}, // sleep out
{SMART_CONFIG_UDELAY,120000},
{SMART_CONFIG_CMD,0x29},//Display On
{SMART_CONFIG_UDELAY,20000},
};
unsigned long New_truly_cmd_buf[]= {
0x2C2C2C2C,
};
void switch_lcd_Newvoid) //切换为ST7789V
{
jzfb1_init_data.smart_config.data_table = New_ili9335_data_table;
jzfb1_init_data.smart_config.length_data_table = ARRAY_SIZENew_ili9335_data_table);
jzfb1_init_data.smart_config.write_gram_cmd = New_truly_cmd_buf;
}
//... ...
查看jz_lcd_v13.c调用顺序
从uboot启动时,调用board_init_r)函数开始:
-> board_init_r)
-> stdio_init)
-> drv_lcd_init) //初始化硬件LCD
-> drv_video_init) //绘制log
其中drv_lcd_init)中调用顺序为:
-> drv_lcd_init)
-> lcd_init)
-> lcd_ctrl_init) // 位于driversvideojz_lcdJz_lcd_v13.c
所以,接下来,我们便来修改jz_lcd_v13.c,让uboot在初始化LCD之前,读LCD的ID,是否需要切换新屏参数
修改jz_lcd_v13.c
由于X1000的SLCD控制寄存器只能向LCD写命令/数据,没有读数据的寄存器,所以我们便需要使用GPIO来模拟时序,读出ID来
参考ST7789V数据手册,找到ID命令为04h:
参考ST7789V数据手册,找到读写8080时序图:
接下来开始改代码:
//添加下面函数,通过GPIO模拟LCD寄存器,来实现读ID void gpio_setfuncunsigned int gpioPort,enum gpio_function fun) { enum gpio_port port; switchgpioPort /32)) { case 0: port = GPIO_PORT_A; break; case 1: port = GPIO_PORT_B; break; case 2: port = GPIO_PORT_C; break; case 3: port = GPIO_PORT_D; break; default: port = GPIO_NR_PORTS; break; } gpio_set_funcport, fun, 1<< gpioPort % 32)); iffun == GPIO_OUTPUT0||fun == GPIO_OUTPUT1) { iffun == GPIO_OUTPUT0) gpio_direction_outputgpioPort, 0); else gpio_direction_outputgpioPort, 1); } } static void write_SLCD_CDint isCOMD,unsigned int value) //写命令/数据 { #define SLCD_DC 20 #define SLCD_WR 17 #define SLCD_RD 16 #define SLCD_CS 18 int i; gpio_direction_outputGPIO_PBSLCD_CS), 1); for i=0;i<8;i++) { gpio_setfuncGPIO_PAi),GPIO_OUTPUT0); gpio_direction_outputGPIO_PAi), value>>i)&0x01); } mdelay10); ifisCOMD!=0) //如果是写命令,则拉低DC脚 { gpio_direction_outputGPIO_PBSLCD_DC), 0); } else { gpio_direction_outputGPIO_PBSLCD_DC),1); } gpio_direction_outputGPIO_PBSLCD_WR), 0); gpio_direction_outputGPIO_PBSLCD_RD), 1); gpio_direction_outputGPIO_PBSLCD_CS), 0); mdelay4); gpio_direction_outputGPIO_PBSLCD_WR), 1); mdelay7); } static unsigned int read_SLCD_DATAvoid) //读数据 { #define SLCD_DC 20 #define SLCD_WR 17 #define SLCD_RD 16 #define SLCD_CS 18 int i; int ret=0; gpio_direction_outputGPIO_PBSLCD_CS), 1); //取消片选 for i=0;i<8;i++) //将data脚设为输入脚 { gpio_setfuncGPIO_PAi),GPIO_INPUT); } gpio_direction_outputGPIO_PBSLCD_DC), 1); gpio_direction_outputGPIO_PBSLCD_WR), 1); gpio_direction_outputGPIO_PBSLCD_RD), 0); gpio_direction_outputGPIO_PBSLCD_CS), 0); //选中片选 mdelay4); gpio_direction_outputGPIO_PBSLCD_RD), 1); for i=0;i<8;i++) ret|=gpio_get_valueGPIO_PAi))<<i); mdelay7); return ret; } static void lcd_func_initint isRestore) { int i,n; #define SLCD_DC 20 #define SLCD_WR 17 #define SLCD_RD 16 #define SLCD_TE 19 //input #define SLCD_CS 18 ifisRestore) //恢复管脚为LCD控制寄存器 { fori=0;i<8;i++) gpio_setfuncGPIO_PAi),GPIO_FUNC_1); gpio_setfuncGPIO_PBSLCD_DC),GPIO_FUNC_1); gpio_setfuncGPIO_PBSLCD_WR),GPIO_FUNC_1); gpio_setfuncGPIO_PBSLCD_RD),GPIO_FUNC_1); gpio_setfuncGPIO_PBSLCD_TE),GPIO_FUNC_1); gpio_setfuncGPIO_PBSLCD_CS),GPIO_FUNC_1); } else //设置为普通IO管脚 { fori=0;i<8;i++) gpio_setfuncGPIO_PAi),GPIO_OUTPUT0); gpio_setfuncGPIO_PBSLCD_DC),GPIO_OUTPUT0); gpio_setfuncGPIO_PBSLCD_WR),GPIO_OUTPUT0); gpio_setfuncGPIO_PBSLCD_RD),GPIO_OUTPUT0); gpio_setfuncGPIO_PBSLCD_TE),GPIO_INPUT); gpio_setfuncGPIO_PBSLCD_CS),GPIO_OUTPUT0); } mdelay200); } static u8 Read_ID_isNewLcdvoid) { #define SLCD_DC 20 #define SLCD_WR 17 #define SLCD_RD 16 #define SLCD_TE 19 //input #define SLCD_CS 18 u8 ret = 0; u8 IDH,IDL; lcd_func_init0); //设置LCD相关的引脚,设置为普通IO脚
write_SLCD_CD1,0x04); //写入0x04命令 IDH = read_SLCD_DATA); IDL = read_SLCD_DATA); printf"Read ID: 0x%X 0x%X ",IDH,IDL); IDH = read_SLCD_DATA); IDL = read_SLCD_DATA); printf"Read ID: 0x%X 0x%X ",IDH,IDL); ifIDL!=0x52) //如果值!=0X52,则表示是旧屏ili9335 { ret =1; } lcd_func_init1); //将lcd相关引脚配置为LCD控制脚 mdelay10); return ret; } extern void switch_lcd_Newvoid) ; static int lcd_type_isNew=0; void set_lcd_type_from_cmdlinevoid) //设置bootargs,向内核传递lcd_type参数 { iflcd_type_isNew) { run_command"set bootargs "CONFIG_BOOTARGS" lcd_type=new ", 0); } }
//在lcd_ctrl_init)函数里添加读ID函数 void lcd_ctrl_initvoid *lcd_base) { ifRead_ID_isNewLcd)==0) //读ID,检测是否是新屏 { printf"Read_ID_isNewLcd=0 "); switch_lcd_New); //调用Lcd-ili9335_240x320.c的切换新屏参数的函数 lcd_type_isNew=1; } //... ... 后面的代码不需要修改,因为后面便会根据LCD初始化参数表.来初始化LCD }
上面的set_lcd_type_from_cmdline)函数需要在后面调用main_loop)的时候之前被调用,所以还需要修改board_init_r)函数archmipslibBoard.c ).
然后装上旧屏ili9335,启动uboot,查看读的屏幕ID,屏幕显示正常:
然后换为新屏,启动uboot,查看读的ID信息,log显示正常:
启动内核时,也可以看到传递给内核bootargs有我们新添的参数:
然后在内核中,便通过新参数再次设置屏参数表即可.