小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

OSAL系統(tǒng)框架專(zhuān)題【轉(zhuǎn)載】

 韋小楓 2012-11-30

OSAL系統(tǒng)框架專(zhuān)題2010-4-15 2:47:00

9. TI協(xié)議棧所用系統(tǒng)框架探討。
51
的系統(tǒng)往往不是太大,但是幾十K的程序,也足以讓一個(gè)初學(xué)者望而卻步。我們首先忽略C語(yǔ)言本身的難度,光是系統(tǒng)框架也讓生手讀起來(lái)很吃力,再加上這種到處是API"define"的程序,還沒(méi)有正式學(xué)習(xí)協(xié)議部分就已經(jīng)讓人在叢林中迷路了。

在接下來(lái)的一段時(shí)間內(nèi),我會(huì)以TI所用的系統(tǒng)框架為主線進(jìn)行學(xué)習(xí),希望大家共同探討。。。

在層層迷霧中摸索了兩天,終于撥云見(jiàn)日,那個(gè)心情啊,怎一個(gè)字了得~~~

可是怎么能把這么復(fù)雜的一個(gè)問(wèn)題講得清楚呢?嗯。。。還是先上圖吧

OSAL系統(tǒng)框架專(zhuān)題【轉(zhuǎn)載】 - 小峰 - happy~
注:為了便于直觀,以下涉及到數(shù)據(jù)地址的地方都是由上而下,地址由高變低

1節(jié)、各個(gè)任務(wù)是如何被調(diào)用到的?
我們還是先從main()函數(shù)開(kāi)始,看看各個(gè)任務(wù)之間是如何協(xié)調(diào)工作的。
插播一句廣告:在一切都看不清的時(shí)候,忽略次要,看主要因素 -- by outman from Zigbeetech

我們直接進(jìn)入主循環(huán)的核心部分,看一下系統(tǒng)中的幾個(gè)主要的任務(wù)是如何被調(diào)用,并開(kāi)始自己的使命的?


看一段程序的時(shí)候,往往要從它的數(shù)據(jù)結(jié)構(gòu)入手。我們先看一下,主循環(huán)中的兩個(gè)關(guān)鍵數(shù)組,*tasksEvents*tasksArr,從圖一中我們可以看出來(lái),tasksEvents這個(gè)數(shù)組存放的是從序號(hào)為0tasksCnt,每個(gè)任務(wù)在本次循環(huán)中是否要被運(yùn)行,需要運(yùn)行的任務(wù)其值非0(用橙色表示),否則為0。而tasksArr數(shù)組則存放了對(duì)應(yīng)每個(gè)任務(wù)的入口地址,只有在tasksEvents中記錄的需要運(yùn)行的任務(wù),在本次循環(huán)中才會(huì)被調(diào)用到。--這節(jié)講完了。。。

