看RM970原理图得知LCD中IM0 IM1 ID0都接上了GND,查LCD(控制器为SPFD5420A)得知,此时LCD工作于18bit,80-system.既为最常见的MCU接口.所以配置RK2706来说是这么一个通用流程:
1.设置相应引脚为LCD功能
void iomux_lcd(void)
{
unsigned long muxa;
muxa = SCU_IOMUXA_CON & ~(IOMUX_LCD_VSYNC|IOMUX_LCD_DEN|0xff);
muxa |= IOMUX_LCD_D18|IOMUX_LCD_D20|IOMUX_LCD_D22|IOMUX_LCD_D17|IOMUX_LCD_D16;
SCU_IOMUXA_CON = muxa;
SCU_IOMUXB_CON |=
IOMUX_LCD_D815;
}
2.设置LCD寄存器,配置时序.
void lcdctrl_init(void)
{
/* alpha b111
* stop at current frame complete
* MCU mode
* 24b RGB
*/
LCDC_CTRL = ALPHA(7) | LCDC_STOP | LCDC_MCU | RGB24B;
MCU_CTRL = ALPHA_BASE(0x3f) | MCU_CTRL_BYPASS;
HOR_ACT = 400 + 3; /* define horizonatal active region */ VERT_ACT = 240; /* define vertical active region */
VERT_PERIOD = 0xfff; /* CSn/WEn/RDn signal timings */
LINE0_YADDR = LINE_ALPHA_EN | 0x7fe;
LINE1_YADDR = LINE_ALPHA_EN | ((1 * 400) - 2);
LINE2_YADDR = LINE_ALPHA_EN | ((2 * 400) - 2);
LINE3_YADDR = LINE_ALPHA_EN | ((3 * 400) - 2);
LINE0_UVADDR = 0x7fe + 1;
LINE1_UVADDR = ((1 * 400) - 2 + 1);
LINE2_UVADDR = ((2 * 400) - 2 + 1);
LINE3_UVADDR = ((3 * 400) - 2 + 1);
LCDC_INTR_MASK = INTR_MASK_LINE; /* INTR_MASK_EVENLINE; */
}
3.初始化LCD寄存器.
void lcd_init_device()
{
unsigned int x, y;
iomux_lcd(); /* setup pins for 18bit lcd interface */
lcdctrl_init(); /* basic lcdc module configuration */
lcdctrl_bypass(1); /* run in bypass mode - all writes goes directly to lcd controller */
lcd_write_reg(RESET, 0x0001);
delay_nop(10000);
lcd_write_reg(RESET, 0x0000);
delay_nop(10000);
lcd_write_reg(IF_ENDIAN, 0x0000); /* order of receiving data */
lcd_write_reg(DRIVER_OUT_CTRL, 0x0000);
lcd_write_reg(ENTRY_MODE, 0x1038);
lcd_write_reg(WAVEFORM_CTRL, 0x0100);
lcd_write_reg(SHAPENING_CTRL, 0x0000);
lcd_write_reg(DISPLAY_CTRL2, 0x0808);
lcd_write_reg(LOW_PWR_CTRL1, 0x0001);
lcd_write_reg(LOW_PWR_CTRL2, 0x0010);
lcd_write_reg(EXT_DISP_CTRL1, 0x0000);
lcd_write_reg(EXT_DISP_CTRL2, 0x0000);
lcd_write_reg(BASE_IMG_SIZE, 0x3100);
......................
}
细心的朋友会发现这些寄存器初始值都为16bit,而LCD为18bit,所以得用下面函数转换成18bit后才能写给LCD.
__inline unsigned int lcd_data_transform(unsigned int data)
{
/* 18 bit interface */
unsigned int r, g, b;
r = (data & 0x0000fc00)<<8;
g = ((data & 0x00000300) << 6) | ((data & 0x000000e0) << 5);
b = (data & 0x00000001f) << 3;
return (r | g | b);
}
初试化完毕后,一个不约而同的规则便是实现画横竖线与打点了.
/* 画水平线 */
void rt_hw_lcd_draw_hline(rtgui_color_t *c, rt_base_t x1, rt_base_t x2, rt_base_t y)
{
lcd_write_reg(WINDOW_H_START, y);
lcd_write_reg(WINDOW_H_END, y);
lcd_write_reg(WINDOW_V_START, x1);
lcd_write_reg(WINDOW_V_END, x2);
lcd_write_reg(GRAM_H_ADDR, y);
lcd_write_reg(GRAM_V_ADDR, x1);
lcd_cmd(GRAM_WRITE); /* Prepare to write GRAM */
while (x1 < x2)
{
LCD_DATA = lcd_pixel_transform(*c);
x1++;
}
}
/* 垂直线 */
void rt_hw_lcd_draw_vline(rtgui_color_t *c, rt_base_t x, rt_base_t y1, rt_base_t y2)
{
lcd_write_reg(WINDOW_H_START, y1);
lcd_write_reg(WINDOW_H_END, y2);
lcd_write_reg(WINDOW_V_START, x);
lcd_write_reg(WINDOW_V_END, x);
lcd_SetCursor(x, y1);
lcd_cmd(GRAM_WRITE); /* Prepare to write GRAM */
while (y1 < y2)
{
LCD_DATA = lcd_pixel_transform(*c);
y1++;
}
}
/* 设置像素点 颜色,X,Y */
void rt_hw_lcd_set_pixel(rtgui_color_t *c, rt_base_t x, rt_base_t y)
{
lcd_write_reg(WINDOW_H_START, y);
lcd_write_reg(WINDOW_H_END, y);
lcd_write_reg(WINDOW_V_START, x);
lcd_write_reg(WINDOW_V_END, x);
lcd_SetCursor(x,y);
lcd_cmd(GRAM_WRITE);
LCD_DATA = lcd_pixel_transform(*c);
}
注意这SPFD5420A打点函数与常见的控制器还不一样,还要设置窗口为此点.要不然会有些莫名奇妙的问题.(起码这边测试的是这样).
实现打点函数后便可以将printf定位到LCD了,新建Retarget.c文件,在里面实现fputc()函数
int fputc(int ch, FILE *f)
{
int MaxX = 400 / 6;
int MaxY = 240 / 12;
int n;
if(ch != '
' && ch != '
' && ch != '')
{
lcd_show_char(CurrentX*6, ((CurrentY + MaxY)%MaxY)*12, ch);
}
CurrentX++;
return 1;
}
这里并没考虑更多情况,请各位按需要自行改进.
最后顺便在rtthread.h加上:
#define rt_kprintf printf
两个应该注意的地方.一是记得开背光,二是Options-Target-Use Micro LIB选项记得勾上,而且启动代码中Micro_Lib_Stack_Size宏大小最好相应改大.
如无意外printf,与rt_kprintf都已经定位到LCD了.