Saturday, May 26, 2012

Bootloader與Kernel間參數傳遞機制




Tag list 被用來在 bootloader  linux kernel 之間傳遞參數,這裡分析一下相關的數據結構,主要包括兩個部分: Tag list  Tag parser list 
先來看 Tag list 
這個 list 是在 bootloader 中填充的,其數據結構定義在 bootloader  linux kernel 中均有定義,是一致的。我們來看 linux kernel 中的定義:

top/arch/arm/include/asm/setup.h
struct tag {
    struct tag_header hdr;
    union {
        struct tag_core        core;
        struct tag_mem32    mem;
        struct tag_videotext    videotext;
        struct tag_ramdisk    ramdisk;
        struct tag_initrd    initrd;
        struct tag_serialnr    serialnr;
        struct tag_revision    revision;
        struct tag_videolfb    videolfb;
        struct tag_cmdline    cmdline;
        /*
         * Acorn specific
         */

        struct tag_acorn    acorn;
        /*
         * DC21285 specific
         */

        struct tag_memclk    memclk;
    } u;
} ;
struct tag_header {
    __u32 size;
    __u32 tag;
} ;

其中 tag 的取值如下,暫且稱之為 tag type :

# define ATAG_CORE            0x54410001
# define ATAG_MEM            0x54410002
# define ATAG_VIDEOTEXT        0x54410003
# define ATAG_RAMDISK        0x54410004
# define ATAG_INITRD            0x54410005
# define ATAG_INITRD2        0x54420005
# define ATAG_SERIAL            0x54410006
# define ATAG_REVISION        0x54410007
# define ATAG_VIDEOLFB        0x54410008
# define ATAG_CMDLINE        0x54410009
# define ATAG_ACORN            0x41000101
# define ATAG_MEMCLK        0x41000402

其數據結構用圖形表示就是:
 
其實就是一個鏈表,通過 Tag size 以及當前 tag 的位置來定位下一個 tag 的位置。而且第一個 tag 的類型必然是 ATAG_CORE 

參數就是按照這個結構進行傳遞的,那麼 kernel 是如何進行解析的呢?
我們來看 tag parser list:
同樣是在 top/arch/arm/include/asm/setup.h ,有如下定義:

top/arch/arm/include/asm/setup.h
struct tagtable {
    __u32 tag;
    int ( * parse) ( const struct tag * ) ;
} ;
# define __tag __used __attribute__( ( __section__( ".taglist.init" ) ) )
# define __tagtable( tag, fn) /
static struct tagtable __tagtable_# # fn __tag = { tag, fn }

從上面知道, tag parser list 存在於 .taglist.init 段,他們的定義將通過宏 __tagtable(tag, fn) 的形式給出,比如在 top/arch/arm/kernel/setup.c 中:

top/arch/arm/kernel/setup.c
__tagtable( ATAG_CORE, parse_tag_core) ;
__tagtable( ATAG_MEM, parse_tag_mem32) ;
__tagtable( ATAG_VIDEOTEXT, parse_tag_videotext) ;
__tagtable( ATAG_RAMDISK, parse_tag_ramdisk) ;
__tagtable( ATAG_SERIAL, parse_tag_serialnr) ;
__tagtable( ATAG_REVISION, parse_tag_revision) ;
__tagtable( ATAG_CMDLINE, parse_tag_cmdline) ;

通過這樣的定義,每個 tag table 的表項就自 動連接在了一起,而且存在於同一個段中。如圖所示:
可以看到,所有支持的 tag parser 都列在這 裡了。
 kernel 中,將針對 tag list 中的每一項在這個 tag parser list 中進行查找,如果有 對應的處理項,則調用解析函數,於是就完成了參數的傳遞以及解析!

注意:
 top/arch/arm/kernel/head-common.s 中會對從 bootloader 傳遞過來的 tag list 進行合法性判斷:
以標號 __vet_atags 開始的一段處理就要是 判斷 tag list 的第一項是否是 ATAG_CORE ,同時判斷長度是否越界!

Tuesday, May 08, 2012

schedule_delayed_work()用法

資料來源: schedule_delayed_work()用法

#include <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/net.h>
#include <net/sock.h>
#include <linux/in.h>
#include <linux/types.h>
#include <linux/kthread.h>
#include <linux/wait.h>
#include <linux/skbuff.h>
#include <linux/string.h>
#include <asm-generic/unaligned.h>
#include <linux/sysctl.h>
#include <linux/netfilter.h>
#include <linux/netfilter_ipv4.h>
#include <asm/checksum.h>
#include <linux/ip.h>
#include <linux/workqueue.h>

#define err(msg) printk(KERN_INFO "%s failed.\n", msg)

static void defense_work_handler(struct work_struct *work);

static DECLARE_DELAYED_WORK(defense_work, defense_work_handler);

static void defense_work_handler(struct work_struct *work)
{
    printk(KERN_INFO "defense_work_handler function.\n");
}

static int __init main_init(void)
{
    schedule_delayed_work(&defense_work, 3 * HZ);

    return 0;
}

static void __exit main_exit(void)
{
    cancel_delayed_work_sync(&defense_work);
}

module_init(main_init);
module_exit(main_exit);
MODULE_LICENSE("GPL");


Wednesday, April 18, 2012

100 個程序員必須知道的 Vim 命令

資料來源:100 個程序員必須知道的 Vim 命令


100 Vim commands every programmer should know

Search/搜索
/word Search 「word」 from top to bottom 從上向下搜索』word'
?word Search 「word」 from bottom to top 從上向下搜索』word'
/jo[ha]n Search 「john」 or 「joan」 搜索」john」或」joan」
/\< the Search 「the」, 「theatre」 or 「then」 /the\> Search 「the」 or 「breathe」
/\< the\> Search 「the」
/\< ….\> Search all words of 4 letters
/\/ Search 「fred」 but not 「alfred」 or 「frederick」
/fred\|joe Search 「fred」 or 「joe」
/\<\d\d\d\d\> Search exactly 4 digits
/^\n\{3} Find 3 empty lines
:bufdo /searchstr/ Search in all open files

Replace
:%s/old/new/g Replace all occurences of 「old」 by 「new」 in file
:%s/old/new/gw Replace all occurences with confirmation
:2,35s/old/new/g Replace all occurences between lines 2 and 35
:5,$s/old/new/g Replace all occurences from line 5 to EOF
:%s/^/hello/g Replace the begining of each line by 「hello」
:%s/$/Harry/g Replace the end of each line by 「Harry」
:%s/onward/forward/gi Replace 「onward」 by 「forward」 , case unsensitive
:%s/ *$//g Delete all white spaces
:g/string/d Delete all lines containing 「string」
:v/string/d Delete all lines containing which didn't contain 「string」
:s/Bill/Steve/ Replace the first occurence of 「Bill」 by 「Steve」 in current line
:s/Bill/Steve/g Replace 「Bill」 by 「Steve」 in current line
:%s/Bill/Steve/g Replace 「Bill」 by 「Steve」 in all the file
:%s/\r//g Delete DOS carriage returns (^M)
:%s/\r/\r/g Transform DOS carriage returns in returns
:%s#<[^>]\+>##g Delete HTML tags but keeps text
:%s/^\(.*\)\n\1$/\1/ Delete lines which appears twice
Ctrl+a Increment number under the cursor
Ctrl+x Decrement number under cursor
ggVGg? Change text to Rot13

