このドキュメントでは、FreeRTOS の 2 つの機能、つまりタスクの作成と、アプリケーションの汎用機能をトリガーする方法としてのキューの使用に焦点を当てています。NXPのQN908x用SDK抽象化レイヤーは、FreeRTOSの使用と制御機能をより簡単にする方法をお客様に提供することを目的としています。
ハードウェア要件:
ソフトウェア要件:
このドキュメントは、SDK のワイヤレス UART の例に基づいています。
注: デバッグコンソールとして UART を選択してください。
2.QN9080 ボードのデフォルト ロールを変更するには、 PROJECT_FILE_NAME > ソース > wireless_uart.c > BleApp_Config() で mGapRole 変数の定義を gGapCentral_c から gGapPeripheral_c に変更する必要があります。
//wireless_uart.c
//static void BleApp_Config(void) {
/* By default, always start node as GAP central */
//mGapRole = gGapCentral_c;
mGapRole = gGapPeripheral_c;
(void)Serial_Print(gAppSerMgrIf, "\n\rWireless UART starting as GAP Peripheral, press the role switch to change it.\n\r", gAllowToBlock_d);
mAdvState.advOn = TRUE;
mScanningOn = FALSE;
//...}
3.フレームワークの osNumberOfMessageQs のマクロ値 osNumberOfMessageQs PROJECT_FILE_NAME >> OSAbstracion > Interface > fsl_os_abstraction_config.h を 0 >値に変更することが重要です。
//fsl_os_abstraction_config.h
#ifndef osNumberOfMutexes
#define osNumberOfMutexes 5
#endif
#ifndef osNumberOfMessageQs
#define osNumberOfMessageQs 1
#endif
#ifndef osNumberOfMessages
#define osNumberOfMessages 10
#endif
//...
次に、タスクの実装を開始するには、ファイルを編集する必要があります: PROJECT_FILE_NAME >フレームワーク > OSAbstracion > Source > fsl_os_abstraction_free_rtos.c.
まず、メインタスク関数のプロトタイプを作成し、次に「OSA_TASK_DEFINE」定義を使用してタスクを定義します。構文は次のとおりです。
この機能はスレッド管理の一部であり、ユーザーが新しいスレッドの作成を定義し、優先度とスタック要件を制御するのに役立ちます。関数定義では、次のパラメータが使用されます。
name: Sは、タスクとして使用される関数の名前である必要があります
priority: スケジューラは、このパラメーターを使用して、関数にマイナーまたはメジャーの優先度を付与します。
instances: このパラメーターは、メモリを最適な方法で管理するために、インスタンスの数を制限する制御を提供します。
stackSz : このパラメーターにはデフォルト値があり、抽象化レイヤーによって次のように定義されます: gMainThreadStackSize_c 1024 バイト。
useFloat : このパラメータはスレッド定義構造の一部であり、ブール値であり、スレッドが浮動小数点を使用するかどうかを定義します。
//fsl_os_abstraction_free_rtos.c
/*! *********************************************************************************
*************************************************************************************
* Private functions
*************************************************************************************
********************************************************************************** */
OSA_TASK_DEFINE(startup_task, gMainThreadPriority_c, 1, gMainThreadStackSize_c, 0) ;
void vfnTaskPWM(void* param); //New Task Definition
OSA_TASK_DEFINE(vfnTaskPWM, 1, 1, 500, FALSE );
osaTaskId_t gAppTestTask1Id = 0; // TestTask1 Id
osaTaskId_t pwmTask_queue = 0;
//get defines from wireless_uart
int main (void)
{
/* Initialize MCU clock */
hardware_init();
OSA_TaskCreate(OSA_TASK(startup_task), NULL);
//Task and Queue creation.
gAppTestTask1Id = OSA_TaskCreate(OSA_TASK(vfnTaskPWM), NULL); //Task Creation
pwmTask_queue = OSA_MsgQCreate(1);
//Scheduler starting
vTaskStartScheduler();
return 0;
}
//..
4. 関数: OSA_TaskCreate は、次のように osaTaskId_t 変数を作成するために必要な taskID を返します: osaTaskId_t gAppTestTask1Id = 0; また、使用する FreeRTOS キューの別の osaTaskId_t 変数も返します。
osaTaskId_t pwmTask_queue = 0.
5. main関数内で、startup_taskが作成されるのと同じ方法でタスクを作成します。
gAppTestTask1Id = OSA_TaskCreate(OSA_TASK(vfnTaskPWM), NULL);
6.また、同じタイプの変数を使用し、OSA_MsgQCreate() 関数を使用して新しいキューを作成するためにキューを作成する必要があります。
pwmTask_queue = OSA_MsgQCreate(1);
7. このステートメントの後、スケジューラーは開始する必要があります: vTaskStartScheduler();
8. wireless_uart.cでキュー用に extern 変数として作成された FILE pwmTask_queueを追加する必要があります。
//wireless_uart.c
static uint8_t gAppSerMgrIf;
static uint16_t mAppUartBufferSize = mAppUartBufferSize_c;
static volatile bool_t mAppUartNewLine = FALSE;
static volatile bool_t mAppDapaPending = FALSE;
extern osaMsgQId_t pwmTask_queue;
/************************************************************************************
*************************************************************************************
* Private functions prototypes
*************************************************************************************
************************************************************************************/
/* Gatt and Att callbacks */
static void BleApp_AdvertisingCallback(gapAdvertisingEvent_t *pAdvertisingEvent);
この例では、 OSA_MsgQPut() を使用して、中央の周辺機器から受信したメッセージをキューに配置するように実装しました。
//wireles_uart.c
static void BleApp_ReceivedUartStream(deviceId_t peerDeviceId, uint8_t *pStream, uint16_t streamLength)
{
static deviceId_t previousDeviceId = gInvalidDeviceId_c;
char additionalInfoBuff[10] = { '\r', '\n', '[', '0', '0', '-', 'M', ']', ':', ' '};
uint8_t *pBuffer = NULL;
uint32_t messageHeaderSize = 0;
if (mAppUartNewLine || (previousDeviceId != peerDeviceId))
{
streamLength += (uint32_t)sizeof(additionalInfoBuff);
}
/* Allocate buffer for asynchronous write */
pBuffer = MEM_BufferAlloc(streamLength);
if (pBuffer != NULL)
{
/* if this is a message from a previous device, print device ID */
if (mAppUartNewLine || (previousDeviceId != peerDeviceId))
{
messageHeaderSize = sizeof(additionalInfoBuff);
if (mAppUartNewLine)
{
mAppUartNewLine = FALSE;
}
additionalInfoBuff[3] = '0' + (peerDeviceId / 10U);
additionalInfoBuff[4] = '0' + (peerDeviceId % 10U);
if (gGapCentral_c != maPeerInformation[peerDeviceId].gapRole)
{
additionalInfoBuff[6] = 'S';
}
FLib_MemCpy(pBuffer, additionalInfoBuff, sizeof(additionalInfoBuff));
}
FLib_MemCpy(pBuffer + messageHeaderSize, pStream, (uint32_t)streamLength - messageHeaderSize);
/**** Adding a message into a Queue ****/
OSA_MsgQPut(pwmTask_queue, (void*)&pBuffer);
/**************************************/
(void)Serial_AsyncWrite(gAppSerMgrIf, pBuffer, streamLength, Uart_TxCallBack, pBuffer);
}
/* update the previous device ID */
previousDeviceId = peerDeviceId;
}
この関数は、プロジェクトの main() 関数の前に作成された外部キュー変数を指します。また、 BleApp_ReceivedUartStream()で受信したメッセージのバッファポインタを指し、これらのパラメータはOSA_MsgQGet() 関数を使用してアクセスできます。
osaStatus_t OSA_MsgQGet(osaMsgQId_t msgQId, void *pMessage, uint32_t millisec)
この関数は、メッセージキューの先頭からメッセージを取得し、この関数のパラメータは次のとおりです。
msgQId : キュー関数の識別子です。
pMessage : OSA_MsgQPut() から送信された同じメッセージへのポインタです。
millisec : メッセージを待つミリ秒数です。
作成されたタスクの内部: vfnTaskPWM() には、メッセージがキューにあるかどうかを確認する無限の while ループがあり、これは os_abstraction 関数を使用して実現されます。
タスクの実装の残りの部分は、別の C ファイルにあります。外部キュー変数は、タスク関数プロトタイプに加えて、このファイルで定義されています。
/*pwmApplication.c*/
/*Global Variables*/
static uint8_t gAppSerMgrIf;
extern osaMsgQId_t pwmTask_queue;
/*Function Prototypes*/
void signalConfigValues(int red, int green, int blue);
void getValuesRGB(uint8_t* msgString);
int getInt(char *stringInteger, int size);
/****Task Definition****/
void vfnTaskPWM(void* param);
/*
* Task to configure the PWM pins and start the timer
* */
void vfnTaskPWM(void* param)
{
uint8_t* msgString;
char msgString1[20] = { '\0', '\0', '\0', '\0','\0', '\0', '\0', '\0','\0', '\0', '\0', '\0','\0', '\0', '\0', '\0','\0', '\0', '\0', '\0'};
while(1)
{
/*
* If there is a new message on queue the value will return a 0 according to the OSA_MsgQGet function
* to compare the incoming message
* */
while((OSA_MsgQGet(pwmTask_queue,(void*)&msgString,10)) == 0){
//shift-up the pointer value to get the payload message
if(*msgString == '\r'){
while(*msgString != 32){
msgString++;
}
msgString++;
}
FLib_MemCpy(msgString1,msgString,20);
if(FLib_MemCmp(msgString1, "OFF", 4)){
(void)Serial_Print(gAppSerMgrIf,"\n\r OFF: ", gAllowToBlock_d);
//configure the PWM new function signalConfigValues(0,0,0) and StartTimers(CTMRA,CTMRB)
signalConfigValues(0,0,0);
}
else{
//a function to convert values from a string to integers
getValuesRGB(msgString);
}
}
}
}