2009年4月6日 星期一

endian & alignment --轉貼


To be TCP/IP or not to be ?

by http://playstation2.idv.tw/garyhu.jpg

不幸的是,這個問題應該是在你的產品中,你需要多複雜的TCP/IP功能?

TCP/IP是一個廣義的通訊協定,他事實上是一個網際網路通訊協定家族的總稱,其中包含了許多的通訊協定,例如IPTCPUDP…等,我們可以參考一下圖一大概的列出整個TCP/IP協定家族之間的關聯性。例如TCPUDP是建構在IP之上的協定,而FTP又是透過TCP來達到傳輸檔案的功能。

圖一、TCP/IP家族

嵌入式系統(Embedded System)在最近這一股資訊家電的潮流中,突然地受到大家的重視,特別是PDA、股票機廠商的業績比起正統電腦設備廠來得亮麗的時候,大家都很好奇這麼樣的小東西為什麼會這麼受歡迎?於是專家們宣告後PC時代來臨。

筆者不在這邊討論這種後PC時代的問題,今天的主題是在嵌入式系統中加入TCP/IP功能的必要性,除了當紅的PDA之外,其實許多藏在生活周遭的裝置裡也存在著許多嵌入式系統,而在嵌入式系統中,往往需要基本的通訊功能,從簡單的RS-232通訊、銀行提款機的專線連接、到複雜許多的手機通話,很明顯的嵌入式系統擺脫不了通訊的功能,不過如果使用者打算的是透過您的產品連接到廣大的Internet,那除了TCP/IP之外,別無選擇,特別是在現今這個Internet橫行的時代裡,如果您不連上Internet就落伍的情況。所以這個問題您應該換另外一個角度來看,真正的問題應該是在你的產品中,你需要多複雜的TCP/IP功能?。於是我們可以看到國內幾家以電子字典打下江山的廠商,從去年開始,強打上網功能的廣告,大都是透過PC將所需要的資料下載,再透過同步功能傳到電子字典裡,這樣的功能表示了無限擴充,筆者手邊有一台哈x族,正是這樣功能的典範之作,不過我們注意到一件事情,電子字典本身並沒有直接上網,是以一種間接的方式取的網路上的資料,很快的,這樣的方式就會因為無線寬頻時代的來臨,而轉變成電子字典直接上網。舉另外一個例子來說,創下國內PDA模範生的產品︰股票機,目前是透過BBCall的方式來取得單方傳遞訊息,若是將來使用者打算直接透過股票機來交易呢?股票機廠商難道沒有看到這樣廣大的商機嗎?事實上是有的,以神乎x機來說,WAP就是這樣的解決方案,目前正如火如荼的進行移植測試的工作。

看看全世界引為龍頭的PalmWinCE,上網功能早已經內含,就算是歐洲遠征出軍的EPOC(手機上普遍所見到的嵌入式作業系統)也是將TCP/IP列為標準的功能,如果您是打算發展嵌入式系統產品的廠商,是否應該將TCP/IP加到您的產品中?我想答案已經很明顯了。不過嵌入式系統是個非常特殊的系統,他事實上是一種『量身訂做』的系統,也許甲廠商跟乙廠商用的是同一個嵌入式作業系統,不過產品可能長得非常不一樣,例如現在許多的PDA是用摩托羅拉(Motolora)所生產的Dragon Ball EZ或是VZ系列的CPU,所以可能順便就使用摩托羅拉所提供的PPSM(Personal Portable System Manager)作業系統,可是一個做出PDA,一個作成電子字典,使用者就可能覺得這是不一樣的系統,因此嵌入式系統必須具有很大的修改空間,特別是使用者視窗部份,廠商必須針對用途、針對客戶群去對整個使用界面做調整,而不是說任何一個寫好的視窗就直接套過來用。

其實PPSM其實功能也算蠻完整的,可是目前並沒有殺手級的產品,因此知名度不如PalmOS,也沒有Microsoft會行銷包裝,所以知名度也不如WinCE,這是題外話。

圖二、Palm的標誌

圖三、EPOC的標誌

圖四、PPSM的標誌

另外就是嵌入式系統都是燒在ROM裡的,ROM的空間可不像PC的硬碟空間那樣的大,記憶體也相對的少了許多,就像筆者的哈x族,每次想裝個新東西進來,就得要把另一個軟體刪除掉,人家的記憶體空間,不管是RAM或是ROM可都是寸土寸金,因此所以就算是TCP/IP,我們需要整包的協定都包進來嗎?

以如果要發展一個WAP瀏覽器為例,事實上目前通用的版本只需要UDP協定就夠了,雖然說新版的WAP會連TCP都用上,不過等到真的出來再說,我們可以很明顯的看到事實上我們不需要一個很複雜的TCP/IP家族,只要兩三個協定,就夠我們享用不盡了。談到這邊,筆者描述一下筆者過去的發展經驗,也許可以提供當作讀者一個發展的經驗借鏡。

當初筆者所用的發展系統TICKERS,原本也是不具有TCP/IP功能的作業系統,不過這是一種單一定址空間、多執行緒的作業系統,挺適合發展嵌入式系統的,簡單而不失完整是他最大的好處,沒聽說過這套作業系統?沒關係,嵌入式作業系統多的是像這種聽都沒聽過的OS,就算是最有名的如pSOS(現在已經被WinRriver併購並且和VxWORKS合為一體了),我想聽過的讀者也應該不多。因為某些因素,筆者必須在這個作業系統上發展出專用的TCP/IP通訊協定,一開始當然找了許多的資料,例如大學時代修課的課本,心裡想想,反正這種東西發展了幾十年了,應該可以參考的原始程式多得數不清,最不濟也有Linux或是BSD TCP/IP stack的原始碼來參考,反正都是free的,總不會慘到自己重頭開始寫吧?

當 然,開發一個算是蠻複雜的系統時,一定要先想好怎麼去進行,尤其是嵌入式系統要求精簡、確實,不可以隨便多或是少,我們會仔細想好界面的需求,並考量到以 後移植到其他的硬體時所需要作的修改,就像下面這張圖一樣,我們會將所有該分層的分開,避免每次換到新的產品上就要花很大的心力去作修改。

圖五、開發網路界面架構圖

準備規劃的動作做完了、稍微看了一下課本,重新喚起當年的記憶之後,就開始準備著手移植BSD TCP/IP stack,這下子不得了了,這是一個非常巨大的工程,非常不容易了解還是其次,事實上是很不容易縮小成我們想要的系統,筆者只不過是要移植WAP瀏覽器所需要的UDP協定,真的有必要去跟這巨大的怪物搏鬥嗎?筆者的朋友很同情我,介紹我去找一下xlinu系統上的TCP/IP協定來研究,於是乎筆者很用心的研究了整個xlinu上的TCP/IP運作,順便後悔當初上課的時候根本有聽沒有懂,xlinu系統上的TCP/IP協定是一個需要開6個執行緒去跑的TCP/IP系統,這樣的東西適合放在嵌入式系統裡嗎?其實不管他照放,也是沒關係,因為整個系統的表現程度還算可以接受,但是從原本是工作站的系統,直接放到一個小小類似PDA的系統上,似乎有那麼一點點不對勁。(Linux何嘗不是?)

談到這邊,筆者先來描述一下所用到的發展環境,所用的作業系統,前面已經提到就是TICKERS,所用的CPUMotorola DragonBall MC68EZ328,這是目前相當普遍的68K系列的CPU,知名的Palm就是採用這個種類的CPU,雖然他是一種32位元的CPU,但是運算執行速度並不快,若是系統設計得好的話,省電是他的一大特色,另外筆者的發展平台還包含了4MB RAM2MB flashROM,因此很明顯可以看出來,這是不太適合一口氣開一大堆執行緒在上面執行的一個環境。

當然進行移植的時候,碰到一大堆的問題,例如DragonBall CPU是一種big endianCPU,普通的x86 CPU是屬於little endianCPU,所以我們在處理多位元的數值,必須要特別做數值的轉換處理。

什麼是big endianCPU?那什麼是little endianCPU?其實這只是取值的方法不同的系統,像big endianCPU,如果你是想要取得多位元的數值,例如取得一個short的值,我們知道short是兩個byte所組成的值,當一個記憶體中顯示為『0x01 0x02』的值,在big endianCPU會視為12,但是在little endianCPU會視為21。當然像是long的話,也是剛好相反﹔不過在字元處理上,我們知道一個字元就是一個byte,處理方式兩者是一樣的,還好一樣,不然做不下去了。我用下面的例子再為各位讀者說明一下,這是以x86 CPU(little endianCPU)為解釋的範例,若是程式長得像這樣︰