Case
Vu Lowercase line
VU Uppercase line
g~~ Invert case
vEU Switch word to uppercase
vE~ Modify word case
ggguG Set all text to lowercase
:set ignorecase Ignore case in searches
:set smartcase Ignore case in searches excepted if an uppercase letter is used
:%s/\<./\u&/g Sets first letter of each word to uppercase :%s/\<./\l&/g Sets first letter of each word to lowercase :%s/.*/\u& Sets first letter of each line to uppercase :%s/.*/\l& Sets first letter of each line to lowercase

Read/Write files
:1,10 w outfile Saves lines 1 to 10 in outfile :1,10 w >> outfile Appends lines 1 to 10 to outfile
:r infile Insert the content of infile
:23r infile Insert the content of infile under line 23

File explorer
:e . Open integrated file explorer
:Sex Split window and open integrated file explorer
:browse e Graphical file explorer
:ls List buffers
:cd .. Move to parent directory
:args List files
:args *.php Open file list
:grep expression *.php Returns a list of .php files contening expression
gf Open file name under cursor

Interact with Unix
:!pwd Execute the 「pwd」 unix command, then returns to Vi
!!pwd Execute the 「pwd」 unix command and insert output in file
:sh Temporary returns to Unix
$exit Retourns to Vi

Alignment
:%!fmt Align all lines
!}fmt Align all lines at the current position
5!!fmt Align the next 5 lines

Tabs
:tabnew Creates a new tab
gt Show next tab
:tabfirst Show first tab
:tablast Show last tab
:tabm n(position) Rearrange tabs
:tabdo %s/foo/bar/g Execute a command in all tabs
:tab ball Puts all open files in tabs

Window spliting
:e filename Edit filename in current window
:split filename Split the window and open filename
ctrl-w up arrow Puts cursor in top window
ctrl-w ctrl-w Puts cursor in next window
ctrl-w_ Maximise current window
ctrl-w= Gives the same size to all windows
10 ctrl-w+ Add 10 lines to current window
:vsplit file Split window vertically
:sview file Same as :split in readonly mode
:hide Close current window
nly Close all windows, excepted current
:b 2 Open #2 in this window

Auto-completion
Ctrl+n Ctrl+p (in insert mode) Complete word
Ctrl+x Ctrl+l Complete line
:set dictionary=dict Define dict as a dictionnary
Ctrl+x Ctrl+k Complete with dictionnary

Marks
mk Marks current position as k
『k Moves cursor to mark k
d'k Delete all until mark k

Abbreviations
:ab mail mail@provider.org Define mail as abbreviation of mail@provider.org

Text indent
:set autoindent Turn on auto-indent
:set smartindent Turn on intelligent auto-indent
:set shiftwidth=4 Defines 4 spaces as indent size
ctrl-t, ctrl-d Indent/un-indent in insert mode
>> Indent
<< Un-indent

Syntax highlighting
:syntax on Turn on syntax highlighting
:syntax off Turn off syntax highlighting
:set syntax=perl Force syntax highlighting

Sunday, April 15, 2012

C語言常用宏定義

資料來源: C語言常用宏定義

01: 防止一個頭文件被重複包含

#ifndef COMDEF_H
#define COMDEF_H
//頭文件內容
#endif

02: 重新定義一些類型,防止由於各種平台和編譯器的不同,而產生的類型字節數差異,方便移植。
typedef  unsigned char      boolean;     /* Boolean value type. */
typedef  unsigned long int  uint32;      /* Unsigned 32 bit value */
typedef  unsigned short     uint16;      /* Unsigned 16 bit value */
typedef  unsigned char      uint8;       /* Unsigned 8  bit value */
typedef  signed long int    int32;       /* Signed 32 bit value */
typedef  signed short       int16;       /* Signed 16 bit value */
typedef  signed char        int8;        /* Signed 8  bit value */

//下面的不建議使用
typedef  unsigned char     byte;         /* Unsigned 8  bit value type. */
typedef  unsigned short    word;         /* Unsinged 16 bit value type. */
typedef  unsigned long     dword;        /* Unsigned 32 bit value type. */
typedef  unsigned char     uint1;        /* Unsigned 8  bit value type. */
typedef  unsigned short    uint2;        /* Unsigned 16 bit value type. */
typedef  unsigned long     uint4;        /* Unsigned 32 bit value type. */
typedef  signed char       int1;         /* Signed 8  bit value type. */
typedef  signed short      int2;         /* Signed 16 bit value type. */
typedef  long int          int4;         /* Signed 32 bit value type. */
typedef  signed long       sint31;       /* Signed 32 bit value */
typedef  signed short      sint15;       /* Signed 16 bit value */
typedef  signed char       sint7;        /* Signed 8  bit value */

03: 得到指定地址上的一個字節或字
#define  MEM_B(x) (*((byte *)(x)))
#define  MEM_W(x) (*((word *)(x)))

04: 求最大值和最小值
#define  MAX(x,y) (((x)>(y)) ? (x) : (y))
#define  MIN(x,y) (((x) < (y)) ? (x) : (y))  05: 得到一個field在結構體(struct)中的偏移量 #define FPOS(type,field) ((dword)&((type *)0)->field)

06: 得到一個結構體中 field 所佔用的字節數
#define FSIZ(type,field) sizeof(((type *)0)->field)

07: 按照 LSB 格式把兩個字節轉化為一個 Word

#define FLIPW(ray) ((((word)(ray)[0]) * 256) + (ray)[1])
 

08: 按照 LSB 格式把一個 Word 轉化為兩個字節
#define FLOPW(ray,val) (ray)[0] = ((val)/256); (ray)[1] = ((val) & 0xFF)

09: 得到一個變量的地址(word寬度)
#define B_PTR(var)  ((byte *) (void *) &(var))
#define W_PTR(var)  ((word *) (void *) &(var))

10: 得到一個字的高位和低位字節
#define WORD_LO(xxx)  ((byte) ((word)(xxx) & 255))
#define WORD_HI(xxx)  ((byte) ((word)(xxx) >> 8))

11: 返回一個比X大的最接近的8的倍數
#define RND8(x) ((((x) + 7)/8) * 8)

12: 將一個字母轉換為大寫
#define UPCASE(c) (((c)>='a' && (c) <= 'z') ? ((c) - 0x20) : (c))

13: 判斷字符是不是 10 進值的數字
#define  DECCHK(c) ((c)>='0' && (c)<='9')

