MTK平台有个图层的概念。每个层的数据存放在不同的buffer中,这些buffer可以从LCD对应的寄存器中读出。具体的自己去查对应平台的规格书吧。
MTK的平台是你在blockwrite中通过STARTLCDTRANSFER打开这个寄存器对应的位,然后硬件把每一层图像中对应的像素点取出,然后通过硬件合成,把合成后的数据通过你在LCD_DATA_ADDR中设置的端口地址找到LCD接口,送入LCD中显示。
1,首先由应用建立一个layer,开一个存放LCD数据的BUFFER,然后把这个BUFFER的地址赋给LCD寄存器
gdi_layer_blt_ext() >> CONFIG_HARDWARE_LAYER >> config_lcd_layer_window()
{......
DRV_WriteReg32(lcd_layer_base_addr+0x0C,layer_data->frame_buffer_address);
}
这样数据源已经关联起来了,其实这里还会设置宽度和高度这些信息.
2,准备好数据源之后开始发指令进行DMA传输
gdi_layer_blt_ext() >> lcd_fb_update() >> MainLCD->BlockWrite()
{
START_LCD_TRANSFER
}
--------------------------------------------------------------------------------------
每个背景就是一个图形或图像填充起来的矩形,只要初始化结构提UI_filled_area,然后交由函数gui_draw_filled_area画出来即可。
typedef struct _UI_filled_area
{
U32 flags; //总控制标志
PU8 b; //背景图像
gradient_color *gc; //递进颜色
color c; //背景色
color ac; //替换色
color border_color; //边框颜色
color shadow_color; //阴影颜色
UI_transparent_color_type transparent_color; //透明色
} UI_filled_area;
flags = 类型标志|边框标志|阴影标志;
颜色为背景
void EntryScreenInternet(void)
{
UI_filled_area filler = {0};
EntryNewScreen(SCR_INT_MAIN, NULL, EntryScreenInternet, NULL);
entry_full_screen();
clear_screen_with_color(gui_color(0, 255, 0));
filler.flags = UI_FILLED_AREA_TYPE_COLOR|UI_FILLED_AREA_BORDER|UI_FILLED_AREA_SHADOW;
filler.c = UI_COLOR_GREY;
filler.border_color = UI_COLOR_DARK_GREY;
filler.shadow_color = UI_COLOR_3D_FILLER;
gui_draw_filled_area(20, 20, 156, 150, &filler);
ShowCategoryInternet();
SetKeyHandler(GoBackHistory, KEY_RSK, KEY_EVENT_UP);
}
递进颜色为背景
void EntryScreenInternet(void)
{
UI_filled_area filler = {0};
static color g_color[3] = {{255, 0, 0},{0, 255, 0},{0, 0, 255}};
static U8 perc[2] = {30, 70};
gradient_color gc = {g_color, perc, 3};
EntryNewScreen(SCR_INT_MAIN, NULL, EntryScreenInternet, NULL);
entry_full_screen();
clear_screen_with_color(gui_color(0, 255, 0));
filler.flags = UI_FILLED_AREA_TYPE_GRADIENT_COLOR;
filler.gc = &gc;
gui_draw_filled_area(20, 20, 156, 150, &filler);
ShowCategoryInternet();
SetKeyHandler(GoBackHistory, KEY_RSK, KEY_EVENT_UP);
}
递进色需要用到一个结构体gradient_color, 其定义如下:
typedef struct _gradient_color
{
color *c; 颜色列表,数量由最后一个参数N决定
U8 *p; 百分比列表,个数为N-1,依次表示两个相邻
颜色递进宽度占整个宽度的百分比
U8 n; 颜色数量
} gradient_color;
如上例,总共有三个颜色红,绿,蓝,其中红绿递进所占的百分比为30%,绿蓝递进所占的百分比为70%
另外还有两个参数控制递进色的显示方式:
UI_FILLED_AREA_HORIZONTAL_FILL: 水平方式递进显示,此为默认方式,可以不用设。
UI_FILLED_AREA_VERTICAL_FILL:垂直方式递进显示,从上到下递进显示。
UI_FILLED_AREA_FLIP_FILL:反转显示,将递进色从右至左,或从下至上显示。
图形为背景
void EntryScreenInternet(void)
{
UI_filled_area filler = {0};
EntryNewScreen(SCR_INT_MAIN, NULL, EntryScreenInternet, NULL);
entry_full_screen();
//clear_screen();
clear_screen_with_color(gui_color(0, 255, 0));
filler.flags = UI_FILLED_AREA_TYPE_BITMAP;
filler.b = GetImage(IMG_GLOBAL_SUB_MENU_BG);
gui_draw_filled_area(20, 20, 156, 150, &filler);
ShowCategoryInternet();
SetKeyHandler(GoBackHistory, KEY_RSK, KEY_EVENT_UP);
}
纹理为背景
纹理就是不停的用一副图填充背景,直到填满为止
filler.flags = UI_FILLED_AREA_TYPE_TEXTURE;
filler.b = GetImage(IMG_FLEXIBLE_TITLEBAR_BG);
gui_draw_filled_area(20, 20, 156, 150, &filler);
3D效果背景
filler.flags = UI_FILLED_AREA_TYPE_3D_BORDER;
filler.c = UI_COLOR_GREY;
gui_draw_filled_area(20, 20, 156, 150, &filler);
还有两种3D效果的背景
UI_FILLED_AREA_TYPE_CUSTOM_FILL_TYPE1
UI_FILLED_AREA_TYPE_CUSTOM_FILL_TYPE2
百页窗及十字纹
flags 等效的图像函数
UI_FILLED_AREA_TYPE_CROSS_HATCH_COLOR gui_cross_hatch_fill_rectangle
UI_FILLED_AREA_TYPE_HATCH_COLOR gui_hatch_fill_rectangle
UI_FILLED_AREA_TYPE_ALTERNATE_CROSS_HATCH_COLOR gui_alternate_cross_hatch_fill_rectangle
UI_FILLED_AREA_TYPE_ALTERNATE_HATCH_COLOR gui_alternate_hatch_fill_rectangle
背景动画
gdi_handle my_anim;
void EntryScreenInternet(void)
{
EntryNewScreen(SCR_INT_MAIN, NULL, EntryScreenInternet, NULL);
entry_full_screen();
clear_screen_with_color(gui_color(0, 255, 0));
gdi_anim_draw_id(0, 0, IMG_ID_PHNSET_ON_0, my_anim)
ShowCategoryInternet();
}
--------------------------------------------------------------------------------------
触摸屏,可以看作是一种硬件中断,在MTK里,表现为Event,event group等概念,源自于nucleus os。一个周期基本操作过程为:点触 -> 采样 -> 校准 -> 解析数据 -> MMI对应事件触发 -> 复位完成。
$(PROJECT)/custom/common/syscomp_tasks_create_func.c 这个文件,实现了很多tasks,触摸屏task创建 custom_tp_task_create 调用了tp_task_create, 具体的实现,在 $(PROJECT)/drv/src/touch_panel_main.c
$(PROJECT)/drv/src/touch_panel.c
所有的tasks创建函数参数都是comptask_handler_struct **handle ,这个结构体为:
typedef struct {
kal_task_func_ptr comp_entry_func;
task_init_func_ptr comp_init_func;
task_cfg_func_ptr comp_cfg_func;
task_reset_func_ptr comp_reset_func;
task_end_func_ptr comp_end_func;
} comptask_handler_struct;
注释也很明了,创建时,填充里面相应的回调函数即可。
函数tp_task_main几乎是最重要的了,首先数据初始化,进入while死循环,不断地从系统获取触摸事件,然后判断是否被按下或释放,并做相应的事件触发处理。讨论一下,这个死循环到底是什么回事呢?里面有意思的代码,仅仅一行:
kal_retrieve_eg_events(TP.event,1,KAL_OR_CONSUME,&event_group,KAL_SUSPEND);
它看起来有着GTK里 gtk_main() 函数般神秘,kal对nucleus os 进行了封装,我们看不到具体的实现,它“睡”一下,来等待事件的发生。
触摸屏现在只是单点触摸,传统的触控屏幕一次只能判断一个触控。 Handwriting,校准算法为三点校正法,就是定义三个点的坐标,触摸点以这三个点作为参考坐标,校准出点的位置,说简单点,解三元一次方程组。还有定义了很多handwriting area和control area,在某个区间(区域范围)属于某个area,判断查找基本是按table找了,具体的数字计算,转化公式蛮复杂的,想弄明白,非得好好静心描绘一张图不可。随便提一下,mtk里的数据查找算法,一般都是最基本的算法,反正达到目的实用就行。
读ADC数据,主要通过spi接口传输。更上一层的,从触摸屏取得的数据,放到一个buffer,供MMI去解析使用. interface/hwdrv/touch_panel_buff.h 里都以 #define的形式定义关于buffer的函数。
还有,就是中断,在Nucleus下,中断分两种,Low level 中断(Lisr)和High level 中断(Hisr),触摸屏里的中断采用的是后者。在eint_def.c 里是这样设置的:
#if defined(TOUCH_PANEL_SUPPORT) || defined(HAND_WRITING)
const kal_uint8 TOUCH_PANEL_EINT_NO = 2;
#endif
优先级算是比较靠前的。
关于设置屏与原理图的对应管脚在touch_panel_spi.h这个文件里,如果用 drv_tool工具配置的,有对应生成的代码,否则,就把默认值给修改。
-------------------------------------------------------------------------------------
6225的板子,用GPIO控制6302和PMIC,双卡模式切换正常,也能控制PMIC出来各路LDO,现在sleep后还有26ma左右的电流,发现SRCLKEN一直为高,导致VTCXO也是恒高,还有一个异常的情况是按键响应非常慢,几乎每个键要30秒才响应,后来焊上触摸IC,发现6301接的eint1脚在没有触击的情况下仍然不断输出中断信号,触摸屏不能用,但此时按键响应却OK了,但吹掉6301后按键响应又奇慢,软件里试过EINT_MASK(1)以及不注册touch_panel_hisr,都没有效果,后来把codebase的touch pannel支持去掉才OK,不贴6301也不会影响按键的响应,但待机电流仍然是近30ma,拿以前支持触摸的板子对比,就算吹掉6301也是不会影响按键的响应,请问有朋友见过这个情况吗
初步怀疑还是板子的中断问题,一直触发占用系统资源。如果能trace的话,在EINT.C文件,EINT_LISR()函数中做个中断计数,然后在某个位置打出来。看看是不是一直在产生中断。
-------------------------------------------------------------------------------------
首先 InitEvents() 初始化所有 清零
然后 注册各事件的处理方法 Set Event Handler
这时 当事件发生时 就会 Execute Protocol Handler
当然 清除全部也是有必要的 Clear All Event Handler
--------------------------------------------------
EINT_Set_HW_Debounce(TP.eint_chan, 5);
EINT_Registration(TP.eint_chan,KAL_TRUE,touch_panel_state,touch_panel_HISR, KAL_TRUE);
EINT_Mask(TP.eint_chan);
EINT_Registration这个是注册一个中断号;注册了一个响应执行函数touch_panel_HISR;
void touch_panel_HISR(void)
{
kal_set_eg_events(TP.event,1,KAL_OR);
if (touch_panel_state==touch_down_level)
{
#ifdef TOUCH_PANEL_DEBUG
dbg_printWithTime("touch down/r/n");
#endif
TP.state=DOWN;
}
else
{
#ifdef TOUCH_PANEL_DEBUG
dbg_printWithTime("touch up/r/n");
#endif
TP.state=UP;
}
touch_panel_state = !touch_panel_state;
EINT_Set_Polarity(TP.eint_chan,touch_panel_state);
EINT_UnMask(TP.eint_chan);
}
void touch_panel_HISR(void)
{
。。。。
kal_set_eg_events(TP.event,1,KAL_OR); //这里设置触摸屏消息
。。。。
}
然后在
void tp_task_main( task_entry_struct * task_entry_ptr )
{
。。。。
while (1)
{
kal_retrieve_eg_events(TP.event,1,KAL_OR_CONSUME
,&event_group,KAL_SUSPEND); //这里获得触摸屏消息
if(TP.state==DOWN)
{
touch_panel_down_hdr();
}
else
{
touch_panel_up_hdr();
}
}
}
-------------------------------------------------------------------------------------
曾在MTK6225平台上做过,设置一个GPIO口为中断来实现slide处理,
实现如下:
a:在GPIO Setting配置选该GPIO的默认方式为EINTx(x为你要设置的中断号0-7)
b:在EINT Setting配置该中断的信息
(EINT Var,Debounce time)
c:写中断处理函数,在程序中注册该中断...
-------------------------------------------------------------------------------------
MTK定时器消息机制分析