char c1 = 1;

char c2 = 2;

short s = 255; // 0x00FF

long l = 0x44332211;

在記憶體直接顯示出來就像這樣︰

offset

Memory dump

0x0000

01

02

FF

00

0x0004

11

22

33

44

看出來了嗎?剛好是顛倒過來的表示方式。

另外可能會碰到的問題就是byte alignment的問題,像是DragonBall CPU2bytes alignmentCPU,所以一旦存取到奇數位元的值,就會發生CPU例外錯誤的發生,簡單一點的講法就是當機了,下次再仔細為讀者介紹這一部份的發生狀況。所以移植的時候,會需要針對不同CPU的特性,特別作調整,仔細一點的程式設計師就會特別對需要這些處理的情況做出定義或是巨集來解決這樣的問題,例如我在處理htons()htonl()ntohs() ntohl()這四個TCP/IP常用的函式裡就定義如下︰

#if defined(BIG_ENDIAN)

#define htons(A) (A)

#define htonl(A) (A)

#define ntohs(A) (A)

#define ntohl(A) (A)

#elif defined(LITTLE_ENDIAN)

#define htons(A) ((((A) & 0xff00) >> 8) | \

((A) & 0x00ff) <<>

#define htonl(A) ((((A) & 0xff000000) >> 24) | \

(((A) & 0x00ff0000) >> 8) | \