14: 判斷字符是不是16進值的數字
#define HEXCHK(c) (((c) >= '0' && (c)<='9') ((c)>='A' && (c)<= 'F') \ ((c)>='a' && (c)<='f'))

15: 防止溢出的一個方法
#define INC_SAT(val) (val=((val)+1>(val)) ? (val)+1 : (val))

16: 返回數組元素的個數
#define ARR_SIZE(a)  (sizeof((a))/sizeof((a[0])))

17: 返回一個無符號數 n 尾的值
#define MOD_BY_POWER_OF_TWO(X,n)=X%(2^n)
#define MOD_BY_POWER_OF_TWO( val, mod_by ) ((dword)(val) & (dword)((mod_by)-1))

18: 對於IO空間映射在存儲空間的結構,輸入輸出處理
#define inp(port) (*((volatile byte *)(port)))
#define inpw(port) (*((volatile word *)(port)))
#define inpdw(port) (*((volatile dword *)(port)))
#define outp(port,val) (*((volatile byte *)(port))=((byte)(val)))
#define outpw(port, val) (*((volatile word *)(port))=((word)(val)))
#define outpdw(port, val) (*((volatile dword *)(port))=((dword)(val)))

19: 使用一些宏跟蹤調試
ANSI標準說明了五個預定義的宏名。它們是:
__LINE__
__FILE__
__DATE__
__TIME__
__STDC__
C++中還定義了 __cplusplus

如果編譯器不是標準的,則可能僅支持以上宏名中的幾個,或根本不支持。記住編譯程序也許還提供其它預定義的宏名。

__LINE__ 及 __FILE__ 宏指示,#line指令可以改變它的值,簡單的講,編譯時,它們包含程序的當前行數和文件名。

__DATE__ 宏指令含有形式為月/日/年的串,表示源文件被翻譯到代碼時的日期。
__TIME__ 宏指令包含程序編譯的時間。時間用字符串表示,其形式為: 分:秒
__STDC__ 宏指令的意義是編譯時定義的。一般來講,如果__STDC__已經定義,編譯器將僅接受不包含任何非標準擴展的標準C/C++代碼。如果實現是標準的,則宏__STDC__含有十進制常量1。如果它含有任何其它數,則實現是非標準的。
__cplusplus 與標準c++一致的編譯器把它定義為一個包含至少6為的數值。與標準c++不一致的編譯器將使用具有5位或更少的數值。


可以定義宏,例如:
當定義了_DEBUG,輸出數據信息和所在文件所在行
#ifdef _DEBUG
#define DEBUGMSG(msg,date) printf(msg);printf(「%d%d%d」,date,_LINE_,_FILE_)
#else
#define DEBUGMSG(msg,date) 
#endif

20: 宏定義防止錯誤使用小括號包含。
例如:
有問題的定義:#define DUMP_WRITE(addr,nr) {memcpy(bufp,addr,nr); bufp += nr;}
應該使用的定義: #difne DO(a,b) do{a+b;a++;}while(0)
例如:
if(addr)
DUMP_WRITE(addr,nr);
else
do_somethong_else();
宏展開以後變成這樣:
if(addr)
{memcpy(bufp,addr,nr); bufp += nr;};
else
do_something_else();

gcc 在碰到else前面的「;」時就認為if語句已經結束,因而後面的else不在if語句中。而採用do{} while(0)的定義,在任何情況下都沒有問題。而改為 #difne DO(a,b) do{a+b;a++;}while(0) 的定義則在任何情況下都不會出錯。

__FILE__,__LINE__,FUNCTION__實現代碼跟蹤調試(linux下c語言編程)

資料來源:__FILE__,__LINE__,FUNCTION__實現代碼跟蹤調試(linux下c語言編程)



先看下簡單的初始代碼:注意其編譯運行後的結果。
root@xuanfei-desktop:~/cpropram/2# cat global.h //頭文件
#ifndef GLOBAL_H
#define GLOBAL_H

#include <stdio.h>

int funca(void);
int funcb(void);

#endif
root@xuanfei-desktop:~/cpropram/2# cat funca.c //函數a
#include "global.h"

int funca(void)
{
   printf ("this is function\n");
   return 0;
}
root@xuanfei-desktop:~/cpropram/2# cat funcb.c //函數b
#include "global.h"

int funcb(void)
{
   printf ("this is function\n");
   return 0;
}
root@xuanfei-desktop:~/cpropram/2# gcc -Wall funca.c funcb.c main.c //聯合編譯
root@xuanfei-desktop:~/cpropram/2# ./a.out //運行
this is main
this is function
this is main
this is function
this is main
相同結果很難讓人看出那裡出錯,下面我們用用 __FILE__,__LINE__,__FUNCTION__加入代碼,看看有什麼區別嗎.
把 __FILE__,__LINE__,__FUNCTION__加入到mail.c中
root@xuanfei-desktop:~/cpropram/2# cat main.c
#include "global.h"

int main(int argc, char **argv)
{
   printf("%s(%d)-%s: this is main\n",__FILE__,__LINE__,__FUNCTION__);
   funca();
   printf("%s(%d)-%s: this is main\n",__FILE__,__LINE__,__FUNCTION__);
   funcb();
   printf("%s(%d)-%s: this is main\n",__FILE__,__LINE__,__FUNCTION__);
   return 0;
}
root@xuanfei-desktop:~/cpropram/2# gcc -Wall funca.c funcb.c main.c
root@xuanfei-desktop:~/cpropram/2# ./a.out
main.c(4)-main: this is main
this is function
main.c(6)-main: this is main
this is function
main.c(8)-main: this is main
上面的結果main.c(4)-main:this is main 表示在mian.c源代碼的第四行main函數裡邊打印出來的 this is main
那樣的話就很方便的讓程序員對自己的程序進行排錯!
為了更方便的使用它我們可以通過在global.h代碼中進行宏定義
root@xuanfei-desktop:~/cpropram/2# cat global.h
#ifndef GLOBAL_H
#define GLOBAL_H
#include <stdio.h>

int funca(void);
int funcb(void);

#define DEBUGFMT  "%s(%d)-%s"
#define DEBUGARGS __FILE__,__LINE__,__FUNCTION__
#endif
root@xuanfei-desktop:~/cpropram/2# cat funca.c
#include "global.h"

int funca(void)
{
   printf (DEBUGFMT " this is function\n",DEBUGARGS);
   return 0;
}
root@xuanfei-desktop:~/cpropram/2# cat funcb.c
#include "global.h"

int funcb(void)
{
   printf (DEBUGFMT " this is function\n",DEBUGARGS);
   return 0;
}
root@xuanfei-desktop:~/cpropram/2# cat main.c
#include "global.h"

