现在的位置: 首页 > 综合 > 正文

mtk 中断

2013年10月26日 ⁄ 综合 ⁄ 共 9819字 ⁄ 字号 评论关闭

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定时器消息机制分析

 

  • 1.   数据结构
         (1). stack_timer_struct
              定时器类型的信息结构( 其主要作用似乎是用以装载待发送的定时器消息数据 )
         (2). TIMERTABLE
              定时器队列节点结构( 其由主要元素mmi_frm_timer_type结构及链表指针两个元素组成 )
         (3). event_scheduler
              队列信息结构
         (4). mmi_frm_timer_type
              定时器信息结构
  • 2.   L4定时器初始化
         (1). 步骤
              ...-> 创建MMI Task -> 设置MMI Task初始化函数 -> 在该函数中调用 L4InitTimer
         (2). 作用
              初始化定时器队列并设置基本定时器1,2
  • 3.   发送定时器消息
         (1). 步骤
              StartTimer -> L4StartTimer
         (2). 两种类型的定时器
              MTK中有两种类型的定时器
              a.  NO_ALIGNMENT
                  非队列式的,即要求立即执行的定时器,时间到了就自动被reset.
              b.  ALIGNMENT
                  队列式的,  即可以通过队列操作,有一定的延时容忍的定时器 .                                   y
                  其基本执行流程: 执行定时器 --> 超时? --> 保存timer id,event id -- timer stop || no event ?----> END ;
                                       |               Y                                       N|
                                       |                                                        |
                                       ----------------------------------------------------------                            
              c.  除了触摸屏和手写,其他情况下的定时器一般都是队列式的.                                                                                      
                                                                                                              
         (3). L4StartTimer的作用
              判断将要发送的定时器ID,根据是否是队列类型传递给不同的队列结构(event_sheduler1/event_sheduler2) ;
         (4). TimerExpiry
                  这是作为参数传递给L4StartTimer的回调函数,由于MTK做了一定的封装,因此其内部具体回调触发过程
              无法得知,但根据猜测,应该是在定时时间一到,以中断的方式发出消息(MSG_ID_TIMER_EXPIRY),并将其写到
              MMI的循环队列.
                  该函数可能是在L4CallBackTimer中调用的,L4CallBackTimer的作用如下:
                  a.  重置当前定时器信息结构(mmi_frm_timer_type) ;
                  b.  执行定时器到点后的执行函数(TimerExpiry) ;
                  c.  讲Timer消息写到MMI循环队列中 .
  • 4.   与StartTimer对应的StopTimer
         (1). 具体实现通过调用L4StopTimer操作.
         (2). 作用: 找出指定要停止的定时器ID在队列中的位置,然后使用evshed_cancel_event将指定定时器节点从队列
                    中删除.
                   
    5.   定时器消息的处理
         (1). 步骤
              ...-> 创建MMI Task -> 设置MMI Task入口函数 -> 调用 EvshedMMITimerHandler
         (2). evshed_timer_handler( ) -> 处理具体的定时器事件
        
    6.   小结
         简单分析MTK定时器消息事件

抱歉!评论已关闭.