(((A) & 0x0000ff00) <<>

(((A) & 0x000000ff) <<>

#define ntohs htons

#define ntohl htohl

#else

#error "One of BIG_ENDIAN or LITTLE_ENDIAN must be #define'd."

#endif

看得出來這四個函式在做些什麼呢?原來就是把多位元數值(例如short或是long)的位元作前後掉換的動作。因為一個標準的網路封包內的格式是固定的,不會因為你的工作環境CPU的不同而有所變動,否則很難達到所有電腦都連上網路的效果。因此他全都是以類似big endian的方式存在,如果在x86電腦這種little endian的系統上,就必須作轉換的動作,不然x86電腦會誤判這個數值。

這是處理這樣問題常用的技巧,如果讀者拿到一個號稱可以跨平台的程式,一定會發現到處都是定義(#define),因為每個平台用的表達方法全都不一樣,如果用的編譯器又很笨,例如筆者現在用的SDS C Compiler,實在是不太聰明,什麼動作都要手動自己調,程式寫錯了也檢查不出來,這時候就是要看個人經驗了,也就是您在這樣的環境下吃過多少苦頭,以後就累積成您的經驗了。例如筆者的一個朋友黑狗兄就曾經對2500AD C Compiler(發展8051系統常用的C Compiler)做出這樣的感慨︰

『如果我有一個願望可以實現的話,我希望2500AD這家公司不曾在地球上出現過,出那鍋什麼爛compiler, sh.......t

講了許多的移植經驗,讀者一定很好奇,可憐的筆者到底最後怎麼解決所需要的答案,很不幸各位讀者一定猜到了,筆者自己重新寫一個出來,真正應驗了莫非定律,最壞的情況一定會發生。還好UDP協定只需要處理網路封包的編解動作,而且是屬於遺失就不理他的協定,並不需要有重新傳送的機制,筆者只需要自己開一個計時器,決定是否要等待這個封包的回應就好了,那書上寫了一大堆的Socket的機制呢?天呀!就不要再要求了吧?Socket本身是一個複雜的資料結構,還真的叫我把這些全部實作出來?好吧!我承認我偷懶。

圖六、TCP/IP架構和OSI七層之間的對應關係

當然,只寫出一個UDP協定是沒有用的,還要其他的相關程式配合,例如撥接上網的話,我需要一個PPP (Point-to-Point Protocol)的機制來幫助我連上ISP,當然還要自己寫一個UART(DragonBall EZ CPU本身就包含了一個UART的控制晶片)的驅動程式來控制數據機的撥號,我需要在作業系統裡開啟一個監控的執行緒,來監視每一個從RS-232傳進來的位元,並且將資料解出來放到應用程式已經規劃好的記憶體空間裡,這時候我們會用到資料結構的教科書裡常常提的環狀buffer的機制,以免記憶體存取失當造成破壞,所以我們做出來的東西就大概類似上圖所示,筆者順便列出整個TCP/IP架構和OSI七層之間的對應關係。

最後特別提醒千萬要注意處理記憶體要非常小心,因為許多嵌入式作業系統為了達到核心很小的目的,並沒有做太多的記憶體保護,有的更扯,連記憶體管理都沒有,也就是說您不可以使用任何動態要求記憶體空間的行為,這種作業系統為什麼還有人用呢?便宜就是最大的原因,例如SuperTask這種作業系統就是一個例子。

拉里拉雜的講了這麼多,無非是想讓有興趣一窺究竟的讀者有個初步的認識跟印象,如果真的對嵌入式系統上TCP/IP協定開發有興趣,也許您可以參考筆者後面所列的幾本書,會有一些基礎的認識,有幾本TCP/IP聖經有中譯版,可惜中譯版翻譯的很難看懂,還是要中英對照之後才懂翻譯的意思,希望從事翻譯工作的大爺們能夠多多用心,因為筆者大學的時候也是靠中譯版撐過每一學期的課程。

最後讀者可能還有疑問就是為什麼筆者只用哈x族當例子,而不是用Palm呢?其實筆者每天都可以接觸到許多的PDA或是類似產品,可是唯一只有這台哈x族是筆者自己買的,其他接觸的東西都是公家的,不能隨便污走,真希望能夠賺點外快,買台屬於自己的PDA,也希望以後還有機會多和讀者分享這方面相關的資訊和經驗。

附註參考資料

Comer, Douglas E. Internetworking with TCP/IP-Volume 1: Principles, Protocols, and Architecture, 4th ed. Englewood Cliffs, NJ: Prentice Hall, 2000.

Comer, Douglas E. and David L. Stevens. Internetworking with TCP/IP-Volume 2, ANSI C Version: Design, Implementation, and Internals, 3rd ed. Englewood Cliffs, NJ: Prentice Hall, 1998.

Comer, Douglas E. and David L. Stevens. Internetworking with TCP/IP-Volume 3, Windows Socket Version: Client-Server Programming and Applications, 1st ed. Englewood Cliffs, NJ: Prentice Hall, 1997.

Comer, Douglas E. and David L. Stevens. Internetworking with TCP/IP-Volume 3, BSD Socket Version: Client-Server Programming and Applications, 2nd ed. Englewood Cliffs, NJ: Prentice Hall, 1996.

Stevens, W. Richard. TCP/IP Illustrated-Volume 1: The Protocols. Reading, MA: Addison-Wesley, 1994.

Wright, Gary R. and W. Richard Stevens. TCP/IP Illustrated-Volume 2: The Implementation. Reading, MA: Addison-Wesley, 1995.

Stevens, W. Richard. TCP/IP Illustrated-Volume 3: TCP for Transactions, HTTP, NNTP, and the Unix Domain Protocols. Reading, MA: Addison-Wesley, 1996.

RFC 參考資料︰http://www.faqs.org/rfcs/.

2009年3月26日 星期四

test1






<br />void ClearClosedCaption(void)<br />{<br /> #ifdef SUPPORT_TW88_CC_DECODER<br /> ClearClosedCaption_TW88();<br /> #endif<br /><br /> #ifdef SUPPORT_CC_DECODER<br /> ClearClosedCaption_Zilog();<br /> #endif<br />}<br />

test

<br /><style type="text/css"> xmp.code { color: #000000; border: 1px solid #cccccc; background: #cccccc url(http://abinlee.link.googlepages.com/BG_CODE.gif) left top repeat-y; } </style><br /><br /><span style="color: rgb(255, 0, 0);"><p></p></span><span style="color: rgb(255, 0, 0);"><br /></span><br />void ClearClosedCaption(void)<br />{<br /> #ifdef SUPPORT_TW88_CC_DECODER<br /> ClearClosedCaption_TW88();<br /> #endif<br /><span style="color: rgb(255, 0, 0);"><br /></span><br /> #ifdef SUPPORT_CC_DECODER<br /> ClearClosedCaption_Zilog();<br /> #endif<br />}<br /><span style="color: rgb(255, 0, 0);"><br /></span><br /><span style="color: rgb(255, 0, 0);"><p></p></span><br /><br />

2009年3月21日 星期六

uc-os ii file system --about hardware mapping

FS__device_type ---- source insight can't index , why ??
FS__fsl_type 卻可以
先備份 ucfs_Source-0322.rar; 將 FS__device_type 拷貝於 FS__fsl_type 之下



記錄目的 : 軟體分層("pure algrithm for file system access" v.s "real hardware")

FS__pDevInfo
[idx].fs_ptr->fsl_fopen


& 一個簡易的操作系統下 -- 驅動程式如何編寫 (也不完全啦)??
應該說 file system 的資料結構......或說看到好多資料結構(於 linux 中) 內都帶有函數
(題外話 : C++ 函數封裝 ); 剛好 uc-os-ii FS 就有這樣的形式



// 原計畫由上層往下層找,但很像由下層找上去也不錯,看起來很像是由上往下找,但上面實際上十後面捕的 ---> 又重新編排,由下層往上層看,排版由上往下

// all project save in C:\test\ucfs_Source ;尚未歸檔於備份硬碟中

顏色管理 : 藍色 往下尋找的關鍵字, 紅色 為找到的結果

/*-------------------------------------------------*/
/*-------------------------------------------------*/
At91rm9200hdd.c (device\ide\hardware\at91rm9200):void AT91F_HDDOpen(void){
At91rm9200hdd.h (device\ide\hardware\at91rm9200):void AT91F_HDDOpen(void);
下列為出現 xx.h 內, **.c 內還有許多 intenal function
故 xx.h 才是開放給上層的


int AT91F_HDDRead(unsigned short *,int);
int AT91F_HDDWrite(unsigned short *,int);
int AT91F_HDDErase(int);
void AT91F_HDDOpen(void);
int AT91F_HDDSleep(void);
int AT91F_HDDRead_ID (unsigned short *);

/*-------------------------------------------------*/
// ide.c (device\ide\hardware\at91rm9200

//int FS__IDE_Init(FS_u32 Unit){
// AT91F_HDDOpen();
// return 0;
//}

//int FS__IDE_ReadSector(FS_u32 Unit,unsigned long Sector,unsigned char *pBuffer){
// AT91F_HDDRead((unsigned short *)pBuffer,Sector);
// return 0;
//}


//int FS__IDE_WriteSector(FS_u32 Unit,unsigned long Sector,unsigned char *pBuffer){
// AT91F_HDDWrite((unsigned short *)pBuffer,Sector);
// return 0;
//}

/*-------------------------------------------------*/
Ide_drv.c (device\ide): FS__IDE_Init(Unit);
_FS_IDE_DevStatus
_FS_IDE_DevIoCtl

/*-------------------------------------------------*/
Ide_drv.c (device\ide):static int _FS_IDE_DevIoCtl(FS_u32 Unit, FS_i32 Cmd, FS_i32 Aux, void *pBuffer)

const FS__device_type FS__idedevice_driver = {
"IDE device",
_FS_IDE_DevStatus,
_FS_IDE_DevRead,
_FS_IDE_DevWrite,
_FS_IDE_DevIoCtl
};

/*-------------------------------------------------*/
(key word seach : FS__idedevice_driver
Fs_info.c (api): extern const FS__device_type FS__idedevice_driver;
Fs_info.c (api): #define FS_DEVINFO_DEVIDE { "ide", &FS__fat_functable, &FS__idedevice_driver, FS_CACHEINFO_IDE_DRIVER 0 },

/*-------------------------------------------------*/
(key word search :FS_DEVINFO_DEVIDE)
Fs_info.c (api): #define FS_DEVINFO FS_DEVINFO_DEVSMC FS_DEVINFO_DEVMMC FS_DEVINFO_DEVIDE FS_DEVINFO_DEVFLASH FS_DEVINFO_DEVWINDRV FS_DEVINFO_DEVRAM

/*-------------------------------------------------*/
Fs_info.c (api):const FS__devinfo_type _FS__devinfo[] = { FS_DEVINFO };

_FS__devinfo -> can not find information to the other file
switch to FS_devinfo_type -->find FS_pDevinfo

/*-------------------------------------------------*/
Fs_int.h (api):extern const FS__devinfo_type *const FS__pDevInfo;
Fs_info.c (api):const FS__devinfo_type *const FS__pDevInfo = _FS__devinfo;

/*-------------------------------------------------*/
(keyword search : FS__pDevInfo
看樣子對應到上層了,因為許多檔案用到這個
Api_misc.c/Fat_dir.c / Fat_in.c / Fat_ioct.c /Fat_misc.c / Fat_open.c
Fat_out.c/Lb_misc.c

ex>FS_FILE *FS_FOpen(const char *pFileName, const char *pMode) {
FS_FARCHARPTR s;
FS_FILE *handle;
unsigned int i;
int idx;
int j;
int c;

/* Find correct FSL (device:unit:name) */
idx = FS__find_fsl(pFileName, &s);
if (idx < style="color: rgb(255, 0, 0);">FS__pDevInfo[idx].fs_ptr->fsl_fopen) {



/*-------------------------------------------------*
終於找到 main 了

Api_misc.c (api):* FS_FOpen
Api_misc.c (api):FS_FILE *FS_FOpen(const char *pFileName, const char *pMode) {
Fs_api.h (api): No open file bug when using FS_FOpen(name,"r+")
Fs_api.h (api):FS_FILE *FS_FOpen(const char *pFileName, const char *pMode);
Main.c (sample): myfile = FS_FOpen(name,"w");
Main.c (sample): myfile = FS_FOpen(name,"r");




// 補充說明 : 操作方法說明 FS__pDevInfo[idx].fs_ptr->fsl_fopen


--------------------------------簡易型式說明------------------------------
struct xxx
{
aaa
bbb
}

ex1>
struct xxx ccc;

if one access aaa/bbb
ccc.aaa / ccc.bbb //using "." dot to access

ex2>
struct xxx *ddd
if one access aaa/bbb
(*ddd).aaa/(*ddd)bbb ------ ddd -> aaa ; ddd -> bbb // using "->" to access
----------------------------正式說明---------------------------------
******FS__pDevInfo[idx].fs_ptr->fsl_fopen*******

typedef struct {
const char *const devname;
const FS__fsl_type *const fs_ptr;
const FS__device_type *const devdriver;
#if FS_USE_LB_READCACHE
FS__LB_CACHE *const pDevCacheInfo;
#endif /* FS_USE_LB_READCACHE */
const void *const data;
} FS__devinfo_type;



typedef struct {
FS_FARCHARPTR name;
FS_FILE * (*fsl_fopen)(const char *pFileName, const char *pMode, FS_FILE *pFile);
void (*fsl_fclose)(FS_FILE *pFile);
FS_size_t (*fsl_fread)(void *pData, FS_size_t Size, FS_size_t N, FS_FILE *pFile);
FS_size_t (*fsl_fwrite)(const void *pData, FS_size_t Size, FS_size_t N, FS_FILE *pFile);
long (*fsl_ftell)(FS_FILE *pFile);
int (*fsl_fseek)(FS_FILE *pFile, long int Offset, int Whence);
int (*fsl_ioctl)(int Idx, FS_u32 Id, FS_i32 Cmd, FS_i32 Aux, void *pBuffer);
#if FS_POSIX_DIR_SUPPORT
FS_DIR * (*fsl_opendir)(const char *pDirName, FS_DIR *pDir);
int (*fsl_closedir)(FS_DIR *pDir);
struct FS_DIRENT * (*fsl_readdir)(FS_DIR *pDir);
void (*fsl_rewinddir)(FS_DIR *pDir);
int (*fsl_mkdir)(const char *pDirName, int DevIndex, char Aux);
int (*fsl_rmdir)(const char *pDirName, int DevIndex, char Aux);
#endif /* FS_POSIX_DIR_SUPPORT */
} FS__fsl_type;
------------------------
FS__devinfo_type _FS__devinfo[] = { FS_DEVINFO };
宣告 裝置結構體"陣列";來表示存取的種類 (sd /mmc/ ide)
------------------------
Fs_int.h (api):extern const FS__devinfo_type *const FS__pDevInfo;
Fs_info.c (api):const FS__devinfo_type *const FS__pDevInfo = _FS__devinfo;
宣告 指針來存取上述 裝置結構體"陣列"

ps : C 語言中讓我困擾的地方 ?? 很像 C++ 有改了 const FS__devinfo_type *const FS__pDevInfo = _FS__devinfo; 正常應該這樣,一步應該分兩步 // step 1 : declare pointer variable // 宣告指針變數 FS__devinfo_type *const FS__pDevInfo; // step 2: assign array name without [] to pointer variable // 將陣列變數名(不帶[] ) 賦值給指針 FS__pDevInfo = _FS__devinfo;


------------------------
FS__pDevInfo[idx].fs_ptr->fsl_fopen
指針又以陣列形式存取內容


//--------------------------------------------
**** Fat_misc.c****
const FS__fsl_type FS__fat_functable = {
#if (FS_FAT_NOFAT32==0)
"FAT12/FAT16/FAT32",
#else
"FAT12/FAT16",
#endif /* FS_FAT_NOFAT32==0 */
FS__fat_fopen, /* open */
FS__fat_fclose, /* close */
FS__fat_fread, /* read */
FS__fat_fwrite, /* write */
0, /* tell */
0, /* seek */
FS__fat_ioctl, /* ioctl */
#if FS_POSIX_DIR_SUPPORT
FS__fat_opendir, /* opendir */
FS__fat_closedir, /* closedir */
FS__fat_readdir, /* readdir */
0, /* rewinddir */
FS__fat_MkRmDir, /* mkdir */
FS__fat_MkRmDir, /* rmdir */
#endif /* FS_POSIX_DIR_SUPPORT */
};

****fat_open.c*****
FS_FILE *FS__fat_fopen(const char *pFileName, const char *pMode, FS_FILE *pFile) {
xxx
FS__lb_ioctl(FS__pDevInfo[pFile->dev_index].devdriver, unit, FS_CMD_INC_BUSYCNT, 0, (void*)0); /* Turn on busy signal */
xxx


FS__pDevInfo[Idx].devdriver

2009年3月17日 星期二

uc-os ii 記憶體佔用分析-part II

嘗試 庖丁解牛,一個個分析所塞入的變數 PART2
於 m51 中找關鍵字 "MODULE",
可看到 code & x -> 程式與變數的配置 (特定模塊)


------- MODULE UCOS_II
C:0000H SYMBOL _ICE_DUMMY_
X:0223H PUBLIC OSRdyGrp
X:0224H PUBLIC OSCPUUsage
X:0225H PUBLIC OSIdleCtrRun
I:000AH PUBLIC OSRunning
X:0229H PUBLIC OSLockNesting
X:022AH PUBLIC OSTCBList
X:022DH PUBLIC OSTCBFreeList
I:000BH PUBLIC OSTCBCur
X:0230H PUBLIC OSIntNesting
I:000EH PUBLIC OSTCBHighRdy
X:0231H PUBLIC OSTime
X:0235H PUBLIC OSTCBPrioTbl
X:024AH PUBLIC OSCtxSwCtr
X:024EH PUBLIC OSEventTbl
X:025EH PUBLIC OSEventFreeList

uc-os ii 記憶體佔用分析-part1

Data: 2009/03/17

嘗試 庖丁解牛,一個個分析所塞入的變數 PART1

XDATA 0000H 0105H UNIT ?XD?OS_CORE
XDATA 0105H 00A2H UNIT ?XD?SERIAL
XDATA 01A7H 007CH UNIT ?XD?DEMO
XDATA 0223H 0049H UNIT ?XD?UCOS_II

1.XDATA 0000H 0105H UNIT ?XD?OS_CORE


一開始要分析有點困難,將m51中 有關 OS_CORE 獨立放於另一個檔案
MODULE OS_CORE
xxxxxxxxxxxx
ENDMOD OS_CORE

X:0000H SYMBOL OSTaskStatStk; 60 ->0x3c
X:003CH SYMBOL OSTCBTbl; 一個 tcb佔 20
X:00C8H SYMBOL OSIntExitY
X:00C9H SYMBOL OSTaskIdleStk


x:0003H SYMBOL prio
x:0004H SYMBOL ptos
x:0007H SYMBOL pbos
x:000AH SYMBOL id
x:000CH SYMBOL stk_size
x:000EH SYMBOL pext
x:0011H SYMBOL opt
------------------------------------
x:0000H SYMBOL ptcb
x:0003H SYMBOL x
x:0004H SYMBOL y
x:0005H SYMBOL bitx
x:0006H SYMBOL bity
x:0007H SYMBOL prio
上面只是一小部份,還有很多重複,程式如何做覆蓋分析的呢 ??
( X:0000H SYMBOL OSTaskStatStk)

60(stack)+20x7(tcb)+1+60(stack) = 261 =0x105 (0x00 ~ 0x104)

補充: 總共有 7 個 task
#define OS_MAX_TASKS 5
static OS_TCB OSTCBTbl[OS_MAX_TASKS + OS_N_SYS_TASKS];

/* 因為 OS_TASK_STAT_EN =1 ,故為 2
//#if OS_TASK_STAT_EN
//#define OS_N_SYS_TASKS 2 /* Number of system tasks */
//#else
//#define OS_N_SYS_TASKS 1
//#endif



2.XDATA 0105H 00A2H UNIT ?XD?SERIAL
0xa2 = 162
X:0105H PUBLIC inRxBuf
X:0108H PUBLIC outRxBuf
X:010BH PUBLIC inTxBuf
X:010EH PUBLIC outTxBuf

X:0111H PUBLIC RxBuf
X:0143H PUBLIC TxBuf

//unsigned char TxBuf[LenTxBuf],RxBuf[LenRxBuf];//收發緩衝區實體
//unsigned char *inTxBuf,*outTxBuf,*inRxBuf,*outRxBuf;//收發緩衝區讀寫指針

//#define LenTxBuf 100
//#define LenRxBuf 50

四個指針 4*3 =12
另外緩衝區 150
---------------------------TOTAL 162




3. XDATA 01A7H 007CH UNIT ?XD?DEMO
ultraedit ctrl+f "01A7H"

X:01A7H PUBLIC Fun_Sem
X:01AAH PUBLIC TaskStartStkyya
X:01E6H PUBLIC TaskStartStkyyb

--指針三個BYTe 0x1a7 -> 0x1a9
--0x1aa + 60 (stack size) = 0x1aa + 0x3c = 0x1e6
--另一段堆疊的底
--0x1e6 + 0x3c = 0x222

----------totol resource get from xram
60+60+3=123= 0x7b ...還少一個

繼續查 m51,有一個 0x222 為 err




4.XDATA 0223H 0049H UNIT ?XD?UCOS_II
0x223+0x49=0x26c (end)
又 0x49 = 73

--OS_EXT OS_EVENT OSEventTbl[OS_MAX_EVENTS];

// struct {
// void *OSEventPtr;
// INT8U OSEventTbl[OS_EVENT_TBL_SIZE];
// INT16U OSEventCnt; /* Count of used when event is a semaphore */
// INT8U OSEventType; /* OS_EVENT_TYPE_MBOX, OS_EVENT_TYPE_Q or OS_EVENT_TYPE_SEM */
// INT8U OSEventGrp; /* Group corresponding to tasks waiting for event to occur */
// } OS_EVENT;

// #define OS_MAX_EVENTS 2

-- 8*2 =16 byte

有重複命名的嫌疑 ?? OSEventTbl[OS_MAX_EVENTS] v.s OSEventTbl[OS_EVENT_TBL_SIZE]

--OS_EXT OS_TCB *OSTCBPrioTbl[OS_LOWEST_PRIO + 1];
又 #define OS_LOWEST_PRIO 6
---指針3 byte --> 3*7=21


X:0223H PUBLIC OSRdyGrp ;1
X:0224H PUBLIC OSCPUUsage ;1
X:0225H PUBLIC OSIdleCtrRun ;4
X:0229H PUBLIC OSLockNesting ;1
X:022AH PUBLIC OSTCBList ;3 pointer
X:022DH PUBLIC OSTCBFreeList ;3
X:0230H PUBLIC OSIntNesting ;1
X:0231H PUBLIC OSTime ;4
X:0235H PUBLIC OSTCBPrioTbl ;21
X:024AH PUBLIC OSCtxSwCtr ;4
X:024EH PUBLIC OSEventTbl ;16
X:025EH PUBLIC OSEventFreeList ;3
X:0261H PUBLIC OSIdleCtr ;4
X:0265H PUBLIC OSTaskCtr ;1
X:0266H PUBLIC OSStatRdy ;1
X:0267H PUBLIC OSIdleCtrMax ;4
X:026BH PUBLIC OSRdyTbl ;1
---------------------------------total--------73 =36+21+16

2009年3月15日 星期日

task schedule & Semaphore--uc/os ii

// 記錄原因 :
task TCB 有用 dual linker pointer 指針串接每一task
--> 目的 -> 管理
但調度與上面指針(串接)沒有很大的關係,有另外映射的機制

// 記錄 task 資訊
static OS_TCB OSTCBTbl[OS_MAX_TASKS + OS_N_SYS_TASKS];

OS_EXT idata OS_TCB *OSTCBCur; /* Pointer to currently running TCB */
OS_EXT OS_TCB *OSTCBFreeList; /* Pointer to list of free TCBs */
OS_EXT idata OS_TCB *OSTCBHighRdy; /* Pointer to highest priority TCB ready to run */
OS_EXT OS_TCB *OSTCBList; /* Pointer to doubly linked list of TCBs */
OS_EXT OS_TCB *OSTCBPrioTbl[OS_LOWEST_PRIO + 1];/* Table of pointers to created TCBs */

task -TCB 以指針串接,以 OSTCBList 為始; 但一般當 OSTimeTick 的時候才會遍尋所有的TCB
(也沒辦法,因為工作中有 delay....要遍尋每一個 )

找出優先權的 task 以這樣遍尋的手法會很浪費時間,所以以
*OSTCBPrioTbl[OS_LOWEST_PRIO + 1]; 記錄工作於這個 "指標陣列" 之中, task 的優先權與之結合,故只要找出 "最高優先權",便可以找到該 task,

task priority from 0~63,你要如何找出呢 ?? 難不成也遍尋 ?? 上面就失去意義了 ??
手法 : 將每個 enable 的 task , 其分配一個特定的優先權( 0~ 63), 以 bit 表示一個 task enable, 8 個 Byte 共有 64 個 bit, bit 的位置就是其優先權-----OSRdyTbl[7]

又是要遍尋嗎 ??
原本遍尋 64 個任務,現在遍尋 8 個 Byte中的每一個 bit ?? 也是 64 次,有做等於沒做
否,還有更好的方法嗎 ?? 遍尋 8 個 Byte, 每個Byte "映射" 找出優先權最高的任務 ??
---> 還是要遍尋 8 次 , 還有更好的方法嗎 ??

再透過一個 Byte (OSRdyGrp) 中的每一個 bit,表示 8 個 Byte 中的每一個 Byte 是否有任務 ??
遍尋 8 個 bit ?? No, 也是以映射的方式,找出優先權最高

OSRdyGrp : 可能的排列組合,XXXX 表示 don't care

xxxx-xxx1 --> 映射到 "0" ; 有 2^7 個組合
xxxx-xx10 --> 映射到 "1" ; 有 2^6 個組合
xxxx-x100 --> 映射到 "2" ; 有 2^5 個組合
xxxx-1000 --> 映射到 "3" ; 有 2^4 個組合
xxx1-0000 --> 映射到 "4" ; 有 2^3 個組合
xx10-0000 --> 映射到 "5" ; 有 2^2 個組合
x100-0000 --> 映射到 "6" ; 有 2^1 個組合 ; 故 64,196 映射成 6
1000-0000 --> 映射到 "7" ; 有 2^0 個組合
----------------------------------------------------
這是一個等比級數,老祖宗有教過 ; Sn=(r^n-1)/(r-1) = (2^8 -1)/(2-1)=255

以這個為例 : x100-0000 --> 映射到 "6" ; 有 2^1 個組合 ; 故 64,196 映射成 6
注意 : 下面 table 內紅色的數字

code INT8U const OSUnMapTbl[] = {
0, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
7, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0
};

// 補充 : 將 priority 0~63 資訊轉成 bit 資訊, 以 OSRdyGrp &OSRdyTbl表達
ptcb->OSTCBY = prio >> 3; /* Pre-compute X, Y, BitX and BitY */
ptcb->OSTCBBitY = OSMapTbl[ptcb->OSTCBY];
ptcb->OSTCBX = prio & 0x07;

ptcb->OSTCBBitX = OSMapTbl[ptcb->OSTCBX];


&
OSRdyGrp |= ptcb->OSTCBBitY; /* Make task ready to run */ OSRdyTbl[ptcb->OSTCBY] |= ptcb->OSTCBBitX;


//-----------------------------------------------//
void OSSched (void) reentrant
{
INT8U y;
OS_ENTER_CRITICAL();
if ((OSLockNesting | OSIntNesting) == 0) {
y = OSUnMapTbl[OSRdyGrp];
OSPrioHighRdy = (INT8U)((y << 3) + OSUnMapTbl[OSRdyTbl[y]]);
if (OSPrioHighRdy != OSPrioCur)
{
OSTCBHighRdy = OSTCBPrioTbl[OSPrioHighRdy];
OSCtxSwCtr++;
OS_TASK_SW(); /* Perform a context switch */
}
}
OS_EXIT_CRITICAL();
}




// 與 task 實做很像

OSSemPend 的時候,需將 task 移出( 這樣排程不到這個 task--delay的時候也是以移出的手法)
所以OSEventGrp,OSEventTbl 記錄 task 資訊; (OsEventTaskWait)
-- 因記錄,所以等會可以恢復----
1. timeout 時,OSEventGrp/OSEventTbl 移除,
2. task 資訊 --OSRdyGrp/OSRdyTbl 於 OSTimeTick 恢復

OSSemPost --> OSEventTaskRdy
1. 透過 Fun_Sem 找出優先權最高的"等待 task",
移除此資訊OSEventGrp/OSEventTbl
2. task 資訊 OSRdyGrp/OSRdyTb 恢復

Note :
OS_EVENT *Fun_Sem;

typedef struct {
void *OSEventPtr; /* Pointer to message or queue structure */
INT8U OSEventTbl[OS_EVENT_TBL_SIZE]; /* List of tasks waiting for event to occur */
INT16U OSEventCnt; /* Count of used when event is a semaphore */
INT8U OSEventType; /* OS_EVENT_TYPE_MBOX, OS_EVENT_TYPE_Q or OS_EVENT_TYPE_SEM */
INT8U OSEventGrp; /* Group corresponding to tasks waiting for event to occur */
} OS_EVENT;



// 測試有 timeout 時的路徑, OSSemPend -> OSEventTaskWait -> OSSched -> OSEventTO
for(;;){

OSSemPend(Fun_Sem,10,&err);

PrintStr("\nAAAA is active.");
OSSemPost(Fun_Sem);
OSTimeDly(OS_TICKS_PER_SEC);
if(P4_3==0)
{

GotoIsp();

}
}




why write this : 1.OSSemPend & OSSemPost 看不出來需求
ptcb->OSTCBEventPtr原因,

查找關鍵字ptcb->OSTCBEventPtr


OSTaskChangePrio() & OSTaskDel 中要判斷到 OSTCBEventPtr

if ((pevent = ptcb->OSTCBEventPtr) != (OS_EVENT *)0) { /* Remove from event wait list */
if ((pevent->OSEventTbl[ptcb->OSTCBY] &= ~ptcb->OSTCBBitX) == 0) {
pevent->OSEventGrp &= ~ptcb->OSTCBBitY;
}
pevent->OSEventGrp |= bity; /* Add new priority to wait list */
pevent->OSEventTbl[y] |= bitx;

/---------------
OSSemPend --> OSEventTaskWait
OSTCBCur->OSTCBStat |= OS_STAT_SEM;
OSTCBCur->OSTCBDly = timeout;

pevent->OSEventTbl[OSTCBCur->OSTCBY] |= OSTCBCur->OSTCBBitX;
pevent->OSEventGrp |= OSTCBCur->OSTCBBitY;



/*-------------------------------------------*/
OSCtxSw_in 改名為 OSCtxSw_out 比較容易理解,另外不會與其他名稱很相似
ex> OSCtxSw,OSIntCtxSw_in

/*---------------------------------------------*/
OSTimeTick 不會安排新工作,只是輪詢所有TCB 的 delay,然後有可能 task 回復運形態

OSIntExit 才是安排新工作的地方

LCALL _?OSIntEnter
LCALL _?OSTimeTick
LCALL _?OSIntExit

/*------------------------------------------*/
void OSIntEnter (void) reentrant
{
OS_ENTER_CRITICAL();
OSIntNesting++; /* Increment ISR nesting level */
OS_EXIT_CRITICAL();
}

/*------------------------------------------*/
void OSIntExit (void) reentrant
{
OS_ENTER_CRITICAL();
if ((--OSIntNesting | OSLockNesting) == 0) { /* Reschedule only if all ISRs completed & not locked */
OSIntExitY = OSUnMapTbl[OSRdyGrp];
OSPrioHighRdy = (INT8U)((OSIntExitY << 3) + OSUnMapTbl[OSRdyTbl[OSIntExitY]]);
if (OSPrioHighRdy != OSPrioCur) { /* No context switch if current task is highest ready */
OSTCBHighRdy = OSTCBPrioTbl[OSPrioHighRdy];
OSCtxSwCtr++; /* Keep track of the number of context switches */
OSIntCtxSw(); /* Perform interrupt level context switch */
}
}
OS_EXIT_CRITICAL();
}
/*------------------------------------------*/

2009年3月7日 星期六

uc-os ii - step by step to analysis

一個任務(ex : TaskStartyya)運行時,同時挪用的系統資源;
定義 : 系統棧 (SP 操作 ) v.s 任務棧 (TaskStartStkyya)
系統棧的深度 : call 的層數 + 中斷 push 的資料量 (worse case)
任務棧的深度 : re-enterance function 層數所累積的資料量,
( note : keil C51 呼叫函數以 r0~r7 傳遞, 標準 C 很像是以 Stack 傳遞 ?? )


觀察點 : 再進入函數所壓入的的資料,其所分配的記憶體是否衝突
add a watch : ?C_XBP
OSTaskStkInit
0x2e4
OSTCBInit
0x2df

一個任務運行時,同時挪用的系統資源;
1. 系統棧 SP 操作, call function / interrupt rs-232 / push, pop when interrupt
2. OS_STK TaskStartStkyya[MaxStkSize];//注意:我在ASM文件中設置?STACK空間為40H即64。 --> 會用到這個 stack 的頂端 as simulation stack for entrance function

( 其他問題點 :
1. OSStart 完成切換任務"前",0x2ff+1 的 simulation 永遠用不到,無法回收,因為不返回

2. Simulation stack 於 任務配置的TaskStartStkyya,因於 xram 中,所以操作速度不好
但相對系統棧要回存的資料只有當下 SP - SP-start;

另外的優點,系統棧可以小一點,與任務棧大小脫鉤

3. 可以改嗎 ?? simulation stack 操作於於系統棧之中,相對需回存所有的系統棧 to 任務棧之中


// 進入 TaskStartyya
?C_XBP 0x267 --> why ??
by 1 & 2 --> 0x22b + 60 = 0x22b + 0x3c = 0x267 ( 不是壓到 TaskStartyyb)
(與前面 0x2ff+1 有異曲同工; 堆棧都是先遞增或遞減操作 ++X)

1----------
#define MaxStkSize 60 //@ askey 100
2----------------------from m51--------
C:195DH PUBLIC main
X:022BH PUBLIC TaskStartStkyya
X:0267H PUBLIC TaskStartStkyyb
X:02A3H PUBLIC err
C:1A69H PUBLIC _?TaskStartyya



TaskStartyya 運行, PrintStr("\n123456789A123456789A123456789A1"); 時,發生串列中斷
?C_XBP 0x25c 當進入到 void serial(void) reentrant // 這一段很像不重要

?C_XBP 0x25f 當 OSTimeDly -> OSCtxSw --> & push all 此時 SP == 0x33,故有 0x13 Byte 需儲存

0x22b + 0x13 = 0x23e ....距離 0x25f 還有一段空間

// 當定義任務棧大小,編譯的結果
#define MaxStkSize 60 (xdata : 733) // 80 (xdata :793)
哈哈 編譯 xdata 爆了,竟然還可以跑 (0x733) --> 沒報,寫錯了
256*3= 768

當 793 看 m51 --肯定爆了
X:0317H PUBLIC OSTaskCtr
X:0318H PUBLIC OSRdyTbl

// 又做了一個實驗,設定成 #define MaxStkSize 70 (xdata 763)
沒爆,但也不會動 --> 因為 simulation stack 覆蓋到有些記憶體的配置,這個從記憶體配置中看不出來
X:02F9H PUBLIC OSTaskCtr
X:02F5H PUBLIC OSIdleCtr

//小結 : 只能說真是狗屎運,設成 60 竟然可以於 sm5964 跑起來,

2009年3月6日 星期五

uc-os ii 任務創建 --參數傳遞

OSTaskCreate(OSTaskIdle, (void *)0, &OSTaskIdleStk[0] 實際參數, OS_IDLE_PRIO);
--->
INT8U OSTaskCreate (void (*task)(void *pd), void *ppdata, OS_STK *ptos 形式參數 , INT8U prio) reentrant
{


void *psp;
psp = (void *)OSTaskStkInit(task, ppdata, ptos, 0); /* Initialize the task's stack * /
--> void *OSTaskStkInit (void (*task)(void *pd), void *ppdata, void *ptos 形參, INT16U opt) reentrant
err = OSTCBInit(prio, psp, (void *)0, 0, 0, (void *)0, 0);
--> INT8U OSTCBInit (INT8U prio, OS_STK *ptos 形參 , OS_STK *pbos, INT16U id, INT16U stk_size, void *pext, INT16U opt) reentrant

}
OS_STK *ptos 呼叫時及強制轉換 void *ptos -> void *psp -> 傳入 OSTCBInit 又強制轉換了 OS_STK *

為何這樣轉來轉去呢 ??


任務創建 --> 建立 task stack 初始化 r0 ~ r7 等任務第一次運行的資料 (覺得很像不重要,但佔據的空間順序或說個數很重要,往後都是依據每一位址取相對應資料,最後也是最特別的 虛擬 stack 的位置
*stk++ = (INT16U) (ptos+MaxStkSize) >> 8; //?C_XBP 仿真堆棧指針高8位
*stk++ = (INT16U) (ptos+MaxStkSize) & 0xFF; //?C_XBP 仿真堆棧指針低8位
)
--> 建立 TCB (TCB 內也要建立與 stack的關係)
ptos 可否直接傳入 OSTCBInit 中呢 ? 不轉來轉去 ?? (實際測試是可以的,因為 psp 內容實際與 ptos 相同,只是型別不同而已)

uc-os ii 調度

調度 -->
中斷級 (由時間中斷產生,並且找出優先權最高的任務)
任務級 (也就是任務 taska 自己 delay or pend semi 等事件發生時)

void TaskStartyya(void *yydata) reentrant;
void TaskStartyyb(void *yydata) reentrant;

曾經認為調度後的進入點,都是task的進入點 (錯誤),下面嘗試說明錯誤點
ex >做完 something1 之後, OSTimeDly使進入任務級切換,當延遲完成後,中斷級調度會使任務從 do something2 開始 (how to catch that point )
ex> 做完 something2 之後, 有可能中斷級調度發生,當高優先權任務完成,中斷級調度會使任務從 do something3 開始
taskA
{
do something1
OSTimeDly(10);
do something2
do something3

}

(how to catch that point )
OSTimeDly -> OSSched -> OS_TASK_SW 任務級調度
(呼叫切換函數,故下一指令 OS_EXIT_CRITICAL 的 位址被 push to stack 硬體機制做掉)

中斷級調度( 延時完成後) taskA 所返回的順序
OS_TASK_SW(OS_EXIT_CRITICAL) -> OSSched -> OSTimeDly -> do something2

us-osii run on sm5964

這個版本是 yy 的版本,有一點修動;
因sm5964 的 xram (internal) 最大為 0x2ff,故這部份要修訂

; Stack Space for reentrant functions in the LARGE model.
XBPSTACK EQU 1 ; set to 1 if large reentrant is used.
XBPSTACKTOP EQU 02FFH+1 ;07FFFH+1; set top of stack to highest location+1.


另串列接收的時候一直有亂碼,以為程式那邊有錯 ??
(看起來很像是 Tera Term 不穩定 - 於 19200 baud rate)




Further check ?? if i increase baud rate to 57600 -> 115200,
沒什麼作用,或說不大;字串轉進緩衝區,有很大的區塊是關閉中斷---無法同步發送資料

what is side effect ?? ( probably may i use less buffer to keep the data wait for transfer ??
but it also increase the times (次數) of rs-232 interrupt -> may cause timer interrupt less responsive to context switch ?? )



note : about PrintChar()
// can not direct use inTxBuf as operation,because it may warp around at begin inTxBuf==TxBuf+LenTxBuf"
// it's not easy to go back what has do, so used a tempraray variable "t"


目標確認 : 串列緩衝區 & Stack 大小的合理值,因為設太大也會丟資料錯誤
serial.h
#define LenTxBuf 100 // 2000 Don't too small,because it will cause display abnormal.
#define LenRxBuf 50
#define MaxLenStr 100 /*buf[MaxLenStr+1] for '\0'*/
os_cfg.h
#define MaxStkSize 60 //@ askey 100


出錯原因 : A 只有單字; ****....一行有31個字 /n 又兩個 --> 總共 33 個
塞 3 行就爆了(指緩衝區 #define LenTxBuf 100 )

而後資料就進不去了




// not 與 C -lang 中差異 --> extern v.s EXTRN
Os_cpu_a.asm
;聲明引用全局變量和外部子程序
EXTRN DATA (?C_XBP) ;仿真堆棧指針用於重入局部變量保存

EXTRN IDATA (OSTCBCur)
EXTRN IDATA (OSTCBHighRdy)


;對外聲明4個不可重入函數
PUBLIC OSStartHighRdy
PUBLIC OSCtxSw

// 設定 IP (d:0xb8) 中斷優先權的 side effect

//
IF XBPSTACK <> 0
EXTRN DATA (?C_XBP)

MOV ?C_XBP,#HIGH XBPSTACKTOP
MOV ?C_XBP+1,#LOW XBPSTACKTOP
ENDIF

//Os_cpu_a.asm
;保存仿真堆棧指針?C_XBP
INC DPTR
MOV A,?C_XBP ;?C_XBP 仿真堆棧指針高8位
MOVX @DPTR,A
INC DPTR
MOV A,?C_XBP+1 ;?C_XBP 仿真堆棧指針低8位
MOVX @DPTR,A




// m51 看記憶體配置,找方法使配置有效率
目前是於sm5964 ( 8051 type mcu),記憶體沒有很大,不向 arm 一樣;所以有點斤斤計較
256*3=768 (目前用 733 ) --引發問題,如何確認仿真堆棧的佔用大小

1.


2. 與 3.配套使用,似乎沒必要那麼大 ??
結果 還是要大一點.因為系統棧上方要放 simulation stack for entrance function

?STACK SEGMENT IDATA // 也是大陸書的說法,51 有系統棧
RSEG ?STACK
OSStack:
DS 40H
OSStkStart IDATA OSStack-1

51 使用系統棧的時機 --1. call 2. 中斷發生--自動push & push r0~r7 等 register
實際測試沒用到那麼多, 13H 已經夠了; 容餘設成 20H ?? 尚待驗證





3.Keil C for 8051 的編譯與大系統不同 ??
(下次有空試一下 mdk ?? 參數傳遞以堆棧,所有函數都是在進入 ?? )













引發問題 : 仿真棧的佔用情形 ??
上圖 看 m51 知變數分配位置,下圖 ?C_XBP (Keil 仿真的情形);已經快衝到了 ??
跑一段時間,看起來真的沖到了,但程式還是繼續跑 ??

(沒沖到,每一task分配stack,而stack的頂段就是simulated stack for entrance function)










TYPE BASE LENGTH RELOCATION SEGMENT NAME
-----------------------------------------------------

* * * * * * * D A T A M E M O R Y * * * * * * *
REG 0000H 0008H ABSOLUTE "REG BANK 0"
DATA 0008H 0002H UNIT ?C?LIB_DATA
IDATA 000AH 0009H UNIT ?ID?UCOS_II
0013H 000DH *** GAP ***
BIT 0020H.0 0000H.1 UNIT ?BI?SERIAL
0020H.1 0000H.7 *** GAP ***
IDATA 0021H 0041H UNIT ?STACK

* * * * * * * X D A T A M E M O R Y * * * * * * *
XDATA 0000H 0189H UNIT ?XD?OS_CORE
XDATA 0189H 00A2H UNIT ?XD?SERIAL
XDATA 022BH 0079H UNIT ?XD?DEMO
XDATA 02A4H 0039H UNIT ?XD?UCOS_II

2009年3月5日 星期四

一些網頁資料關於 :ucos & linux

轉貼備份的

linux系统编程视频教程
渴望学习linux系统编程程序员的福音!
本教程是由资深linux开发人员制作的一套系统学习linux系统编程的视频教程!
适合有c语言基础的各类开发人员进行学习。循序渐进,理论与实践相结合
学习完本套教程可以达到linux编程的中高级水平。

本套教程的优势:
1.有c语言基础但是不了解linux,在学完本套教程之后可以顺利帮助你走上出色linux程序员之路。
2.如果已经是专业的unix程序员,本套教程帮助您轻松转向linux
3.若已经是linux开发人员,通过对一些容易混淆和最新内核提供的新的替代系统调用的学习可以更加容易完成各类编程任务。
详情登陆:
http://blog.sina.com.cn/u/4b06636e010005v8 或
http://celebes-indian.spaces.live.com/ 或
http://blog.sina.com.cn/u/1258709870

uc-os ii 分析
http://blog.csdn.net/silenceee/archive/2006/11.aspx

uc-os ii file system
http://blog.csdn.net/silenceee/archive/2006/12/21/1452248.aspx

Team

Doing your best is easy in individual work(s),but when it comes to team work(s),you need a bit more wisdom.Doing your best in a team work(s) requires you to understand your role on the team.Everyone does not play the same role.In car lcd monitor works,there are at least three different roles in product design( electrical /software /mechanic engineer).The better teams are the ones in which each engineer performs his role well.

紅字有感觸,有時開發的產品被其他人扯後腿,心裡真不舒服,所以換工作的時候有時候會挑硬體的工作,有時候會挑軟體的工作來做,想要成會全才的人(但開發的時程不允許一個人做所有的工作,才會有分工)---會不會我也變成扯人家後腿的人 ?? 還有如何了解自身於該職務上的定位

上一期的 Studio Clase room 我有點小修改,覺得不錯就寫下來了 (上個月沒聽,因為出差到大陸,好冷又沒暖氣,人都沒有戰鬥力--人都躲到被窩了)

2009年3月4日 星期三

ISP 更新問題--結案

昨天很得到很明確的SyncMos 燒錄失敗的原因:
當專案程式內含有 ISP 區段的程式,而與 IC 內 ISP 程式不同時;
透過 WinHost 燒錄會失敗 (因為會做燒錄檢查,但那一段ISP程式又無法燒錄)

又看了BOX的電路圖,其他公司畫的圖真的比較有Sense,又很容易理解
例如說 : 實現的電路元件的排列 有由上而下,由左而又 (Input -> process -> Output)

2009年3月3日 星期二

IC 破解---orz

單晶片破解的公司
http://jm.infomcu.com/Crack/Holtek.html
硬體抄板的公司
http://pcbwork.net/sp.asp

公司拿到的樣品,想拿去解密,就上網查了一下;我是寫韌體的
(韌體的人以後就不用養了-- 決策著 是硬體主管;突然之間覺得很危險.....哈哈)
但是硬體乾脆也拿去給人家抄板好了,也不用花時間畫線路圖 & layout
(假如開發時程那麼趕的話,又想走短線的話;所以說 幹這種事情的 可不都是大陸同胞;
台灣的人也會這樣做)

(後記1 :七八年前剛出社會的時候,那時候在大陸做事情,就曾經幹過這種事情,拿去給人家抄板)
呵呵 剛剛還打電話與抄板的人扯淡 --> 分三種收費 : 1...抄板 (sch,bom,gerber) 2. 製版 3. 克隆
抄板費用約2800 人名幣;假如已經有電路圖與BOM;大概收費約 500~1000人民幣(收取for製作Gerber)

(後記2: 破解 HT46R22 --> 300 人民幣)

2009年3月2日 星期一

Holtek 資料閱讀

紀錄原因 : 找不到說明文件檔

有開發案需求要使用到Holtek 的 MCU
http://www.holtek.com.tw/chinese/tech/appnote/appnote.htm
這連結是 application note :
zip 欄位 : source code
描述 欄位 : 說明文件檔 pdf 格式

組語注意事項 :
1 -- mov a,0a0h ; 是搬 10100000(b) 到 a, 其它種組語 #0xa0 立即定址模式
2.-- 宣告區段 .section 'data' / .section at 0 'code'
3.-- 副程式 要宣告 xxx proc (source code) xxx endp


廣告時間 : 孕龍科技的邏輯分析儀真好用

今天該司的業務又打電話過來,之前因為使用該司邏輯分析儀有些使用上問題,
使用心得覺得不錯啦 (其實與之前使用的也差不多...呵呵 雖然之前不知道是哪各牌子 )
大部分PC連線 Base 的邏輯分析儀 都有協議分析的功能


今天特別請教他與大陸製造的邏輯分析儀間的差異,一般採購設備都有價格的考慮
(Orz 開發的時候使用的單晶片也是一樣,自己熟悉 Microchip ; 但有個案子,卻因為價格考慮要使用Holtek--當然Holtek 也不錯啦 )

廠商回覆 :
1. 有壓縮功能 -- 這有申請專利,所以大陸仿冒的話,可以取締
當初使用覺得不錯,未開取壓縮功能時;大概只有五秒鐘的紀錄 (因為機型記憶體小),打開時可以達到取樣資料達 30秒;但是PC等級最好高一點(或是RAM多一點),因為當初PC ram 很少,所以打開壓縮功能時,PC端軟體會出錯;後來RAM 加多就不會出現這個狀況

2. 協議分析持續增加 -- 隨然覺得協議分析的Loading 都是於PC端,但總要軟體工程師持續開發,這些都是金錢的投資


總結 : 台灣加油,面對全球化的競爭,落實好的想法於產品開發;還有事業經營可長可久,要走長線還是短線就看主事者的心態

SyncMos sm5964 專案內未包含ISP 程序問題點

問題點 : 當將 ISP 程序包進專案內,有 WinHost V31c 更新失敗的問題
(所以當初並沒有將ISP 程序包進專案內 )

引發問題 : 委外燒錄時,燒錄器 erase 時,也會將 ISP 區段的程式碼清除,故發生產線批量量產的機器無法更新的問題
(isp service space 的設定,對燒錄器使用時很像沒有作用 ?? 要使用那一款燒錄器呢 ?? 實際使用心得為只能於 WinHost V31c 時有起作用 )

原廠網站有一動畫檔 : 描述如何於量產型燒錄器 同時載入 專案燒錄檔 & ISP燒錄檔
兩階段式載入 : 1 .載入ISP燒錄檔 --但注意需於unused Bytes : 0xff (否則包含原廠ISP的專案燒錄檔於WinHost也是無法使用)
2.載入專案燒錄檔 --Unused Bytes : don't care (否則上面載入的內容會被覆蓋)

於 Keil 中只能產生 hex file,透過 hexbin2 轉換 bin file;
echo 1 | .\tools\hexbin2 .\obj\%1.hex .\obj\%1.bin I 0
其中參數 echo 1 ....使空白處也是保持 0xff; 之前的程序都是 echo 0 , 這樣空白處就是 0x00
實際WinHost燒錄,還好沒出什麼問題;(因為轉換過程非全部65536 都填值,只有轉到到 hex 終止處) (原擔心之前的問題 : ISP 區段內容不同,導致WinHost 更新失敗 )

SyncMos sm5964 WDT 應用考慮

讀了兩篇 IRFWX-A109_A_SM59264_WDT_APN(TC).pdf (有 C 的範例 ) & syncmos_sm59xx_wdt(chinese)_apn.pdf (只有組語的範例 )

一開始案子進行時,不敢將WDT打開;考慮的因素為 因為ISP的區段程序沒有按照 application note 說明將 WDT 關閉,
WDTKEY = 0X1E;
WDTKEY = 0XE1;
WDTC = 0X00;
WDTKEY = 0XE1;
WDTKEY = 0X1E;
所以想進入 ISP 程序時,會有WDT Reset 的可能 ?? ( 後記 : 結果不會 )
案子開發過程中,頻繁的使用ISP更動程序;所以此時未將 WDT 功能加入專案中;
想法 : 進入 ISP 程序前, 關狗

最近透過原廠得知 : ISP_AUTO30C.asm 中的 mov ie,#0x0 ; disable IE --> 也可以將狗關掉(錯誤)

(後記: 一個月前用的,記錯了...原廠FAE 有更正我,我又重新測試了一下)
if(P4_3==0)
{
WDTC = 0x00; // to ensure wdt disable
GotoIsp();
}
進入前要關狗,這只有 for sm5965, 其他的還是要透過 WDTKEY 的方式寫入 WDTC

ISP 更新問題4-燒錄器ALL-11設定

狀況 : 透過 WinHost V31c 燒錄時,連線第一次OK,但燒錄失敗 ; 再連線時 Fail

原因 : WinHost V31c 燒錄時有先清除的動作,因為使用All-11 燒錄時沒有設定 isp service space:default : 0 ; 故清除時是所有內容都清除(包含ISP的區段) --透過 all-11 讀出而知


ALL-11 燒錄ISP程序時, 注意事項 : 需於 isp service space 設定為 1
目前原廠ISP大小 : 464 (10) , 小於 512 ; 故只需設定 1 就好了 ;
原廠網站內的 application note 寫 2 (是針對另一型號的IC,可能ISP程序比較大)

ISP 更新問題3-燒錄器ALL-11設定

狀況 : 將原廠的 ISP_AUTO30C 透過 ALL-11 燒錄,更新 (因為這顆IC 同事之前使用過,ISP 的程式不是原廠的 )

後來當將自己專案的程式碼透過 WinHost V31c 燒錄,連線OK,燒錄失敗

讀出這顆IC的內容 (ISP-1) 與拿一顆未更動 (原廠出貨內含)ISP的IC--,讀出內容 (ISP-2)


差異點,原廠出貨的IC 內 ISP程序的區段,空白處為 0xff, 而自己使用燒錄器 all-11 時,燒錄設定時
unused bytes : 0x00 ---> 要改成 0xff (測試結果OK )

2009年3月1日 星期日

SyncMos sm5964 ISP 更新問題1-單一燒錄檔

目的 : 使燒錄檔單一化 ( 1. PC 配合 WinHost V31C 2. 委外燒錄 ) 需將 ISP_AUTO30C.obj 包進專案內編譯

(ISP_AUTO30C.asm 需先更動如下,否則產生的 obj 與 C 專案無法 link )
; org 0fe00h ;For ISP start address
CSEG AT 0xFE00
)
(ISP_AUTO30C.asm 與 keil C 的 C 專案不相容,所以需先將 ISP_AUTO30C.asm 產生 obj 格式
透過 linker 連接為燒錄檔)

(產生的 hex file 轉成 bin file 後,燒錄檔為 64K, 於PC端燒錄時,需配合 WinHost V31C;其他版本會有限制63.5K )

SyncMos sm5964 ISP 更新問題2-ISP 改動

狀況 : 同事改動ISP程式(根據客戶更新程式的要求)
SyncMos 原始ISP 定義為 ISP-A,
同事更動為ISP 定義為 ISP-B;

專案程式內包含新的ISP-B,以 WinHost V31C 無法更新 ISP區塊,
故以燒錄器 (all-11) 燒錄 --( isp service space : 1 ) ?? 有些人說 2

問題點 :
當拿包含 ISP-B的 IC 來使用時, 但自己的專案內是包含 ISP-A;
此時以WinHost V31C 更新程式時, 連線( autobaud -ok ) 但燒錄時Fail
拿新的IC (未更動ISP) --此時OK


想一想也有點合理的機制 -- 這樣才能用到配對 ISP 程式,

但引申出另外的問題 -- 當我 release 的燒錄檔包含ISP-A,
但一兩年後,原廠可能有新版ISP-C; 出貨的IC包含新的 ISP-C
--此時是否會造成上面的狀況--燒錄Fail (因為我的專案內包含的是ISP-A)

-- 所以要釐清為何更動ISP程式後,為何以 WinHost V31C 燒錄失敗 ??






另外抓了一個比較器軟體 extract difference ---因為這個軟體可比較 binary file
(compare it / beyond compare 比較之後都是亂碼

2009年2月26日 星期四

Hello world

Hello world ! it's my first blog, happy to here