int main(int argc, char **argv)
{
   printf(DEBUGFMT "this is main\n", DEBUGARGS);
   funca();
   printf(DEBUGFMT "this is main\n", DEBUGARGS);
   funcb();
   printf(DEBUGFMT "this is main\n", DEBUGARGS);
   return 0;
}
root@xuanfei-desktop:~/cpropram/2# gcc -Wall funca.c funcb.c main.c
root@xuanfei-desktop:~/cpropram/2# ./a.out
main.c(4)-mainthis is main
funca.c(4)-funca this is function
main.c(6)-mainthis is main
funcb.c(4)-funcb this is function
main.c(8)-mainthis is main
root@xuanfei-desktop:~/cpropram/2#
這就是通過定義__FILE__,__LINE__,FUNCTION__的宏來簡單實現代碼的跟蹤調試:)

下面是一個可供調試用的頭文件
#ifndef _GOLD_DEBUG_H
#define _GOLD_DEBUG_H

#ifdef __cplusplus
#if __cplusplus
extern "C"{
#endif
#endif /* __cplusplus */

//#define GI_DEBUG

#ifdef GI_DEBUG

#define GI_DEBUG_POINT()   printf("\n\n[File:%s Line:%d] Fun:%s\n\n", __FILE__, __LINE__, __FUNCTION__)
#define dbg_printf(arg...)   printf(arg);

#define GI_ASSERT(expr)                                     \
    do{                                                     \
        if (!(expr)) { \
            printf("\nASSERT failed at:\n  >File name: %s\n  >Function : %s\n  >Line No. : %d\n  >Condition: %s\n", \
                    __FILE__,__FUNCTION__, __LINE__, #expr);\
        } \
    }while(0);

/*調試宏, 用於暫停*/
#define GI_DEBUG_PAUSE()           \
 do               \
 {               \
  GI_DEBUG_POINT();          \
  printf("pause for debug, press 'q' to exit!\n");  \
  char c;             \
  while( ( c = getchar() ) )        \
   {             \
    if('q' == c)         \
     {           \
      getchar();        \
      break;         \
     }           \
   }             \
 }while(0);
#define GI_DEBUG_PAUSE_ARG(arg...)          \
  do               \
  {               \
   printf(arg);           \
   GI_DEBUG_PAUSE()          \
  }while(0);


#define GI_DEBUG_ASSERT(expression)      \
if(!(expression))                        \
{                                  \
    printf("[ASSERT],%s,%s:%d\n", __FILE__,  __FUNCTION__, __LINE__);\
    exit(-1);             \
}
#else
#define GI_ASSERT(expr)
#define GI_DEBUG_PAUSE()
#define GI_DEBUG_PAUSE_ARG(arg...)
#define GI_DEBUG_POINT()
#define dbg_printf(arg...)
#define GI_DEBUG_ASSERT(expression)

#endif

#ifdef __cplusplus
#if __cplusplus
}
#endif
#endif /* __cplusplus */


#endif

Sunday, April 08, 2012

台灣50 你可以靠50家好公司退休

資料來源:台灣50 你可以靠50家好公司退休

Money錢雜誌 │ 2010-01-01 撰文:朱國鳳

無論中、外,投資大師都很推崇ETF最適合做為一般投資人參與股市的工具,因為採取被動式操作,因此也被形容為「自動駕駛」。台股第一檔ETF「0050」,是否夠格成為退休資產呢?

想要投資一檔股票養自己的下半生,總是擔心風險太集中;如果用小錢就能同時投資幾十檔、幾百檔股票,風險大量分散,似乎較能令人放心,這個投資工具就叫做「指數股票型基金」(以下簡稱ETF)。

ETF 因為是被動式操作,加上投資成本低,因此廣被中外專家推崇做為退休工具。因為ETF的目標只是打平指數、不是打敗指數,基金經理人按照合約規定,只要指數調整成分股,就要被動跟著增刪基金組合裡的成分股,操作過程透明,投資人易於掌握。

不像主動式基金周轉率一向偏高,甚至有高達1900%(也就是基金經理人在一年中將組合中的所有股票整個換新高達19趟),投資人很難掌握,而如果經理人擇時與選股不正確,投資人也很難受益。相較ETF的投資人,只要能選對指數,長期投資,較能期待資產長期穩定累積。

台灣第一檔ETF「寶來台灣卓越50 基金」(以下用股市代號0050簡稱),基金價格於2009 年12 月11 日的收盤價為53.85 元,等於是用5 萬3850 元買進一張,就能買到一籃子包含50 檔市值最大的上市股票。

如果投資人去股市買進同樣成分股各一張的話,代價要310 多萬元,這是ETF小錢買到一籃子股票的魅力。只是,這檔ETF是否適合做為退休資產呢?經過嚴格檢視,目前為止,0050 符合專家群列出的5大要求。


市值論英雄 可以掌握強勢產業的脈動

把0050 做為退休資產,特別獲得專家一致認同的關鍵是「產業自動調整機制」。寶來指數投資處副總經理黃昭棠解釋,0050 每季要按市值、公眾流通量、流動性等3項標準調整成分股,也就是每季都會自動選取總市值最大的前50家公司。

市值愈大的公司,也代表所處的產業愈強勢。由於每個波段都會有不同的強勢股、強勢產業,一般投資人很難持續追得上,「0050 用市值論英雄,更能掌握強勢產業的脈動」,黃昭棠表示。

政大財務管理系所教授周行一則進一步解釋市值的意義:市值=流通股份 × 股價,由於市值有先期指標的功能,當企業走下坡時,市值就會逐漸萎縮,當落到排名50 以外時,指數就會自動將其剔除,反之就會將其列入。周行一肯定表示,「0050靠著這種優勝劣敗的淘汰機制,就能確保組合中總是有最具競爭力的50 家公司;但投資人若是買現股,就會有一夕變成地雷股的風險。」而美股中有所謂的「藍籌股」,指的就是績效優、市值大的企業。

擁有CFP認證理財顧問執照的聯合財信資產管理公司副總經理黃柏仁在0050 掛牌時就買進至今,他也認為0050 選擇的都是台灣最有競爭力的企業,「只要全球景氣長線向上,這些企業就是最有機會跟著全球景氣賺大錢。」而從0050 掛牌以來,年化報酬率遠比台灣GDP 成長率高出一大截就可知道,投資一籃子最有競爭力的企業,可以賺到比GDP 更優的報酬率。

但是周行一也特別提醒, 把0050 當成長期投資的退休資產,一定要把配息再滾進去投資,才能享受長期複利的效果。


ETF當退休資產 配息滾入再投資才有效果

周行一曾經做過模擬,1990 年台股歷史高點12682 點,目前台股位置是7、8 千點,單純用指數位置來看,離歷史高點還差一大截;但是假設在1990年就用0050長期投資,將平均配息再滾入,報酬率換算的指數位置等於是14000點了。周行一表示,台股投資人太注重賺資本利得(價差),其實長期將配息滾入的複利效果,遠比資本利得更優。就以0050 掛牌以來的表現試算,配息再滾入的累積報酬率為79.5%,年化報酬率為9.55%,比配息不滾入的表現又好上一截。曾經在華爾街工作過的黃柏仁,將可投資資金的一半拿來長期投資0050、另一半自己選股操作,結果實際投資績效呢?黃柏仁靦腆的表示︰「四分之三,都是0050 打敗自己的操作績效。」

總結來說,周行一認為,想要將0050 當成退休資產,「最大的風險,就是原本設定的長期投資目標,很容易變成短線交易。」因為0050 的交易成本比股票型基金低,透過集中市場交易,買進賣出也比股票型基金容易,自認為「藝高人膽大」的投資人,很容易就變成短線操作。

黃柏仁也認為把0050 當成退休標的的最大風險,就是拿來當成波段操作的工具,「自以為很會抓波段,其實抓不到,把賠錢責任推到0050,從此不碰。」因而錯失「養我下半生」的好標的。

曾經中間出清掉0050 的黃柏仁,堅定的表示︰「我不會再被嚇出場了」,目前已經累積到上百張部位,他更打定主意,只要有上班、有穩定的現金流,就會努力的繼續存0050。


2種模式 逐步建立0050部位

想要長期投資0050 該怎麼開始呢?周行一用2個「一定」提醒投資任何工具前需做好的準備:??一定要先預留1 年生活預備金;????一定要長期儲蓄。

有了這兩項準備後再開始投資0050,才不會因為急需用錢而被迫賣出;有足夠儲蓄當後盾,當0050 隨著股市重挫而大跌時,才不會心急跟著賣,因而中斷了可以長期投資的機會。周行一更補充,當所得逐漸提升後,應該增加全球股市與新興股市的ETF,既能分散「集中台股投資」的風險,又能分沾到更多市場成長的獲益。


模式1 定額投資

金融海嘯期間,台股跌到4 千點,周行一在演講中表示,應該開始進場了!但是很多聽眾擔心詢問︰「會不會再跌到2千點?」由於大多數投資人都是「大跌不敢買、大漲又嫌貴」,想要擇時買在最低點的結果,就是永遠都無法建立部位,因此,周行一建議投資人應該要「紀律性」的定額買進。

當行情過熱時暫停買進,當行情過冷時可以考慮加碼。黃柏仁就曾經在今年3月間等到投信投顧公會公布2 月定期定額戶數比1 月戶數回升之時,加碼買進0050。因為當定時定額戶不斷退場到低檔而出現止穩訊號時,指數也快要反彈了,這是黃柏仁從2000 年科技基金揣摩出的心法。


方法1 ︰存到一張的資金後買進
目前一張0050 價格約5 萬多元,只要投資人在幾個月間一存到足夠資金,就可以買進1 張。但是專家建議薪水入戶後,一定要有紀律的先將資金預扣下來,否則就會因為不小心花掉而發生「始終存不到足夠資金」買進的現象。


方法2 ︰每月用零股買進
0050 是在集中市場掛牌, 當然也會有零股交易,資金有限的上班族也可考慮在盤後用零股買進。只是黃昭棠提醒,零股未必每天都能撮合成交,每筆手續費20 元,如果零股金額太低,相對地,零股的手續費率就會偏高。


模式2 大波段單筆投資

如果對台股走勢已有一定程度了解,具備相關知識後,也可考慮採取波段式的「單筆投資」來建立部位。要注意的是,長期定額買進可以壓低持股平均價位,波段單筆買進就要確保買進價格要夠低,因此黃昭棠建議跟著景氣循環買進,最適合用來建立退休部位。


方法︰跟著景氣燈號買進
瑞展產經研究董事長陳忠瑞統計過去20 年的景氣循環,鑽研出一套景氣燈號投資術︰「藍燈買進、紅燈賣出」。陳忠瑞提醒,不是每次循環都會進到紅燈區或是藍燈區,但一旦出現、就是強烈的賣出警訊與買進喜訊。

如果景氣衰退時間很長,就會亮出很多顆藍燈,藍燈過半是最佳買訊, 問題是藍燈沒有全部亮完,也不知第幾顆算是過半?因此陳忠瑞建議用平均藍燈數買進。台灣過去20 年來的景氣循環共出現7 次藍燈區,平均5.7 顆藍燈,建議用平均5 顆藍燈、5 等分按月分批承接。


0050符合退休資產的5大要件

條件1 指數長線趨勢向上
寶來指數投資處副理蔡玗玹表示,ETF 可以分成大型股、中小型股、產業型、主題型等,如果某產業的長期趨勢向下,根據該產業指數所發行的ETF 就不適合用來當作退休標的。0050 是買進市值最大的50 檔上市股票,企業競爭力愈強、市值愈高,這些最具競爭力的企業所組成的指數,長線趨勢應該呈現向上。


條件2 ETF規模要夠大
2008 年間美國Ameristock 基金公司旗下有5 檔ETF,因為規模不斷萎縮而遭到清算,這些ETF比投資人還短命,如何發揮退休資產功能? 0050統計至2009年12月4日的規模是480億元,已經是台股規模第一大的基金(台股基金平均規模為23 億元),受益人也從掛牌當年的3 千6 百人成長到7 萬4 千人,規模經濟與市場接受度都已受到肯定。


條件3 流動性要夠
流動性主要是看成交量,目前台灣掛牌的14 檔ETF 中,成交量前二名為0050、0061(滬深300),20日均量都有7千多張。其他不少ETF則只有數百張、甚至僅數十張的成交量,流動性不足,大型法人不敢投資,退休族日後要變現也會有困難。


條件4 要有配息
台股中有不少「鐵公雞企業」,就算有賺錢也吝於配出現金股息。而0050 按合約規定,「基金累計報酬率大於標的指數累計報酬率達1%以上者,應進行收益分配」,蔡玗玹表示,譬如若超過5%,經理人看市場狀況保留1%,將剩下的4% 收益進行配息,2005 年以來都有配息,從1 ? 4元不等,約當殖利率從1.86 ? 6.97%。


條件5 年化報酬打敗定存
0050於2003年6月掛牌,截至2009年12月7日為止,累計報酬率為65.12%(含息)、年化報酬率為8.13%(含息),遠比同期間定存利率高出一大截。

Wednesday, March 14, 2012

command mode 和 video mode

資料來源:command mode 和 video mode

Command mode:

以命令(command)和數據(data)的形式傳遞給外設(通常是顯示模塊,或者顯示控制器display controller, 這裡,顯示控制器可能包括本地寄存器(local register)和frame buffer)。 系統可以通過command mode向本地寄存器和frame buffer memory寫或讀。這樣,處理器就可以通過向顯示控制器下達命令,參數和數據,間接地控制外設的行為了。另外,處理器可以讀取顯示模塊的狀態或者frame memory中的內容。command mode需要一個bidrectional interface。


Video mode:

以實時像素流(real-time pixel stream)的形式傳遞給外設。通常,顯示模塊需要處理器在一個足夠寬的帶寬上來傳輸圖像數據,以避免閃爍(flicker)或其他畫質問題。影響信息需要在high speed mode 上傳輸。通常,為了節省成本和降低複雜度,系統在unidirectional data path上來操作video mode。

Wednesday, March 07, 2012

Android Ice Cream Sandwich kernel 3.0 on Pandaboard

資料來源:Android Ice Cream Sandwich kernel 3.0 on Pandaboard

好核心,不胖達嗎?

繼上一篇討論如何燒錄Android framework到Pandaboard後,這篇來教學如何燒錄Android kernel for OMAP-4430,再進行這裡的步驟之前,請先照著上一篇做一次,把必要的工具和環境建立出來

1. 下載Android kernel source for Pandaboard

由於Android的kernel source repository掛掉很久了,要檢視所有的branch變得非常困難,首先我們要用git下載Android kernel for OMAP,Pandaboard採用的核心版本為最新的krenel 3.0

$ mkdir kernel_ICS
$ cd kernel_ICS
$ git clone https://android.googlesource.com/kernel/omap.git
$ cd omap
$ git branch -r
$ git checkout -b android-omap-panda-3.0 origin/android-omap-panda-3.0

由於Panda是採用OMAP4430的CPU,當然要抓這個分支囉


2. 編譯kernel

$ export PATH=android_ICS/prebuilt/linux-x86/toolchain/arm-eabi-4.4.0/bin:$PATH
$ export CROSS_COMPILE=arm-eabi-
$ cd kernel_ICS/omap/
$ make ARCH=arm panda_defconfig
$ make ARCH=arm -j4

要編譯kernel當然要先設定cross compiler, 從4.0原始碼裡面有提供編譯好的cross compiler binary,直接用他的就好


kernel config這邊選擇panda_defconfig,(我當初下載的是common kernel source,找半天沒有適合Panda的config)

到目前就算是初步完成囉,編譯好的kernel image會放在arch/arm/boot/zImage


3. 重建boot.img

網路上有很多人寫了方便的script,主要功能就是把原本要燒到SD卡上的boot.img拆開後,再把裡面原本的kernel image掉包成我們剛剛編譯好的zImage,這方法是比較有效率的,但是我太懶所以就請Android本身的makefile幫我們做這件事情囉

$ cd android_ICS/device/ti/panda/
$ mv kernel kernel.bak
$ cp kernel_ICS/omap/arch/arm/boot/zImage ./kernel
$ make -j4

簡單來說,Panda的kernel原本是以預先編譯好的方式存放在device資料夾裡面,我們做的事情就是單純的把他的image掉包成我們編譯的image(記得備份舊的)

重新編譯以後,會把新的kernel重新包入boot.img裡面,就算大功告成了

4. 燒錄kernel

燒錄時可以完全參考前一篇的作法,但是因為連整個system都重燒,會導致第一次開機非常久,

因此建議採用以下步驟來燒錄kernel

4.1 SD卡,USB線,UART線,HDMI線,電源線全部都接好,按住GPIO按鈕再按reset按鈕,直到u-boot進入fastboot模式

4.2 由於SD卡已經format好,而且我們只需要重燒boot.img的部分

$ sudo su
$ cd android_ICS/out/host/linux/bin
$ ./fastboot flash boot
$ ./fastboot reboot

如此一來重開機速度就會非常快了,附上一張修改kernel後顯示的kernel version

高亮 LXR 的代碼

資料來源:高亮 LXR 的代碼


LXR ── Linux Cross Refercence。Linux內核源碼閱讀和查詢的利器之一,不用多介紹了。LXR安裝後看到的源碼是沒有顏色的,用慣了語法高亮的編輯器,一下子看到滿屏的黑白代碼不免有點枯燥。於是給它裝了個可以顯示語法顏色的工具。
1、安裝google-code-prettify
項目地址是:http://code.google.com/p/google-code-prettify/
$ wget http://google-code-prettify.googlecode.com/svn/trunk/src/prettify.css
$ wget http://google-code-prettify.googlecode.com/svn/trunk/src/prettify.js
我把它們放到lxr的安裝目錄下面,lxr我放在web服務器的根目錄,所以就
2、修改lxr/http/template-head
這是lxr默認的html頭,在<head></head>標籤之間加上
1<link href="/lxr/prettify.css" type="text/css" rel="stylesheet" />
2<script type="text/javascript" src="/lxr/prettify.js"></script>
注意文件路徑,不在乎需要從遠方服務器讀取的話,也可以
1<link href='http://google-code-prettify.googlecode.com/svn/trunk/src/prettify.css' rel='stylesheet' type='text/css'/>
2<script src='http://google-code-prettify.googlecode.com/svn/trunk/src/prettify.js' type='text/javascript'></script>
這樣也可以讓google-code-prettify的維護者來自行維護這些腳本。
然後找到<body>標籤:
1<body bgcolor=white>
改為
1<body bgcolor=white onload='prettyPrint()'>
3、修改lxr/http/source
這是個perl腳本,查找字符串"<pre>",這有好幾處,都在printfile這個子函數裡面,改為
1<pre class=/"prettyprint/">
已經好了,這樣再看LXR裡面的代碼就可以看到漂亮的語法顏色了。效果圖:
2009-05-01 Update:
上面的效果圖有一個問題,就是代碼的行號也被渲染高亮了。這個可以通過給行號標識加上"nocode"這個prettifier提供的class來解決。對lxr/http/lib/LXR/Common.pm進行如下修改即可:
diff --git a/Common.pm b/Common.pm
index 9e23088..529d5a2 100755
--- a/Common.pm
+++ b/Common.pm
@@ -151,7 +151,7 @@ sub linetag {
$tag .= ' ' if $_[1] < 10;
$tag .= ' ' if $_[1] < 100;
$tag .= &fileref($_[1], $_[0], $_[1]).' ';
- $tag =~ s/<a/<a name=L$_[1]/;
+ $tag =~ s/<a/<a class="nocode" name=L$_[1]/;
# $_[1]++;
return($tag);
}
還可以在自己的css文件裡面重寫nocode這個class,例如加個方框啥的。

Ubuntu 環境下安裝 LXR

資料來源:Ubuntu 環境下安裝 LXR

由於項目需求,需要搭建一套代碼索引環境,經過網上查找,瞭解可以使用LXR (the Linux Cross Referencer)來做,同時網上有很多搭建方法,我嘗試學習,一步一步搭建環境,在這個過程中,遇到一些問題,記錄下來,分享給大家,方便大家順利完成LXR 搭建。 

環境:Ubuntu 10.10,新安裝的系統,具體搭建步驟如下(整個過程中基本都需要root權限): 

1.安裝apache2 
sudo apt-get install apache2 

2.安裝Glimplse 
. Glimplse 
# wget http://webglimpse.net/trial/glimpse-latest.tar.gz 
# tar xvzf glimpse-latest.tar.gz 
# cd glimpse-4.18.6 
# ./configure 
# make 

我在make 的時候報下面的錯

make[1]: flex: Command not found

make[1]: *** [lex.yy.c] Error 127

make[1]: Leaving directory `/usr/local/src/glimpse-4.18.6/dynfilters'

make: *** [build-sub] Error 2

在編譯之前,首先看看你的機器上是否已經安裝了flex,因為編譯glimpse的時候需要這個軟件。如果沒有的話,那麼進行安裝:
sudo apt-get install flex
 

執行 

# make 
# sudo make install 

3.安裝lxr 
sudo apt-get install lxr 

4. 對文件做映射 
在/etc/apache2/httpd.conf 在裡面添加以下內容: 
Alias /lxr /usr/share/lxr 
<Directory /usr/share/lxr> 
Options All 
AllowOverride All 
</Directory> 
這樣可以達到http://localhost/lxr/ =>/usr/share/lxr 

5. 在/usr/share/lxr/http下創建文件 .htaccess, 並寫入一下內容
<Files ~ (search|source|ident|diff|find)$> 
SetHandler cgi-script 
</Files> 

6.啟動apache2 
sudo /etc/init.d/apache2 restart 

7. 下載linux 源代碼 
linux內核源碼下載地址http://www.kernel.org/,我下載了2.6.39.4版本的linux 源碼,默認下載到/home/beaver(beaver是我的用戶名,根據大家的機器而定)/Downloads,解壓後為linux-2.6.39.4 

創建/usr/share/lxr/source/XX  目錄 (XX為版本號) 
mkdir /usr/share/lxr/source/2.6.39.4 
然後在/usr/share/lxr/source/2.6.39.4下創建linux符號連接 
ln -s /home/beaver/Downloads/linux-2.6.39.4 /usr/share/lxr/source/2.6.39.4/linux 
                  (源碼地址) 

8. 創建/usr/share/lxr/source/versions 文件,這裡記錄所有要看的版本,內容是 
2.6.39.4 
2.6.22(可有可無) 
要保證2.6.39.4 =>/usr/share/lxr/source/2.6.39.4 
創建/usr/share/lxr/source/defversion 文件,這裡記錄缺省要看的版本,內容是 
2.6.39.4 
之所以是這兩個文件,見/usr/share/lxr/http/lxr.conf裡的相關設置 

9. 建立索引 
cd /usr/share/lxr/source/2.6.39.4/ 
生成關鍵字交叉索引數據庫 
sudo genxref linux 
接下來要等待一段比較長的時間,因為它要掃瞄文件。這樣會在當前目錄生成fileidx和xref 
接下來,生成freetext交叉索引數據庫: 
sudo glimpseindex -H /usr/share/lxr/source/2.6.39.4/ /usr/share/lxr/source/2.6.39.4/linux 
(需要等待一段時間) 
之所以是這個目錄(/usr/share/lxr/source/2.6.39.4/),見/usr/share/lxr/http/lxr.conf裡的相關設置(database項) 

10.修改屬性,使任何人都可以讀取改文件 
sudo chmod +r -R /usr/share/lxr/source/2.6.39.4/* 
sudo chmod +r /usr/share/lxr/source/2.6.39.4/.glimpse*  (注意:這句命令必須執行,否則在 file search 的時候會出現警告:Warning: Could not open .glimpse_filenames) 

11.啟動apache,查看源碼 
sudo /etc/init.d/apache2 restart 
http://localhost/lxr/http/blurb.html //成功查看源碼 
閱讀的時候可以看到頁面頂部有 
~ [ source navigation ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~ 
source navigation是用戶查看頁面的界面 
identifier search是查找某個變量名、結構名、函數名的界面 
freetext search是查找任何字符串的界面 
file search查找某個文件 


參考文件: 
http://blog.sina.com.cn/s/blog_6c6d405f0100oq6l.html 
http://www.linuxsir.org/bbs/showthread.php?t=246594 
http://linux.chinaunix.net/techdoc/system/2006/12/21/946450.shtml 
http://yp.oss.org.cn/software/show_resource.php?resource_id=1044 
http://wenku.baidu.com/view/7d3c0471f242336c1eb95e13.html 
收藏: 
http://blog.csdn.net/fengyanhui/article/details/6320117 

Tuesday, March 06, 2012

Lcd Controller Timing parameters

資料來源:Lcd Controller Timing parameters


Lcd panel 的Timing 最小單位是clock,datasheet中標示為 Clock cycle。
這是panel 的特性,每個panel 有他工作的極限。

像 XXX 的 480x272 type,他的 clock cycle 就標示:
  Typ : 9, Max 15, Unit MHz
所以我們就要適當調整(除頻) host controller 的lcd vclk 頻率,讓他落在這個範圍內。

這個 Clock 信號,配合 R.G.B Data line,每個clock 會write一個pixel 的data到Lcd。

-------------------------------------------------------------------------------------------------------------------



Lcd 掃描是橫式的,以這個例子來看,就是一條 480 的線。 這是一條 horizontal 掃描線。

Lcd 需要另一個信號 HSYNC,用來標示Horizontal 掃描線的開始。
HSYNC信號必須要維持一段時間,讓Lcd controller能夠正確收到。在datasheet中,稱作 Horizontal Sync Pulse Width。
480x272 這個type,標示:
  Min 2, Typ 41 Unit CLK
基於每個 Lcd controller 內部控制器的能力,一旦收到 HSYNC 後,需要一段內部處理時間,才能開始收取horizontal line 的pixel 資料。
這一段時間叫做 Horizontal Back Porch。是以 lcd clock 為單位來計算的。
這也標示在lcd 的data sheet中。
像 480x272這個 type,就標示 Horizontal back porch:
 Min 2, Typ 2, Unit CLK
另外,由於Lcd Controller 實在太糟了,在處理完一條horizontal line的所有pixel後,ㄒ需要休息一段時間,才能再處理下一條。這段時間叫做 Horizontal front porch。
datasheet標示
 Min 2, Typ - Unit CLK
這樣,一條掃描線所需要的參數都定義出來了 (都是以 lcd clock 為單位):

|<--HSPW-->|<--HBP-->|<---HORIZONTAL_LINE_DATA--->|<--HFP-->|

-------------------------------------------------------------------------------------------------------------------


掃描線做完後,接著要靠一條一條的掃描線形成一個畫面(frame)。所以這部份的參數內容,都是以一條掃描線的時間為單位的..

和水平掃描線一樣,每個畫面的開頭,都需要一個信號,告知Lcd "這一條線是frame的開頭",這個信號叫做 Vertical Synch : VSYNC。
在datasheet標示 VSYNC 的信號,必須要維持至少 2 條掃描線的時間: Vertical Pulse Width
 Min 2, Typ 10, Unit H
其中"H"代表一個掃描線所需要的時間。
完全和Horizontal line一樣,Lcd收到VSYNC後,需要一段準備的時間,叫做 vertical back porch。datasheet上寫
 Min 2, Typ 2, Unit H
接下來還是一樣,一個畫面的所有掃描線資料都收完後,Lcd需要休息一段時間,才能再處理下一個Vertical Synch 信號,這段時間叫 Vertical Front Porch。Datasheet上寫:
 Min 2, Typ 2, Unit H
所以Vertical 部份看起來Horizontal 一樣,只是他的reference clock 單位變成"Horizontal Line Time (Period)"

|<--VSPW-->|<--VBP-->|<---EVERY_LINES_IN_FRAME--->|<--VFP-->|

-------------------------------------------------------------------------------------------------------------------


所以 決定 Lcd Clock 頻率後,在決定一條horizontal line 需要的clock 數後,就可以得到 horizontal line 的頻率:
Lcd Clock = 9MHz
HSPW(41)+HBP(2)+H_PIXEL_NUMBER(480)+HFP(2) = 525.
Horizontal Freq = 10MHz/525 = 17.14kHz
然後由vertical 參數算出一個畫面(frame)需要的horizontal line 後,就可以知道frame rate (frame freq:
Horizontal Freq = 17.14kHz
VSPW(10)+VBP(2)+V_LINE_NUMBER(272)+VFP(2) = 286
Frame Rate = 17.14kHz/286 = 59.9 Hz


lcd時序解疑

資料來源:lcd時序解疑


這裡主要是針對嵌入式開發常用的TFT-LCD系統作一些淺顯的分析,討論了大家在學習LCD時最容易混淆的一個地方,若有講的不對的地方那個,還請指正。
1. TFT-LCD系統的構成主要由三部分構成:TFT-LCD控制器、TFT-LCD驅動器和TFT-LCD屏。TFT-LCD控制器一般是集成在MCU中的,比如S3C2410的LCD控制器;而TFT-LCD驅動器和TFT-LCD屏一般就構成了我們常說的TFT液晶模塊,注意液晶和液晶模塊的區別,記得大學的嵌入式老師經常說:「你們一定要說買液晶模塊,而不要說買液晶,免得別人說你外行」。TFT液晶模塊除了這兩個部分外,還有背光電路和FPC接口等。如下圖。 TFT-LCD驅動器一般是由專用芯片構成的。常見的有ILI9325、NT39115等。這些芯片的主要是接收MCU的LCD控制器傳過來的RGB數據,根據這些RGB值,然後控制液晶點陣顯示相應的內容。那有人會問了,直接把RGB送給液晶不行嗎,為什麼要LCD驅動芯片呢?這是因為,要顯示一個像素單元,需要三個液晶點,分別來代表RGB三原色,而這三個液晶點,需要接三根source driver線和一根gate driver線,才能完成對這個像素單元的顯示控制,所以,對於一塊240*320像素的液晶,需要720根source driver線和320根gate driver線,而一般的MCU的所有接口加起來也超不過500個,所以,必須用專用LCD驅動芯片。


2. 從CRT掃瞄說起電視在顯示圖像的時候,把一幀分成了兩場來顯示,一個場由幀中的奇數行組成,叫做奇場;另一個場由幀中的偶數行組成,叫做偶場。之所以要這樣做,主要是因為在CRT顯像管上每秒鐘顯示25幀圖像時,人眼感覺到連續性還是不太好,而且還有明顯的閃爍,一幀分成兩場後,場頻為50Hz,圖像更加連續一些。當然還有一些別的原因,與電路設計方面有關。而掃完一場後,回到開始處從新掃瞄的過程叫做回掃,也即場消隱(field blanking)。同樣的也有行消隱(line blanking)。見下圖。這方面的詳細資料可以參考Video Electronics Standards Association發佈的Monitor Timing Standard標準文檔。圖中顯示是:Blanking = Front Porch + Sync + Back Porch。即,消隱時間 = 同步前沿 + 同步時間 + 同步後沿,而現在的LCD顯示器為了兼容這種場掃瞄模式,也採用消隱的做法。不同的是以前的CRT顯示一幀畫面,分兩場掃瞄,而現在的LCD顯示一幀只需要掃瞄一次。所以,以前的說法是行場(line、field),現在的說法是線幀(Horizontal、vertical)。也就是說以前是場消隱,現在是幀消隱。上面講的時序仍然是LCD驅動器對LCD屏的控制時序,還不是LCD控制器的時序。


3.LCD控制器時序我們都知道,一般的TFT-LCD的顯示刷新頻率是60Hz,也就是每秒鐘顯示60幀畫面。而我們視頻播放幀率是23~30fps,我們大概不會利用LCD控制器每秒送60幀圖像的RGB信息給LCD吧,一般是每秒鐘送20~30幀的RGB信息給LCD,讓其顯示。其實,我們是通過LCD控制器把RGB數據送給LCD驅動器,LCD驅動器就把它放到緩存中,然後以60fps的速度送給LCD屏顯示。可能有人會問,視頻幀率有多大,LCD就顯示多快,不行嗎?不行,由於液晶分子有一種特性,就是不能夠一直固定在某一個電壓不變,不然時間久了,液晶分子就遭到了破壞。所以要以一定的頻率(通常是60Hz)不停的刷新LCD屏,然後在幀消隱的時間裡,變換顯示電壓極性,達到保護液晶的目的。對於PAL制式的CRT顯示器,幀頻是25Hz,場頻是50Hz,這時,視頻幀率和顯示器刷新率是相同的。而我們在嵌入式當中使用TFT-LCD顯示器,視頻幀率一般是不等於顯示器幀率的。所以,LCD控制器時序和LCD驅動器時序(LCD顯示掃瞄時序)雖然表示方法大體相同,但有實質上的區別,LCD控制器時序控制著視頻幀率;LCD驅動器時序控制著顯示器刷新率。這是大家在學習LCD的時候最容易混淆的地方。下面以S3C2410的TFT-LCD控制器說明一下。見下圖。其中VSYNC是幀同步信號,VSYNC每發出1個脈衝,都意味著新的1屏視頻資料開始發送。而HSYNC為線同步信號,每個HSYNC脈衝都表明新的1掃瞄線視頻資料開始發送。而VDEN則用來標明視頻資料的有效,VCLK是用來鎖存視頻資料的像數時鐘。並且在幀同步以及線同步的頭尾都必須留有消隱時間,例如對於VSYNC來說消隱時間是(VSPW+1)+(VBPD+1)+ (VFPD+1);HSYNC亦類同。其中: VSPW:Vertical sync pulse width,也就是VSYNC處於高電平時的線的數目 VFPD:Vertical front porch delay VBPD:Vertical back porch delay HSPW:Hertical sync pulse width,也就是HSYNC處於高電平時的VCLK的數目 HFPD:Hertical front porch delay HBPD:Hertical back porch delay