FreeRTOS-同期と通信

5999 ワード

以前の記事ではFreeRTOSシステムにおける信号量とキューについて述べたが、信号量は、リソース管理とスレッド(割り込み)の同期に使用され、キューはデータバッファの作成に使用されます.実際の応用では、一般的に複数のスレッドがあり、スレッド間にも同期と通信の問題があり、信号量とイベントグループを使用して同期の問題を解決し、キューとその派生品を使用して通信の問題を解決することができます.
スレッド間の同期には、2値信号量とカウント信号量を用いることができる.二値信号量とカウント信号量の関数プロトタイプを作成するには、次のようにします.
#include “FreeRTOS.h”
#include “semphr.h”
SemaphoreHandle_t xSemaphoreCreateBinary( void );
#include “FreeRTOS.h”
#include “semphr.h”
SemaphoreHandle_t xSemaphoreCreateCounting( UBaseType_t uxMaxCount,
UBaseType_t uxInitialCount );

信号量の取得使用関数:
#include “FreeRTOS.h”
#include “semphr.h”
BaseType_t xSemaphoreTake( SemaphoreHandle_t xSemaphore, TickType_t xTicksToWait );

信号量の解放使用関数:
#include “FreeRTOS.h”
#include “semphr.h”
BaseType_t xSemaphoreGive( SemaphoreHandle_t xSemaphore );

信号量の取得と解放関数にはFromISRバージョンがあり、configmaX_より優先度が低いことに注意してください.SYSCALL_INTERRUPT_PRIORITYの割り込みでは、FromISRバージョンのAPI関数が使用されます.
参照FreeRTOS Reference manural:
Binary Semaphores – A binary semaphore used for synchronization does not need to be ‘given’ back after it has been successfully ‘taken’ (obtained). Task synchronization is implemented by having one task or interrupt ‘give’ the semaphore, and another task ‘take’ the semaphore (see the xSemaphoreGiveFromISR() documentation). Note the same functionality can often be achieved in a more efficient way using a direct to task notification.
Counting Semaphores – Counting semaphores are typically used for two things:
1. Counting events. In this usage scenario, an event handler will ‘give’ the semaphore each time an event occurs, and a handler task will ‘take’ the semaphore each time it processes an event. The semaphore’s count value will be incremented each time it is ‘given’ and decremented each time it is ‘taken’. The count value is therefore the difference between the number of events that have occurred and the number of events that have been processed. Semaphores created to count events should be created with an initial count value of zero, because no events will have been counted prior to the semaphore being created.
2. Resource management. In this usage scenario, the count value of the semaphore represents the number of resources that are available. To obtain control of a resource, a task must first successfully ‘take’ the semaphore. The action of ‘taking’ the semaphore will decrement the semaphore’s count value. When the count value reaches zero, no more resources are available, and further attempts to ‘take’ the semaphore will fail. When a task finishes with a resource, it must ‘give’ the semaphore. The action of ‘giving’ the semaphore will increment the semaphore’s count value, indicating that a resource is available, and allowing future attempts to ‘take’ the semaphore to be successful. Semaphores created to manage resources should be created with an initial count value equal to the number of resource that are available.
イベントグループ(Event Group)は、タスク(割り込み)間の同期に使用できるFreeRTOSによって提供されるイベント管理メカニズムです.(イベント)状態レジスタの原理と同様に、あるイベントグループのうちの1人がそのビットに対応するイベントが発生したことを示すセット操作を行い、同時にそのイベントを待つタスクをBlocked状態からReady状態に遷移させることができる.イベントグループの作成関数は以下のように定義される.
#include “FreeRTOS.h”
#include “event_groups.h”
EventGroupHandle_t xEventGroupCreate( void );

入力パラメータなしで直接イベントグループが作成されましたconfigUSE_16_BIT_TICKSの値が0の場合、作成されたイベントグループは、合計24ビット、すなわち24イベントを表すことができる.各ビットの値は、対応するAPI関数によって設定および消去することができる.詳細はFreeRTOS Reference manuralを参照してください.
スレッド間の通信はキューで実現することができるが、キューだけでは容易ではない場合がある.例えば、シリアルポートを用いてデータ伝送を行う場合、1バイトのデータを受信するとキューに1バイトのデータを書き込みたいと考え、1024バイトのデータを連続的に受信すると、キューを1024回書き、効率が低い.関数を1回呼び出すだけで1024バイトのデータを書き込むことができれば、効率が高くなります.
このときFreeRTOSは、Stream BufferとMessage Buffer、Stream BufferはQueue、Message BufferはStream Bufferという2つのキューベース実装メカニズムを提供し、Message BufferはStream Bufferベース実装であるため、両方の「親」はキューである.
Stream Bufferは、実際には複数のデータを同時に書き込むことができるキューであり、作成当初はStream Bufferの格納可能な最大データ長を設定する必要があります.残りの操作はQueueとよく似ています.
Message Bufferは、Stream Bufferに基づいて1層カプセル化されており、Message Bufferにデータを書き込むたびに1つのMessageに従って書き込まれている.1つのMessageは固定長を持つデータフレームであり、Message Bufferからデータを読み出す際もMessageを基本単位としているが、Messageごとに長さが異なる場合があるため、したがって、実際にMessage Bufferのバッファに書き込むと、有効データの前に長さ情報が追加され、そのMessageが実際に持っているデータの長さを表します.Message Bufferを読み込むと、API関数はまず長さ情報を読み出し、それから長さ情報に基づいて対応する有効データを読み出します.
参照FreeRTOS Reference manural:
Notes
Uniquely among FreeRTOS objects, the stream buffer implementation (so also the message buffer implementation, as message buffers are built on top of stream buffers) assumes there is only one task or interrupt that will write to the buffer (the writer), and only one task or interrupt that will read from the buffer (the reader). It is safe for the writer and reader to be different tasks or interrupts, but, unlike other FreeRTOS objects, it is not safe to have multiple different writers or multiple different readers. If there are to be multiple different writers then the application  writer  must  place  each  call  to  a  writing  API  function  (such  as xMessageBufferSend()) inside a critical section and must use a send block time of 0. Likewise, if there are to be multiple different readers then the application writer must place each call to a reading API function (such as xMessageBufferRead()) inside a critical section and must use a receive block time of 0. Use xMessageBufferReceive() to read from a message buffer from a task. Use xMessageBufferReceiveFromISR() to read from a message buffer from an interrupt service routine (ISR). Message buffer functionality is enabled by including the FreeRTOS/source/stream_buffer.c source file in the build (as message buffers use stream buffers).
上記のコアを抽出すると、Stream BufferとMessage Bufferを使用する場合は、同じStream BufferまたはMessage Bufferにデータを書き込むタスクが1つしかないことに注意し、複数のWriterとReaderを必要としない場合は、Stream BufferまたはMessage Bufferからデータを読み出すタスクが1つしかないことに注意してください.読み取りまたは書き込み関数を臨界領域に配置し、block timeを0に設定する必要があります.