又有同學(xué)舉手?什么?還沒(méi)明白?恩。。。好像是不能講這么短的。。。
那好吧,把main函數(shù)貼過(guò)來(lái),我們一點(diǎn)一點(diǎn)看
初始化過(guò)程先不管,我們先看主循環(huán)(dead loop

for(;;)  // Forever Loop
{
    uint8 idx = 0;
    Hal_ProcessPoll();  
//
先不管1

    do {
      if (tasksEvents[idx])  //
尋找最高優(yōu)先級(jí)的任務(wù)來(lái)運(yùn)行

      {
        break;
      }
    } while (++idx < tasksCnt);

    if (idx < tasksCnt)
    {
      uint16 events;
      halIntState_t intState;

      HAL_ENTER_CRITICAL_SECTION(intState);
      events = tasksEvents[idx];
      tasksEvents[idx] = 0;  
//
本任務(wù)運(yùn)行完了,要對(duì)其清空,為后面要運(yùn)行的任務(wù)讓路
      HAL_EXIT_CRITICAL_SECTION(intState);

      events = (tasksArr[idx])( idx, events );
//
最關(guān)鍵的一句話,如圖一中,運(yùn)行對(duì)應(yīng)的任務(wù)

      HAL_ENTER_CRITICAL_SECTION(intState);
      tasksEvents[idx] |= events;  
//
本任務(wù)可能沒(méi)完全完成,如果是這樣,再次設(shè)置標(biāo)志位,在下一次循環(huán)中繼續(xù)執(zhí)行
      HAL_EXIT_CRITICAL_SECTION(intState);
      }
    }

2節(jié)、系統(tǒng)時(shí)間

我們知道,每個(gè)操作系統(tǒng)(雖然我不認(rèn)為OSAL是一個(gè)標(biāo)準(zhǔn)的操作系統(tǒng),但我們先這么叫著吧)都有一個(gè)節(jié)拍tick,就像每一個(gè)活人都有心跳一樣。那么OSAL的心跳有多快呢?--1ms。當(dāng)然這個(gè)速度是可以設(shè)置的,在osal_timer_activate函數(shù)中開(kāi)啟了系統(tǒng)節(jié)拍,用TICK_TIME來(lái)定義其速度
#define TICK_TIME   1000   // Timer per tick - in micro-sec
注意:這個(gè)1000micro-sec(微秒),而不是millisec(毫秒)!我剛開(kāi)始的時(shí)候就是誤以為是1000ms而耽誤了不少時(shí)間。
那這個(gè)心臟是怎么跳動(dòng)起來(lái)的呢?

這得從定時(shí)器說(shuō)起,由于本文的重點(diǎn)不是講單片機(jī)基礎(chǔ)的,如果對(duì)這個(gè)名字還陌生的同學(xué),那還是回去先看看基礎(chǔ)再來(lái)看這個(gè)吧。24304個(gè)定時(shí)/計(jì)數(shù)器,其中timer4用來(lái)做系統(tǒng)計(jì)時(shí)。如果認(rèn)為是timer2的同學(xué)請(qǐng)看一下halTimerRemap這個(gè)函數(shù)。在上述osal_timer_activate函數(shù)中,開(kāi)啟了系統(tǒng)計(jì)時(shí),并將timer4的初始設(shè)為TICK_TIME1000),這樣timer4就開(kāi)始了從1000開(kāi)始的減計(jì)數(shù),減到0以后呢?寄存器TIMIF會(huì)產(chǎn)生一個(gè)溢出標(biāo)志,那么它會(huì)立即產(chǎn)生中斷并進(jìn)入中斷服務(wù)程序嗎?不會(huì)的。

我們看一下第1節(jié)主函數(shù)里的“Hal_ProcessPoll();  // 先不管1”(不管的東西早晚要管的,只是時(shí)間的問(wèn)題而已)  這個(gè)函數(shù)里調(diào)用了HalTimerTick,這個(gè)函數(shù)就是專(zhuān)門(mén)來(lái)檢查是否有硬件定時(shí)器溢出的,如果有的話會(huì)調(diào)用halTimerSendCallBack這個(gè)函數(shù),對(duì)溢出事件做處理。

回過(guò)頭來(lái)說(shuō)系統(tǒng)節(jié)拍,那timer4在計(jì)數(shù)滿1000(即1ms)后做了些什么事呢,那我們看一下halTimerSendCallBack 這個(gè)函數(shù)
void halTimerSendCallBack (uint8 timerId, uint8 channel, uint8 channelMode)
{
  uint8 hwtimerid;

  hwtimerid = halTimerRemap (timerId);

  if (halTimerRecord[hwtimerid].callBackFunc)
    (halTimerRecord[hwtimerid].callBackFunc) (timerId, channel, channelMode);
}

