Try   HackMD

2021單晶片課程:RTOS(下)


Mutex

Mutex 是一種可以將執行緒進行同步處理的方式,使用 lock 和 unlock 的方式來共享資源使用。

Mutex的方法無法被 ISR (interrupt service routines)所使用。

以下為 Mutex 的示意圖 :

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

以下為 Mutex 的範例程式 :

#include "mbed.h" #include "rtos.h" Mutex stdio_mutex; void notify(const char* name, int state) { stdio_mutex.lock(); printf("%s: %d\n\r", name, state); stdio_mutex.unlock(); } void test_thread(void const *args) { while (true) { notify((const char*)args, 0); Thread::wait(1000); notify((const char*)args, 1); Thread::wait(1000); } } int main() { Thread t2; Thread t3; t2.start(callback(test_thread, (void *)"Th 2")); t3.start(callback(test_thread, (void *)"Th 3")); test_thread((void *)"Th 1"); }

利用 lock() 來使 stdio 正常運作,並用 unlock()釋放資源。

在 ARM C 標準函式庫內已經存在 Mutex 。主要是可以讓 stdio 進行正常運作,因此以上的範例在實作時並不是必須,除非有些沒有以上保護機制的開發板才需要以上程式碼,如 ARM M0 系列。

正是因為 ARM C 標準函式庫在使用 stdio 時會使用到 Mutex,所以在 ISR 中變無法使用 printf, putc, getc, malloc 和 new 。

Thread class 中的 wait() function 中間是以毫秒為單位,使用 Thread::wait(1000) 是該 funciotn 下 全部 thread 暫停一秒, t1.wait(500) 是 t1 該物件暫停 0.5 秒。

相關語法請參考 : Mutex


Semaphore

Semaphore 可以用來管理多種特定線程使用共享資源 (a pool of shared resources) 的情況。

以下為 Semaphore 的示意圖 :

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

以下為 Semaphore 的範例程式 :

#include "mbed.h" #include "rtos.h" Semaphore two_slots(2); //宣告兩執行緒的Semaphore void test_thread(void const *name) { while (true) { two_slots.wait(); printf("%s\n\r", (const char*)name); Thread::wait(1000); two_slots.release(); } } int main (void) { Thread t2; Thread t3; t2.start(callback(test_thread, (void *)"Th 2")); t3.start(callback(test_thread, (void *)"Th 3")); test_thread((void *)"Th 1"); }

可管理同時要釋放多少資源來處理執行緒。

相關語法請參考 : Semaphore


Queue

在資料結構中我們學過 Queue,即是 FIFO (Frist In Frist Out) 的結構,在實作執行緒排程時就會使用到此種結構方式。

以下為 Queue 的示意圖 :

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

常用指令 :

Queue () //Create and initialise a message Queue . Queue< T, queue_sz > osStatus put (T *data, uint32_t millisec=0) //Put a message in a Queue ; T : templete osEvent get (uint32_t millisec=osWaitForever)//Get a message or Wait for a message from a Queue .

相關語法請參考 : Queue


MemoryPool

MemoryPool 是用來定意並管理記憶體空間的程式。混合 Queue 的函式我們可以得到以下範例程式 :

#include "mbed.h" #include "rtos.h" typedef struct { float voltage; /* AD result of measured voltage */ float current; /* AD result of measured current */ uint32_t counter; /* A counter value */ } message_t; MemoryPool<message_t, 16> mpool; Queue<message_t, 16> queue; /* Send Thread */ void send_thread (void) { uint32_t i = 0; while (true) { i++; // fake data update message_t *message = mpool.alloc(); message->voltage = (i * 0.1) * 33; message->current = (i * 0.1) * 11; message->counter = i; queue.put(message); Thread::wait(1000); } } int main (void) { Thread thread; thread.start(callback(send_thread)); while (true) { osEvent evt = queue.get(); if (evt.status == osEventMessage) { message_t *message = (message_t*)evt.value.p; printf("\nVoltage: %.2f V\n\r" , message->voltage); printf("Current: %.2f A\n\r" , message->current); printf("Number of cycles: %u\n\r", message->counter); mpool.free(message); } } }

常用指令 :

MemoryPool< T, pool_sz > //Create and Initialize a memory pool. MemoryPool () T* alloc (void) //Allocate a memory block of type T from a memory pool. T* calloc (void) //Allocate a memory block of type T from a memory pool and set memory block to zero. osStatus free (T *block) //Return an allocated memory block back to a specific memory pool.

