iT邦幫忙

第 11 屆 iThome 鐵人賽

DAY 17
1
IoT

玩玩 BLE系列 第 17

[Day 17] TI-RTOS 執行緒(Thread)

執行緒/線程(Thread)

在作業系統的定義中,Thread 是能夠進行排成的最小單位。
每條執行緒負責不同的任務,且他們有各自的優先級,
優先級高的執行緒必須先被執行。

在TI-RTOS中,可分成四種執行緒,依照優先等級最高到低分別是

  • 硬體中斷
  • 軟體中斷
  • Tasks
  • Idle Task

硬體中斷(Hwi, Hardware Interrupt)

硬體中斷又稱ISR(Interrupt Service Routine),
不只TI-RTOS,在所有的系統中這應該都是擁有最高優先級的執行緒。
這是由最底層所觸發的事件,用來處理非常緊迫的任務,所以執行時間被嚴格的限制,
在SimplePeripheral 範例中,按鈕偵測就使用到硬體中斷,這個函式的位址在初始化的時候被註冊

void Board_initKeys(keysPressedCB_t appKeyCB)
{
  ...
  // 將函式的位址設定給底層的驅動,
  // 當中斷發生(按鈕被按下或放開)時,
  // 底層會自己呼叫這個函式。
  PIN_registerIntCb(hKeyPins, Board_keyCallback);
  ...
}
// 當中斷發生(按鈕被按下或放開)時,
// 底層自己會在硬體中斷的執行緒來執行這段程式碼
// 這邊只做簡單的讀寫暫存器和變數
static void Board_keyCallback(PIN_Handle hPin, PIN_Id pinId)
{
  keysPressed = 0;
  if ( PIN_getInputValue(Board_PIN_BUTTON0) == 0 )
  {
    keysPressed |= KEY_LEFT;
  }
  if ( PIN_getInputValue(Board_PIN_BUTTON1) == 0 )
  {
    keysPressed |= KEY_RIGHT;
  }
  // 這個啟動定時器的動作,是為了做按鈕的除抖動(Debouncing)
  Util_startClock(&keyChangeClock);
}

軟體中斷(Swi, Software Interrupt)

軟體中斷對於執行時間的要求比硬體中斷稍微寬鬆一些,
但也不是完全不管,執行時間一樣要盡量地短,且不能使用 blocking API。
在這類的執行緒中,建議使用TI-RTOS 提供的 API (XXX_post())
在SimplePeripheral 範例中,
被設定好的定時器時間到,就會產生軟體中斷

static void SimplePeripheral_init(void)
{
  ...
  // 在Simple Peripheral 任務初始化的階段,
  // 我們有建立一個定時器,
  // 並指定時間到的時候要呼叫的程式碼 SimplePeripheral_clockHandler
  Util_constructClock(&clkPeriodic, SimplePeripheral_clockHandler,
                      SP_PERIODIC_EVT_PERIOD, 0, false, (UArg)&argPeriodic);
  ...
}
// 定時器時間到的時候,
// 會在軟體中斷的執行緒來執行這段程式碼
static void SimplePeripheral_clockHandler(UArg arg)
{
  spClockEventData_t *pData = (spClockEventData_t *)arg;
  if (pData->event == SP_PERIODIC_EVT)
  {
    ...
    // 這邊還沒看到官方建議的XXX_post(),繼續往下追
    SimplePeripheral_enqueueMsg(SP_PERIODIC_EVT, NULL);
  }
  ...
}
// 最後追到這
uint8_t Util_enqueueMsg(Queue_Handle msgQueue,
                        Event_Handle event,
                        uint8_t *pMsg)
{
  ...
  // 在這裡也還沒處理要做的事情,
  // 而是透過Event_post(),把定時器到期的這個事件發布出來
  Event_post(event, UTIL_QUEUE_EVENT_ID);
  ...
}
// 接著我們來看SimplePeripheral 任務
static void SimplePeripheral_taskFxn(UArg a0, UArg a1)
{
  // Initialize application
  SimplePeripheral_init();

  // Application main loop
  for (;;)
  {
    ...
    // 這裡是比軟體中斷優先級低一點的Task級別
    // 在這邊會一直等待Event,
    // 剛在軟體中斷所發出的Event_post 就會在這邊被接收到,
    // 然後真正要做的事情,就會在Task 級別的執行緒中來執行
    events = Event_pend(syncEvent, Event_Id_NONE, SP_ALL_EVENTS,
                        ICALL_TIMEOUT_FOREVER);
  }
}

Task

這裡的優先級比軟體中斷低,
另外跟軟體中斷最大的不同在於Task 允許等待,
就像剛剛舉的例子,Task 可以卡在Event_pend(),
直到有其他執行緒呼叫Event_post(),
再繼續往下跑就好。
另外,我們可以建立多個Task,
每個Task 都是獨立的Thread,
Task 之間可以使用 TI-RTOS 提供的機制來進行通訊,(例如:Semaphore、Event、Queue、Mailbox)。

Idle Task

當中斷和Task 都沒事做的時候,系統就會來到Idle Task,
以CC26X2來說,就會被允許進入省電模式。


上一篇
[Day 16] BLE 封包監聽工具(Packet Sniffer)
下一篇
[Day 18] TI-RTOS 任務(Task)
系列文
玩玩 BLE27
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言