這里面調(diào)用了“callBackFunc”函數(shù),也就是說(shuō)每個(gè)定時(shí)器溢出后都有一個(gè)callBackFunc函數(shù),它在哪里呢,我們?cè)倏匆幌?span lang="EN-US">HalTimerConfig
這個(gè)函數(shù),它可以對(duì)每個(gè)定時(shí)器進(jìn)行定義。那什么時(shí)候定義的呢?--InitBoard,即板子上電初始化的時(shí)候就做了這個(gè)定義的。我說(shuō)什么來(lái)?先不管的東西,后要管的。。。

我們看到timer4callBackFunc函數(shù)是Onboard_TimerCallBack,最終指向osalTimerUpdate,這個(gè)函數(shù)厲害了~
從上面的分析中我們知道它是每1ms被調(diào)用一次的,這樣它就為應(yīng)用程序提供了一個(gè)ms計(jì)時(shí)器,應(yīng)用程序所用的定時(shí)往往以ms為單位足夠了,這樣的話就不用另外再占用硬件計(jì)時(shí)器了,畢竟只有4個(gè)嘛。。。同時(shí)這個(gè)函數(shù)還提供了一個(gè)系統(tǒng)時(shí)鐘-osal_systemClock,看看它能計(jì)時(shí)多久吧,它是“uint32”型的,也就是2^32ms=49.7天,怎么樣?你不會(huì)讓這個(gè)系統(tǒng)時(shí)鐘overflow吧:)


3節(jié)、系統(tǒng)的消息處理機(jī)制