相關語法請參考 : MemoryPool


Mail

Mail的功能即是將上述的 QueueMemory pool 功能整合起來。

以下為 Mail 的示意圖 :

以下為 Mail 的範例程式 :

#include "mbed.h" #include "rtos.h" /* Mail */ typedef struct { float voltage; /* AD result of measured voltage */ float current; /* AD result of measured current */ uint32_t counter; /* A counter value */ } mail_t; Mail<mail_t, 16> mail_box; void send_thread (void) { uint32_t i = 0; while (true) { i++; // fake data update mail_t *mail = mail_box.alloc(); mail->voltage = (i * 0.1) * 33; mail->current = (i * 0.1) * 11; mail->counter = i; mail_box.put(mail); Thread::wait(1000); } } int main (void) { Thread thread; thread.start(callback(send_thread)); while (true) { osEvent evt = mail_box.get(); if (evt.status == osEventMail) { mail_t *mail = (mail_t*)evt.value.p; printf("\nVoltage: %.2f V\n\r" , mail->voltage); printf("Current: %.2f A\n\r" , mail->current); printf("Number of cycles: %u\n\r", mail->counter); mail_box.free(mail); } } }

常用指令 :

Mail< T, queue_sz > //Create and Initialise Mail queue. Mail () T *alloc (uint32_t millisec=0) //Allocate a memory block of type T. T *calloc (uint32_t millisec=0) //Allocate a memory block of type T and set memory block to zero. osStatus put (T *mptr) //Put a mail in the queue. osEvent get (uint32_t millisec=osWaitForever) //Get a mail from a queue. osStatus free (T *mptr) //Free a memory block from a mai

相關語法請參考 : Mail


Status and Error Codes

The Status and Error Codes section lists all the return values that the CMSIS-RTOS functions will return:

CMSIS-RTOS 是 ARM 公司為統一操作系統、降低嵌入式門檻而發佈的操作系統標準軟件接口。通俗講,CMSIS-RTOS 將操作系統(不管是 FREE-RTOS 還是 RTX 等)屏蔽起來,然後提供 CMSIS-RTOS 接口函數給最終用户調用。

  • osOK : function completed ; no event occurred.
  • osEventSignal : function completed; signal event occurred.
  • osEventMessage : function completed; message event occurred.
  • osEventMail : function completed; mail event occurred.
  • osEventTimeout : function completed; timeout occurred.
  • osErrorParameter : parameter error: a mandatory parameter was missing or specified an incorrect object.
  • osErrorResource : resource not available: a specified resource was not available.
  • osErrorTimeoutResource : resource not available within given time : a specified resource was not available within the timeout period.
  • osErrorISR : not allowed in ISR context: the function cannot be called from interrupt service routines.
  • osErrorISRRecursive : function called multiple times from ISR with same object.
  • osErrorPriority : system cannot determine priority or thread has illegal priority.
  • osErrorNoMemory : system is out of memory: it was impossible to allocate or reserve memory for the operation.
  • osErrorValue : value of a parameter is out of range.
  • osErrorOS : unspecified RTOS error: run-time error but no other error message fits.

※ 使用thread.terminate();使thread停止


Lab 1

請利用上述 RTOS 中的 Thread & Semaphore & Mutex來完成以下功能:

  1. 每隔1秒亮一顆開發板上之LED,總共3顆輪流。
  2. 當開發板上 Button 按下後,改變為 Semaphore的狀態,Semaphore 觸發內容為每隔1秒亮兩顆開發版上之LED。
  3. 再按一次開發板上的 Button 後,改變為 Mutex的狀態,每隔1秒閃爍開發版上所有LED。
  4. 最後再按一次Button回歸每隔1秒亮一顆LED的狀態。

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →


Lab 2

請利用上述 RTOS 中的 Mail 實現可繼續計時的碼表。 ※使用Thread::wait()計時

  1. 輸入"s" : 開始計時(最小單位為1/100秒)。
  2. 輸入"p" : 顯示計時的秒數。
  3. 輸入" r ":將計時至今的秒數清空
    Image Not Showing Possible Reasons
    • The image file may be corrupted
    • The server hosting the image is unavailable
    • The image path is incorrect
    • The image format is not supported
    Learn More →

課後問題

  • Q1.請詳述 Thread 在 Mbed 平台中是如何運作的。
  • Q2.請嘗試解釋 Mbed 平台 API 中, wait() 與 Thread::wait() 之間的差別。