結(jié)合第12節(jié)中的內(nèi)容,讓我們一起進(jìn)入到系統(tǒng)最核心的部分-消息處理中來(lái)吧(這個(gè)句型怎么這么耳熟~~~

1節(jié)中我們說(shuō)了,tasksEvents數(shù)組存放了一個(gè)任務(wù)是否該被運(yùn)行的序列,但是這個(gè)序列是如何產(chǎn)生的呢?如果了解了這個(gè)問(wèn)題,那也就知道了OSAL系統(tǒng)的運(yùn)作方式。
再插句廣告:在浩如煙海的程序中搜索最重要的東西,就像大浪淘沙,其實(shí)也是蠻享受的一件事情--by outman from zigbeetech

source insight "ctr+/"
,整個(gè)項(xiàng)目搜索,我們發(fā)現(xiàn)了一個(gè)“osal_set_event”的函數(shù)是專(zhuān)門(mén)來(lái)設(shè)置tasksEvents的,但是似乎并不能幫到我們。繼續(xù)搜!有兩個(gè)很重要的地方引起了我們的注意:osalTimerUpdateosal_msg_send這兩個(gè)函數(shù)


osalTimerUpdate
,這個(gè)稱(chēng)得上厲害的函數(shù)還記得吧?它會(huì)去設(shè)置tasksEvents?那不就是說(shuō),它可以讓任務(wù)在主循環(huán)中被運(yùn)行到?答對(duì)了,這就是它厲害的地方。。。那看看它運(yùn)行任務(wù)的條件吧?
      // When timeout, execute the task
      if ( srchTimer->timeout == 0 )
      {
        osal_set_event( srchTimer->task_id, srchTimer->event_flag );
... ...
也就是說(shuō),計(jì)時(shí)器溢出--恩。。。不多說(shuō)了,我們埋個(gè)伏筆,先介紹另一個(gè)朋友-osal_start_timerEx,先看下它的自我介紹
/*********************************************************************
* @fn      osal_start_timerEx
*
* @brief
*
*   This is called to start a timer to expire in n mSecs.
*   When the timer expires, the calling task will get the specified event.
*
* @param   byte taskID - task id to set timer for
* @param   UINT16 event_id - event to be notified with
* @param   UNINT16 timeout_value - in milliseconds.
*
* @return  ZSUCCESS, or NO_TIMER_AVAIL.
*/
byte osal_start_timerEx( byte taskID, UINT16 event_id, UINT16 timeout_value )

也就是說(shuō),它會(huì)開(kāi)始一個(gè)timeout_value(ms)的計(jì)時(shí)器,當(dāng)這個(gè)計(jì)時(shí)器溢出時(shí),則會(huì)對(duì)taskID這個(gè)task,設(shè)置一個(gè)event_id,讓這個(gè)任務(wù)在后面的主循環(huán)中運(yùn)行到,但是是怎么實(shí)現(xiàn)的呢?還是要請(qǐng)osalTimerUpdate來(lái)幫忙。。。

那位同學(xué)說(shuō)啥?復(fù)雜了,聽(tīng)不懂?
唉,還是上圖吧
OSAL系統(tǒng)框架專(zhuān)題【轉(zhuǎn)載】 - 小峰 - happy~
還是先從數(shù)據(jù)結(jié)構(gòu)說(shuō)起吧,不知道啥是數(shù)據(jù)鏈表的同學(xué),把譚老師的書(shū)拿過(guò)來(lái)再讀幾遍。。。
這個(gè)表就是osalTimerUpdate函數(shù)的任務(wù)表,上面不是說(shuō)過(guò)這個(gè)函數(shù)給應(yīng)用程序提供了軟計(jì)時(shí)了嗎?就是體現(xiàn)在這里,osal_start_timerEx通過(guò)osalAddTimer向鏈表里添加了定時(shí)任務(wù),由osalTimerUpdate來(lái)以ms為單位對(duì)這些軟定時(shí)器減計(jì)數(shù),溢出時(shí),即調(diào)用osal_set_event,實(shí)現(xiàn)主循環(huán)里對(duì)任務(wù)的調(diào)用。

好了,到此講了上面提到的"set event"函數(shù)中的一個(gè)osal_start_timerEx, 還有一個(gè)更厲害的還在外面呢,osal_msg_send,這就漸入佳境,進(jìn)入最重要的消息處理機(jī)制了。。。

-- by outman 2010-4-14 18:00  
下班啦,老婆在家等著回去一起做飯哪~~~晚上見(jiàn)~~~

為了更好地說(shuō)明這個(gè)問(wèn)題,還是拿一個(gè)具體的例子來(lái)講比較直觀。不過(guò)在這個(gè)筆記中,我盡量不涉及具體開(kāi)發(fā)板,而講一些通用的知識(shí),因?yàn)檫@樣會(huì)讓更多的人受益。在TI官方zstack 2006中有4個(gè)例子,其中一個(gè)叫GenericApp最基本的通信的例程,如果沒(méi)有安裝zstack的同學(xué)可以到本站專(zhuān)用下載貼中下載。當(dāng)然由于講的是些比較通用的東西,所以手頭有開(kāi)發(fā)板的同學(xué)可以用自己的開(kāi)發(fā)板來(lái)試驗(yàn),效果更好。。。


在這樣的通信例程中,一般會(huì)有一個(gè)按鍵觸發(fā),然后會(huì)和相鄰的模塊進(jìn)行通信,當(dāng)然由于這部分是講OSAL的系統(tǒng)框架的,我們先不涉及通信的內(nèi)容,只是看一下按鍵是如何產(chǎn)生的,及如何調(diào)用相應(yīng)的接口程序。

OSAL的模塊定義,按鍵可能在哪層來(lái)?硬件服務(wù)相關(guān)的,恩。。。是不是在HAL層呢?到Hal_ProcessEvent看看?有個(gè)HalKeyPoll函數(shù)不是?恩,這就是檢測(cè)按鍵的地方~~不過(guò),我可不是像上面這樣這么容易猜出來(lái)的,這幾句話足足用了我大半個(gè)鐘頭呢。。。過(guò)程我不細(xì)說(shuō)了,有興趣的話我可以再補(bǔ)充一下。

HalKeyPoll函數(shù)中,無(wú)論按鍵是ADC方式,或者是掃描IO口的方式,最后都會(huì)生成一個(gè)鍵值keys, 然后通過(guò)下面的語(yǔ)句來(lái)調(diào)用按鍵服務(wù)程序
  /* Invoke Callback if new keys were depressed */
  if (keys && (pHalKeyProcess))
  {
    (pHalKeyProcess) (keys, HAL_KEY_STATE_NORMAL);
  }

這里調(diào)用的服務(wù)程序,在InitBoard中被初始化為OnBoard_KeyCallback,這個(gè)函數(shù)又通過(guò)OnBoard_SendKeys運(yùn)行下面語(yǔ)句
  {
    // Send the address to the task
    msgPtr = (keyChange_t *)osal_msg_allocate( sizeof(keyChange_t) );
    if ( msgPtr )
    {
      msgPtr->hdr.event = KEY_CHANGE;
      msgPtr->state = state;
      msgPtr->keys = keys;

      osal_msg_send( registeredKeysTaskID, (uint8 *)msgPtr );
    }
    return ( ZSuccess );
  }

下面我們就看下osal_msg_send是如何向上級(jí)應(yīng)用程序發(fā)送消息的。終于要講消息量的數(shù)據(jù)結(jié)構(gòu)了,好像繞得有點(diǎn)遠(yuǎn)。。。。還是先上圖

OSAL系統(tǒng)框架專(zhuān)題【轉(zhuǎn)載】 - 小峰 - happy~
在理解了消息量的數(shù)據(jù)鏈表后,再來(lái)理解osal_msg_send里的語(yǔ)句就不難了
  OSAL_MSG_ID( msg_ptr ) = destination_task;//
設(shè)置消息數(shù)據(jù)對(duì)應(yīng)是屬于哪個(gè)任務(wù)的

  //
將要發(fā)送的消息數(shù)據(jù)鏈接到以osal_qHead開(kāi)頭的數(shù)據(jù)鏈表中
  osal_msg_enqueue( &osal_qHead, msg_ptr );

  //
通知主循環(huán)有任務(wù)等待處理
  osal_set_event( destination_task, SYS_EVENT_MSG );

這樣用戶任務(wù)GenericApp_ProcessEvent就收到一個(gè)按鍵的處理任務(wù),并通過(guò)GenericApp_HandleKeys來(lái)執(zhí)行相應(yīng)的操作。

好了,現(xiàn)在應(yīng)該對(duì)OSAL的消息處理機(jī)制有個(gè)了解了吧?我們?cè)賮?lái)復(fù)習(xí)一下這個(gè)按鍵的處理過(guò)程:任務(wù)驅(qū)動(dòng)層Hal_ProcessEvent負(fù)責(zé)對(duì)按鍵進(jìn)行持續(xù)掃描,發(fā)現(xiàn)有按鍵事件后OnBoard_KeyCallback函數(shù)向應(yīng)用層GenericApp_ProcessEvent發(fā)送一個(gè)有按鍵需要處理的消息,最終由GenericApp_HandleKeys來(lái)負(fù)責(zé)執(zhí)行具體的操作。

讓我們?cè)倩氐阶畛醯膯?wèn)題,任務(wù)處理表tasksEvents是怎么被改動(dòng)的呢?初始化程序、其他任務(wù)或者本任務(wù)主要通過(guò)下面幾種方式對(duì)其操作:
1
、設(shè)置計(jì)時(shí)器,當(dāng)其溢出時(shí),觸發(fā)事件處理
2
、直接通過(guò)任務(wù)間的消息傳遞機(jī)制觸發(fā)
3
、...(等我想到了再補(bǔ)充)

-- by outman 2010.4.15 00:18   
該睡覺(jué)啦~~~

文章來(lái)自:http://www./bbs/viewthread.php?tid=16&extra=page%3D1

              加速度 April 15,2010

 

說(shuō)明:本文轉(zhuǎn)載自http://blog.21ic.com/user1/6121/archives/2010/68309.html

      保持了原文的完整性,本人未作任何內(nèi)容上的修改!

      本文對(duì)我給予了很多幫助!感謝作者!

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買(mǎi)等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類(lèi)似文章 更多