이 문서는 Richard Barry가 만든 오픈소스 실시간 내장형 운영체제인 FreeRTOS의 API를 각각에 대해 상세하게 설명합니다.
Contents[hide] |
Task Creation
xTaskHandle
태스크를 참조하는데 사용되는 자료형이다. 예를 들어 xTaskCreate() 를 호출하면 포인터 형태로 xTaskHandle 을 반환하는데 이것을 사용하여 나중에 vTaskDelete() 에서 이 태스크를 삭제할 수 있다.
xTaskCreate
portBASE_TYPE xTaskCreate( | pdTASK_CODE pvTaskCode, |
const portCHAR * const pcName, | |
unsigned portSHORT usStackDepth, | |
void *pvParameters, | |
unsigned portBASE_TYPE uxPriority, | |
xTaskHandle *pvCreatedTask | |
); |
새로운 태스크를 생성하고 실행 준비된 태스크들의 목록에 추가시킨다.
- 전달 인자
pvTaskCode | 태스크 진입 함수에 대한 포인터이다. 태스크는 반드시 반환이 되지 않게 설계되어야 한다.(예를 들면 무한루프) |
pcName | 태스크의 이름을 정의한다. 이것은 주로 디버깅을 위해 사용될 수 있다. 최대 길이는 tskMAX_TASK_NAME_LEN 이며 기본값은 16 이다. |
usStackDepth | 태스크 스택의 크기는 스택이 수용할 수 있는 변수들의 수로써 명시된다. 이것은 바이트단위가 아니다. 예를 들어 스택이 16 비트의 자료를 수용하고 usStackDepth 가 100바이트로 정의된다면 200바이트가 스택을 저장하기 위한 공간으로 할당될 것이다. 스택의 깊이와 스택의 너비를 곱한 값이 type size_t 변수에 저장될 수 있는 최대값을 초과하면 안된다. |
pvParameters | 생성된 태스크를 위한 매개변수로 사용될 포인터. |
uxPriority | 태스크의 우선순위 |
pvCreatedTask | 생성된 태스크를 참조할 수 있는 핸들을 다시 되돌려주는데 사용 |
- 반환값
- 태스크가 성공적으로 생성되어 준비 리스트에 추가된 경우에는 pdPASS를 반환하고 그렇지 않으면 projdefs.h 파일에 정의된 에러코드를 반환한다.
- 사용 예
// Task to be created. void vTaskCode( void * pvParameters ) { for( ;; ) { // Task code goes here. } } // Function that creates a task. void vOtherFunction( void ) { unsigned char ucParameterToPass; xTaskHandle xHandle; // Create the task, storing the handle. xTaskCreate( vTaskCode, "NAME", STACK_SIZE, &ucParameterToPass, tskIDLE_PRIORITY, &xHandle ); // Use the handle to delete the task. vTaskDelete( xHandle ); }
xTaskDelete
void | vTaskDelete( | xTaskHandle pxTask |
); |
RTOS 실시간 커널 관리자에서 태스크를 제거한다. 삭제되는 태스크는 모든 준비, 대기, 중지, 이벤트 리스트에서 그 이름이 제거된다.
- 설정 상수
INCLUDE_vTaskDelete = 1
- 전달 인자
pxTask | 삭제될 태스크의 핸들이다. NULL 을 넘겨주면 이 함수를 호출한 태스크 자신이 제거된다. |
- 주의사항
idle 태스크는 삭제된 태스크에게 할당되어 있던 메모리를 해제시킨다. 그래서 응용프로그램에서 vTaskDelete() 를 호출할 때는 idle 태스크가 CPU 처리 시간을 충분히 가지지 못하는 이른바 기아(starvation) 상태에 빠지지 않도록 주의해야한다. 태스크에 할당된 메모리는 자동으로 해제되지 않는다. 그리고 태스크가 제거되기 전에 반드시 할당된 메모리의 해제가 이루어져야한다.
- 사용 예
void vOtherFunction( void ) { xTaskHandle xHandle; // Create the task, storing the handle. xTaskCreate( vTaskCode, "NAME", STACK_SIZE, NULL, tskIDLE_PRIORITY, &xHandle ); // Use the handle to delete the task. vTaskDelete( xHandle ); }
Task Control
vTaskDelay
void | vTaskDelay( | portTickType xTicksToDelay |
); |
주어진 숫자만큼의 틱 동안 태스크를 지연시킨다. 실제 지연 시간은 tick rate 와 관계가 있다. 상수 portTICK_RATE_MS 는 tick rate 를 이용하여 하나의 틱 주기를 분석해서 실제 시간을 계산하는데 사용된다.
- 설정 상수
INCLUDE_vTaskDelay = 1
- 전달 인자
xTicksToDelay | 틱 주기 단위의 시간량. 이 길이 만큼 호출한 태스크는 대기 상태가된다. |
- 사용 예
// Perform an action every 10 ticks. // NOTE: // This is for demonstration only and would be better achieved // using vTaskDelayUntil(). void vTaskFunction( void * pvParameters ) { portTickType xDelay, xNextTime; // Calc the time at which we want to perform the action // next. xNextTime = xTaskGetTickCount () + ( portTickType ) 10; for( ;; ) { xDelay = xNextTime - xTaskGetTickCount (); xNextTime += ( portTickType ) 10; // Guard against overflow if( xDelay <= ( portTickType ) 10 ) { vTaskDelay( xDelay ); } // Perform action here. } }
vTaskDelayUntil
void | vTaskDelayUntil( | portTickType *pxPreviousWakeTime, |
portTickType xTimeIncrement | ||
); |
태스크를 특정 시간 까지 지연시킨다. 이 함수는 반복되는 태스크에 대해 일정한 실행 주기를 보장해 주기 위해 사용된다.
이 함수는 vTaskDelay() 와 다른 중요한 점이 있다. vTaskDelay() 는 태스크가 vTaskDelay() 를 호출했을 때부터 지정된 틱만큼의 기간동안 태스크를 지연시킨다. 그래서 태스크가 실행을 시작하고 나서 태스크가 vTaskDelay() 를 호출한 시점 사이는 그 실행 시간을 예측할 수 없으므로 (태스크가 실행되는 동안 함수를 호출하거나 인터럽트를 받거나 다른 태스크에 의해 선점되는 과정에서 여러 가지 다른 경로를 거칠지도 모른다.) vTaskDelay() 를 사용하여 고정된 실행 주기를 만들기는 어렵다. vTaskDelay() 는 태스크가 깨어나는 시각을 자신이 호출된 시점을 기준으로 한 상대적인 시간으로 명시한다. 그에 반해 vTaskDelayUntil() 은 태스크가 대기 상태에서 벗어나기를 원하는 절대적인(정확한) 시점을 명시한다. 상수 configTICK_RATE_MS 를 사용해서 tick rate 로부터 실제 시간을 계산할 수 있다.
- 설정 상수
INCLUDE_vTaskDelayUntil = 1
- 전달 인자
pxPreviousWakeTime | 태스크가 마지막으로 깨어난 시점을 기록하는 포인터이다. 이 변수는 처음 사용에 앞서 초기화 되어야 한다.(아래예제 참고) 그다음에 이 변수는 자동적으로 vTaskDelayUntil() 함수 내부에서 갱신된다. |
xTimeIncrement | 반복 주기이다. 태스크는 (*pxPreviousWakeTime + xTimeIncrement) 을 통해 계산된 시각에 깨어난다. vTaskDelayUntil 을 같은 xTimeIncrement 값을 가지게 하여 함께 부르면 태스크가 고정된 간격의 주기에서 실행되게 할 수 있다. |
- 사용 예
// Perform an action every 10 ticks. void vTaskFunction( void * pvParameters ) { portTickType xLastWakeTime; const portTickType xFrequency = 10; // Initialise the xLastWakeTime variable with the current time. xLastWakeTime = xTaskGetTickCount(); for( ;; ) { // Wait for the next cycle. vTaskDelayUntil( &xLastWakeTime, xFrequency ); // Perform action here. } }
uxTaskPriorityGet
unsigned portBASE_TYPE | uxTaskPriorityGet( | xTaskHandle pxTask |
); |
태스크의 우선순위를 얻는데 사용된다.
- 설정 상수
INCLUDE_vTaskPriorityGet = 1
- 전달 인자
pxTask | 알아볼 태스크의 핸들. NULL 을 전달하면 호출한 태스크의 우선순위를 반환한다. |
- 반환값
지정한 태스크의 우선순위
- 사용 예
void vAFunction( void ) { xTaskHandle xHandle; // Create a task, storing the handle. xTaskCreate( vTaskCode, "NAME", STACK_SIZE, NULL, tskIDLE_PRIORITY, &xHandle ); // ... // Use the handle to obtain the priority of the created task. // It was created with tskIDLE_PRIORITY, but may have changed // it itself. if( uxTaskPriorityGet( xHandle ) != tskIDLE_PRIORITY ) { // The task has changed it's priority. } // ... // Is our priority higher than the created task? if( uxTaskPriorityGet( xHandle ) < uxTaskPriorityGet( NULL ) ) { // Our priority (obtained using NULL handle) is higher. } }
vTaskPrioritySet
void | vTaskPrioritySet( | xTaskHandle pxTask, |
unsigned portBASE_TYPE uxNewPriority | ||
); |
태스크의 우선순위를 지정하는 API. 현재 실행되고 있는 태스크의 우선순위 보다 더 높은 우선순위를 지정하면 함수가 반환되기 전에 문맥 전환이 일어난다.
- 설정 상수
INCLUDE_vTaskPrioritySet = 1
- 전달 인자
pxTask | 우선순위가 수정될 태스크의 핸들. NULL 을 넘겨주면 현재 태스크의 우선순위가 변경된다. |
uxNewPriority | 태스크가 새롭게 가질 우선순위. |
- 사용 예
void vAFunction( void ) { xTaskHandle xHandle; // Create a task, storing the handle. xTaskCreate( vTaskCode, "NAME", STACK_SIZE, NULL, tskIDLE_PRIORITY, &xHandle ); // ... // Use the handle to raise the priority of the created task. vTaskPrioritySet( xHandle, tskIDLE_PRIORITY + 1 ); // ... // Use a NULL handle to raise our priority to the same value. vTaskPrioritySet( NULL, tskIDLE_PRIORITY + 1 ); }
vTaskSuspend
void | vTaskSuspend( | xTaskHandle pxTaskToSuspend |
); |
태스크를 중지(Suspend)시키는 API. 중지된 태스크는 우선순위에 관계없이 CPU 처리 시간을 할당받지 못한다. vTaskSuspend 를 호출하는 행동은 누적되지 않는다. 다시말해서 vTaskSuspend 를 같은 태스크에 대해 두 번 호출하더라도 중지된 태스크를 다시 준비 상태로 돌리기 위해서는 vTaskResume() 함수를 한번만 호출하면 된다.
- 설정 상수
INCLUDE_vTaskSuspend = 1
- 전달 인자
pxTaskToSuspend | 중지시킬 태스크의 핸들. NULL 을 넘겨주면 호출한 태스크가 중지된다. |
- 사용 예
void vAFunction( void ) { xTaskHandle xHandle; // Create a task, storing the handle. xTaskCreate( vTaskCode, "NAME", STACK_SIZE, NULL, tskIDLE_PRIORITY, &xHandle ); // ... // Use the handle to suspend the created task. vTaskSuspend( xHandle ); // ... // The created task will not run during this period, unless // another task calls vTaskResume( xHandle ). //... // Suspend ourselves. vTaskSuspend( NULL ); // We cannot get here unless another task calls vTaskResume // with our handle as the parameter. }
vTaskResume
void | vTaskResume( | xTaskHandle pxTaskToResume |
); |
중지된(suspended) 태스크를 재개(Resume) 시킨다. 이전에 몇 번 vTaskSuspend() 에 의해 중지되었더라도 한번의 vTaskResume() 호출로 즉시 재개된다.
- 설정 상수
INCLUDE_vTaskSuspend = 1
- 전달 인자
pxTaskToResume | 준비상태로 되돌릴 태스크의 핸들. |
- 사용 예
void vAFunction( void ) { xTaskHandle xHandle; // Create a task, storing the handle. xTaskCreate( vTaskCode, "NAME", STACK_SIZE, NULL, tskIDLE_PRIORITY, &xHandle ); // ... // Use the handle to suspend the created task. vTaskSuspend( xHandle ); // ... // The created task will not run during this period, unless // another task calls vTaskResume( xHandle ). //... // Resume the suspended task ourselves. vTaskResume( xHandle ); // The created task will once again get microcontroller processing // time in accordance with it priority within the system. }
vTaskResumeFromISR
void | vTaskResume( | xTaskHandle pxTaskToResume |
); |
ISR 내부에서 호출될 수 있는 중지된 태스크를 재개시키는 함수이다. vTaskResume() 에서와 같이 이전에 몇 번 vTaskSuspend() 에 의해 중지되었더라도 한번의 vTaskResumeFromISR() 호출로 즉시 재개된다.
- 설정 상수
INCLUDE_vTaskSuspend = 1
INCLUDE_xTaskResumeFromISR = 1
- 전달 인자
pxTaskToResume | 준비상태로 되돌릴 태스크의 핸들 |
- 반환값
재개되는 태스크가 현재 실행중인 태스크보다 우선순위가 높아서 문맥 전환이 필요해지면 pdTRUE 를 반환하고 그렇지 않으면 pdFALSE 를 반환한다. 이 반환값을 이용해 ISR은 ISR 이 끝난 후 문맥 전환이 필요한지의 여부를 판단할 수 있다.
- 사용 예
xTaskHandle xHandle; void vAFunction( void ) { // Create a task, storing the handle. xTaskCreate( vTaskCode, "NAME", STACK_SIZE, NULL, tskIDLE_PRIORITY, &xHandle ); // ... Rest of code. } void vTaskCode( void *pvParameters ) { // The task being suspended and resumed. for( ;; ) { // ... Perform some function here. // The task suspends itself. vTaskSuspend( NULL ); // The task is now suspended, // so will not reach here until the ISR resumes it. } } void vAnExampleISR( void ) { portBASE_TYPE xYieldRequired; // Resume the suspended task. xYieldRequired = xTaskResumeFromISR( xHandle ); if( xYieldRequired == pdTRUE ) { // We should switch context so the ISR returns to a different task. // NOTE: How this is done depends on the port you are using. Check // the documentation and examples for your port. portYIELD_FROM_ISR(); } }
Kernel Control
taskYIELD
강제 문맥 전환 매크로
taskENTER_CRITICAL
크리티컬 코드 영역의 시작을 표시하는 매크로. 이 영역 안에서는 선점형 문맥 전환이 일어나지 않는다.
- 주의 사항
스택을 변경시킬 수 있으므로 주의해서 사용해야만 한다.
taskEXIT_CRITICAL
크리티컬 코드 영역의 끝을 표시하는 매크로.
taskDISABLE_INTERRUPTS
마스킹 가능한 모든 인터럽트를 비활성화 시키는 매크로.
taskENABLE_INTERRUPTS
비활성화된 인터럽트들을 활성화시키는 매크로.
vTaskStartScheduler
void | vTaskStartScheduler( | void |
); |
실시간 커널 틱 처리를 시작시킨다. 이후에 커널은 어떤 시점에 어떤 태스크가 실행되는가에 대한 제어권을 가지게 된다. vTaskStartScheduler() 가 시작되면 자동적으로 idle task 가 생성된다. vTaskStartScheduler() 가 성공적으로 수행되면 함수는 실행중인 태스크가 vTaskEndScheduler() 를 호출하기 전까지 반환하지 않는다. 만약 idle 태스크를 생성할 충분한 RAM 용량이 없을 경우 호출은 실패하고 즉시 호출 지점으로 돌아간다.
- 사용 예
void vAFunction( void ) { // Create at least one task before starting the kernel. xTaskCreate( vTaskCode, "NAME", STACK_SIZE, NULL, tskIDLE_PRIORITY, NULL ); // Start the real time kernel with preemption. vTaskStartScheduler(); // Will not get here unless a task calls vTaskEndScheduler () }
vTaskEndScheduler
void | vTaskEndScheduler( | void |
); |
실시간 커널 틱을 정지시킨다. 모든 생성된 태스크들이 자동적으로 삭제되고 멀티태스킹이 중지된다. 그리고 vTaskStartScheduler() 가 호출된 지점으로 돌아가서 나머지 부분을 실행한다. vTaskEndScheduler() 는 이식 계층(portable layer) 안에서 정의된 종료 함수가 필요하다. 이것은 커널 틱을 정지시키는 것과 같은 하드웨어 관련 작업을 수행한다. vTaskEndScheduler() 는 커널에 의해 할당된 모든 리소스를 해제시킨다. 하지만 응용프로그램에 의해 할당된 리소스는 해제시키지 않는다.
- 사용 예
void vTaskCode( void * pvParameters ) { for( ;; ) { // Task code goes here. // At some point we want to end the real time kernel processing // so call ... vTaskEndScheduler (); } } void vAFunction( void ) { // Create at least one task before starting the kernel. xTaskCreate( vTaskCode, "NAME", STACK_SIZE, NULL, tskIDLE_PRIORITY, NULL ); // Start the real time kernel with preemption. vTaskStartScheduler(); // Will only get here when the vTaskCode () task has called // vTaskEndScheduler (). When we get here we are back to single task // execution. }
vTaskSuspendAll
void | vTaskSuspendAll( | void |
); |
인터럽트를 제외한 모든 실시간 커널의 동작을 정지시킨다. 이것을 호출한 태스크는 xTaskResumeAll() 이 호출되기 전까지 다른 태스크에게 선점당할 걱정 없이 실행을 계속할 수 있다.
- 사용 예
void vTask1( void * pvParameters ) { for( ;; ) { // Task code goes here. // ... // At some point the task wants to perform a long operation during // which it does not want to get swapped out. It cannot use // taskENTER_CRITICAL ()/taskEXIT_CRITICAL () as the length of the // operation may cause interrupts to be missed - including the // ticks. // Prevent the real time kernel swapping out the task. vTaskSuspendAll (); // Perform the operation here. There is no need to use critical // sections as we have all the microcontroller processing time. // During this time interrupts will still operate and the kernel // tick count will be maintained. // ... // The operation is complete. Restart the kernel. xTaskResumeAll (); } }
xTaskResumeAll
portBASE_TYPE xTaskResumeAll( | void |
); |
vTaskSuspendAll()이 호출됨으로써 정지되었던 실시간 커널의 동작을 재개시킨다. xTaskResumeAll() 을 호출하면 커널은 태스크에 대한 실행 제어권을 다시 가지게 된다.
- 반환값
스케줄러를 재개하는 과정에서 이전에 우선순위의 변경이 있어 문맥 전환이 필요하다면 pdTRUE를 반환하고 그렇지 않으면 pdFALSE를 반환한다.
- 사용 예
void vTask1( void * pvParameters ) { for( ;; ) { // Task code goes here. // ... // At some point the task wants to perform a long operation during // which it does not want to get swapped out. It cannot use // taskENTER_CRITICAL ()/taskEXIT_CRITICAL () as the length of the // operation may cause interrupts to be missed - including the // ticks. // Prevent the real time kernel swapping out the task. xTaskSuspendAll (); // Perform the operation here. There is no need to use critical // sections as we have all the microcontroller processing time. // During this time interrupts will still operate and the real // time kernel tick count will be maintained. // ... // The operation is complete. Restart the kernel. We want to force // a context switch - but there is no point if resuming the scheduler // caused a context switch already. if( !xTaskResumeAll () ) { taskYIELD (); } } }
Task Utilities
xTaskGetTickCount
volatile | portTickType xTaskGetTickCount( | void |
); |
- 반환값
vTaskStartScheduler 가 호출된 이후부터의 틱 카운트 수를 반환한다.
uxTaskGetNumberOfTasks
unsigned portBASE_TYPE uxTaskGetNumberOfTasks( | void |
); |
- 반환값
실시간 커널이 현재 관리하고 있는 태스크의 개수를 반환한다. 여기에는 준비, 대기 및 중지 상태에 있는 모든 태스크들이 다 포함된다. 삭제되었지만 태스크에게 할당된 메모리가 아직 idle 태스크에 의해 해제되지 못한 경우도 여기에 포함된다.
vTaskList
void vTaskList( | portCHAR *pcWriteBuffer |
); |
현재의 모든 태스크들을 그 상태 및 스택 사용량과 함께 나열한다. 태스크의 상태는 대기(‘B'), 준비 (’R'), 삭제 (‘D'), 중지(’S') 로 표현된다.
- 설정 상수
configUSE_TRACE_FACILITY = 1
INCLUDE_vTaskDelete = 1
INCLUDE_vTaskSuspend = 1
- 전달 인자
pcWriteBuffer | 앞에서 언급한 태스크에 관한 상세 내용들이 아스키 형식으로 기록된 버퍼이다. 버퍼의 크기는 생성된 보고 내용을 담을 수 있도록 충분히 커야 하며, 보통 각 태스크당 40바이트면 충분하다. |
- 주의 사항
이 함수는 실행 기간 동안 인터럽트를 비활성화 시킨다. 따라서 일반적인 응용프로그램 수행 상황에는 쓰이지 않으며 디버그를 위한 기능이다.
vTaskStartTrace
void vTaskStartTrace( | portCHAR * pcBuffer, |
unsigned portLONG ulBufferSize | |
); |
실시간 커널 동작 추적을 시작한다. 어떤 태스크가 언제 실행되는지에 대한 것을 추적하여 기록한다. 추적 결과는 바이너리 형식으로 저장된다. 별도의 DOS 프로그램인 convtrce.exe 를 이용해 이 바이너리 자료를 탭으로 구분되는 텍스트 파일로 만들 수 있다. 이렇게 해서 스프레드 시트에서 보거나 출력할 수 있다.
- 전달 인자
pcBuffer | 추적 결과가 기록될 버퍼. |
ulBufferSize | pcBuffer의 바이트단위 크기. 동작 추적은 크기 만큼의 버퍼가 가득 찰 때 까지 또는 ulTaskEndTrace() 이 호출될 때 까지 계속해서 기록된다. |
ulTaskEndTrace
unsigned portLONG ulTaskEndTrace( | void |
); |
커널 동작 추적을 중지한다. vTaskStartTrace() 참고.
- 반환값
지금까지 추적 버퍼에 기록된 바이트의 수를 반환한다.
Queue Management
uxQueueMessagesWaiting
unsigned portBASE_TYPE uxQueueMessagesWaiting( | xQueueHandle xQueue |
); |
큐에 저장된 메시지의 개수를 반환한다.
- 전달 인자
xQueue | 질의할 큐에 대한 핸들. |
- 반환값
큐에 남아 있는 메시지의 개수.
vQueueDelete
void vQueueDelete( | xQueueHandle xQueue |
); |
큐를 삭제학고 큐에 저장되어 있는 모든 항목에 대한 메모리를 해제시킨다.
- 전달 인자
xQueue | 삭제될 큐에 대한 핸들. |
xQueueCreate
xQueueHandle xQueueCreate( | unsigned portBASE_TYPE uxQueueLength, |
unsigned portBASE_TYPE uxItemSize | |
); |
새로운 큐 인스턴스를 생성한다. 이 함수는 새로운 큐에 필요한 메모리를 할당하고 큐에 대한 핸들을 반환한다.
- 전달 인자
uxQueueLength | 큐가 가질 수 있는 항목의 최대 개수. |
uxItemSize | 큐에 있는 각각의 항목이 필요로 하는 바이트 수. 항목이 큐에 저장될 때 이만큼의 바이트씩 저장된다. 큐에 저장되는 각각의 항목은 반드시 같은 크기여야 한다. |
- 반환값
큐가 성공적으로 생성되면 새롭게 생성된 큐의 핸들을 반환한다. 만약 큐가 생성되지 않으면 0을 반환한다.
- 사용 예
struct AMessage { portCHAR ucMessageID; portCHAR ucData[ 20 ]; }; void vATask( void *pvParameters ) { xQueueHandle xQueue1, xQueue2; // Create a queue capable of containing 10 unsigned long values. xQueue1 = xQueueCreate( 10, sizeof( unsigned portLONG ) ); if( xQueue1 == 0 ) { // Queue was not created and must not be used. } // Create a queue capable of containing 10 pointers to AMessage structures. // These should be passed by pointer as they contain a lot of data. xQueue2 = xQueueCreate( 10, sizeof( struct AMessage * ) ); if( xQueue2 == 0 ) { // Queue was not created and must not be used. } // ... Rest of task code. }
xQueueSend
portBASE_TYPE xQueueSend( | xQueueHandle xQueue, |
const void * pvItemToQueue, | |
portTickType xTicksToWait | |
); |
큐에 항목을 저장하는 함수. 항목은 참조 형태로 저장되는 것이 아니라 복사를 통해 저장된다. 이 함수는 인터럽트 서비스 루틴에서 호출 할 수 없다. 이 경우 xQueueSendFromISR()를 사용해야 한다.
- 전달 인자
xQueue | 항목을 저장할 큐에 대한 핸들. |
pvItemToQueue | 큐에 저장할 항목에 대한 포인터. 큐가 가질 수 있는 항목의 크기는 큐를 생성할 때 정의한다. 그래서 이만큼의 바이트를 pvItemToQueue 가 가리키는 곳에서 큐 영역으로 복사한다. |
xTicksToWait | 큐에 공간이 빌 때까지 테스크가 기다리는 최대 시간. 이것이 0 으로 설정이 되어있으면 즉시 호출한 지점으로 돌아간다. 이 시간은 tick 주기로 정의한다. 그래서 필요하다면 portTICK_RATE_MS을 사용하여 실제의 시간을 변환해서 사용해야한다. |
- 반환값
항목이 성공적으로 큐에 저장되면 pdTRUE를 반환하고 그렇지 않으면 errQUEUE_FULL를 반환한다.
- 사용 예
struct AMessage { portCHAR ucMessageID; portCHAR ucData[ 20 ]; } xMessage; unsigned portLONG ulVar = 10UL; void vATask( void *pvParameters ) { xQueueHandle xQueue1, xQueue2; struct AMessage *pxMessage; // Create a queue capable of containing 10 unsigned long values. xQueue1 = xQueueCreate( 10, sizeof( unsigned portLONG ) ); // Create a queue capable of containing 10 pointers to AMessage structures. // These should be passed by pointer as they contain a lot of data. xQueue2 = xQueueCreate( 10, sizeof( struct AMessage * ) ); // ... if( xQueue1 != 0 ) { // Send an unsigned long. Wait for 10 ticks for space to become // available if necessary. if( xQueueSend( xQueue1, ( void * ) &ulVar, ( portTickType ) 10 ) != pdPASS ) { // Failed to post the message, even after 10 ticks. } } if( xQueue2 != 0 ) { // Send a pointer to a struct AMessage object. Don't block if the // queue is already full. pxMessage = & xMessage; xQueueSend( xQueue2, ( void * ) &pxMessage, ( portTickType ) 0 ); } // ... Rest of task code. }
xQueueReceive
portBASE_TYPE xQueueReceive( | xQueueHandle xQueue, |
void *pvBuffer, | |
portTickType xTicksToWait | |
); |
큐에서 항목을 받는 함수. 항목을 복사하여 받기 때문에 미리 적당한 크기의 버퍼를 마련해 두어야 한다. 버퍼로 복사되는 바이트의 수는 큐를 생성할 때 정의한다. 이 함수는 인터럽트 서비스 루틴에서 사용되어서는 안 된다. 이 경우에는 그 대신 xQueueReceiveFromISR를 사용하도록 한다.
- 전달 인자
pxQueue | 항목을 가져올 큐에 대한 핸들. |
pvBuffer | 받은 항목을 복사할 버퍼에 대한 포인터. |
xTicksToWait | 큐가 비어있을 경우 태스크가 항목을 받기위해 기다리는 시간. 이 시간은 틱 주기로 정의한다. 그래서 필요하다면 portTICK_RATE_MS을 사용하여 실제의 시간을 변환해서 사용해야한다. |
- 반환값
큐에서 항목을 성공적으로 받으면 pdTRUE를 반환하고, 그렇지 않으면 pdFALSE를 반환한다.
- 사용 예
struct AMessage { portCHAR ucMessageID; portCHAR ucData[ 20 ]; } xMessage; xQueueHandle xQueue; // Task to create a queue and post a value. void vATask( void *pvParameters ) { struct AMessage *pxMessage; // Create a queue capable of containing 10 pointers to AMessage structures. // These should be passed by pointer as they contain a lot of data. xQueue = xQueueCreate( 10, sizeof( struct AMessage * ) ); if( xQueue == 0 ) { // Failed to create the queue. } // ... // Send a pointer to a struct AMessage object. Don't block if the // queue is already full. pxMessage = & xMessage; xQueueSend( xQueue, ( void * ) &pxMessage, ( portTickType ) 0 ); // ... Rest of task code. } // Task to receive from the queue. void vADifferentTask( void *pvParameters ) { struct AMessage *pxRxedMessage; if( xQueue != 0 ) { // Receive a message on the created queue. Block for 10 ticks if a // message is not immediately available. if( xQueueReceive( xQueue, &( pxRxedMessage ), ( portTickType ) 10 ) ) { // pcRxedMessage now points to the struct AMessage variable posted // by vATask. } } // ... Rest of task code. }
xQueueSendFromISR
portBASE_TYPE xQueueSendFromISR( | xQueueHandle pxQueue, |
const void *pvItemToQueue, | |
portBASE_TYPE xTaskPreviouslyWoken | |
); |
항목을 큐에 저장시킨다. 이 함수는 인터럽트 서비스 루틴에서 사용해도 안전하다. 항목은 참조가 아니라 복사로 큐에 저장되므로 특별히 ISR에서 호출할 경우 작은 사이즈의 항목을 저장하도록 해야만 한다. 대부분의 경우 큐에 저장시킬 항목에 대한 포인터를 저장하는 것이 바람직하다.
- 전달 인자
xQueue | 항목을 저장할 큐에 대한 핸들 |
pvItemToQueue | 큐에 저장할 항목에 대한 포인터. 큐가 저장할 수 있는 항목의 크기는 큐가 생성될 때 정의한다. 그래서 이 만큼의 바이트가 pvItemToQueue에서 큐 영역으로 복사될 것이다. |
xTaskPreviouslyWoken | ISR 은 하나의 인터럽트를 받아서 같은 큐에 여러 번 저장시킬 수 있다. 첫 번째 호출은 항상 pdFALSE을 전달한다. 다음번 호출부터는 이전의 호출에서 반환한 값을 넘겨준다. |
- 반환값
만약 이전에 실행중이던 태스크가 ISR에서 큐에 항목을 저장한 뒤에 다시 깨어나면 pdTRUE를 반환한다. 이것은 ISR 이 ISR 이후에 컨텍스트 스위치가 필요한지 여부를 결정하는데 사용한다.
- 사용 예
- (버퍼드 IO -ISR이 한번의 호출에 하나 이상의 값을 얻을 수 있음)
void vBufferISR( void ) { portCHAR cIn; portBASE_TYPE xTaskWokenByPost; // We have not woken a task at the start of the ISR. xTaskWokenByPost = pdFALSE; // Loop until the buffer is empty. do { // Obtain a byte from the buffer. cIn = portINPUT_BYTE( RX_REGISTER_ADDRESS ); // Post the byte. The first time round the loop xTaskWokenByPost // will be pdFALSE. If the queue send causes a task to wake we do // not want the task to run until we have finished the ISR, so // xQueueSendFromISR does not cause a context switch. Also we // don't want subsequent posts to wake any other tasks, so we store // the return value back into xTaskWokenByPost so xQueueSendFromISR // knows not to wake any task the next iteration of the loop. xTaskWokenByPost = xQueueSendFromISR( xRxQueue, &cIn, xTaskWokenByPost ); } while( portINPUT_BYTE( BUFFER_COUNT ) ); // Now the buffer is empty we can switch context if necessary. if( xTaskWokenByPost ) { // We should switch context so the ISR returns to a different task. // NOTE: How this is done depends on the port you are using. Check // the documentation and examples for your port. portYIELD_FROM_ISR(); } }
xQueueReceiveFromISR
portBASE_TYPE xQueueReceiveFromISR( | xQueueHandle pxQueue, |
void *pvBuffer, | |
portBASE_TYPE *pxTaskWoken | |
); |
큐에서 항목을 하나 가져오는 함수. 이 함수는 인터럽트 서비스 루틴 내부에서 사용해도 안전하다.
- 전달 인자
pxQueue | 항목을 받을 큐에 대한 핸들. |
pvBuffer | 받은 항목을 복사할 버퍼에 대한 포인터 |
pxTaskWoken | 태스크는 큐에 항목이 생길 때까지 대기하고 있을 수 있다. 만약 xQueueReceiveFromISR 이 태스크의 대기 상태를 해제시킬 경우 *pxTaskWoken 는 pdTRUE로 설정된다. 그렇지 않다면 *pxTaskWoken는 변하지 않는다. |
- 반환값
만약 항목을 성공적으로 큐에서 가져오면 pdTRUE를 반환하고 그렇지 않으면 pdFALSE를 반환한다.
- 사용 예
xQueueHandle xQueue; // Function to create a queue and post some values. void vAFunction( void *pvParameters ) { portCHAR cValueToPost; const portTickType xBlockTime = ( portTickType )0xff; // Create a queue capable of containing 10 characters. xQueue = xQueueCreate( 10, sizeof( portCHAR ) ); if( xQueue == 0 ) { // Failed to create the queue. } // ... // Post some characters that will be used within an ISR. If the queue // is full then this task will block for xBlockTime ticks. cValueToPost = 'a'; xQueueSend( xQueue, ( void * ) &cValueToPost, xBlockTime ); cValueToPost = 'b'; xQueueSend( xQueue, ( void * ) &cValueToPost, xBlockTime ); // ... keep posting characters ... this task may block when the queue // becomes full. cValueToPost = 'c'; xQueueSend( xQueue, ( void * ) &cValueToPost, xBlockTime ); } // ISR that outputs all the characters received on the queue. void vISR_Routine( void ) { portBASE_TYPE xTaskWokenByReceive = pdFALSE; portCHAR cRxedChar; while( xQueueReceiveFromISR( xQueue, ( void * ) &cRxedChar, &xTaskWokenByReceive) ) { // A character was received. Output the character now. vOutputCharacter( cRxedChar ); // If removing the character from the queue woke the task that was // posting onto the queue xTaskWokenByReceive will have been set to // pdTRUE. No matter how many times this loop iterates only one // task will be woken. } if( xTaskWokenByPost != pdFALSE ) { // We should switch context so the ISR returns to a different task. // NOTE: How this is done depends on the port you are using. Check // the documentation and examples for your port. taskYIELD (); } }
Semaphore / Mutex
vSemaphoreCreateBinary
vSemaphoreCreateBinary( | xSemaphoreHandle xSemaphore |
); |
큐 메커니즘을 이용해서 세마포어를 생성하는 매크로. 큐의 길이가 1일 때 이것은 바이너리 세마포어를 뜻한다. 우리가 실제 데이터를 여기 저장하는 것이 목적이 아니기 때문에 저장될 데이터의 크기는 0이다. 단지 우리가 알기 원하는 것은 큐가 비어있는지 또는 가득 차 있는지 알아보는 것이 목적이다.
- 전달 인자
xSemaphore | 생성된 세마포어의 핸들. xSemaphoreHandle 자료형이어야 한다. |
- 사용 예
xSemaphoreHandle xSemaphore; void vATask( void * pvParameters ) { // Semaphore cannot be used before a call to vSemaphoreCreateBinary (). // This is a macro so pass the variable in directly. vSemaphoreCreateBinary( xSemaphore ); if( xSemaphore != NULL ) { // The semaphore was created successfully. // The semaphore can now be used. } }
xSemaphoreTake
xSemaphoreTake( | xSemaphoreHandle xSemaphore, |
portTickType xBlockTime | |
); |
세마포어를 획득하기 위한 매크로. 이전에 반드시 vSemaphoreCreateBinary() 를 통해 세마포어가 생성 되어 있어야 한다.
- 전달 인자
xSemaphore | 획득한 세마포어의 핸들. 이것은 vSemaphoreCreateBinary () 가 반환한 핸들이다. |
xBlockTime | 세마포어를 획득할 수 있을 때 까지 기다리는 틱의 길이. portTICK_RATE_MS 매크로는 이것을 실제 시간으로 변환하는데 사용된다. 0을 넘겨주면 사용가능한 세마포어를 찾아 폴링(polling) 한다. |
- 반환값
만약 세마포어가 획득되면 pdTRUE를 반환하고 세마포어를 획득하지 못하고 xBlockTime이 종료된다면 pdFALSE를 반환한다.
- 사용 예
xSemaphoreHandle xSemaphore = NULL; // A task that creates a semaphore. void vATask( void * pvParameters ) { // Create the semaphore to guard a shared resource. vSemaphoreCreateBinary( xSemaphore ); } // A task that uses the semaphore. void vAnotherTask( void * pvParameters ) { // ... Do other things. if( xSemaphore != NULL ) { // See if we can obtain the semaphore. // If the semaphore is not available // wait 10 ticks to see if it becomes free. if( xSemaphoreTake( xSemaphore, ( portTickType ) 10 ) == pdTRUE ) { // We were able to obtain the semaphore and can now access the // shared resource. // ... // We have finished accessing the shared resource. Release the // semaphore. xSemaphoreGive( xSemaphore ); } else { // We could not obtain the semaphore and can therefore not access // the shared resource safely. } } }
xSemaphoreGive
xSemaphoreGive( | xSemaphoreHandle xSemaphore |
); |
획득한 세마포어를 놓아주기 위한 매크로. 놓아줄 세마포어는 반드시 vSemaphoreCreateBinary()를 이용하여 생성되어 있어야 하고 sSemaphoreTake()를 사용하여 획득된 상태여야 한다. 이 매크로 함수는 ISR 에서는 사용될 수 없다. ISR에서 이 기능을 사용하기 위해서는 xSemaphoreGiveFromISR()를 사용하여야 한다.
- 전달 인자
xSemaphore | 해제될 세마포어의 핸들. 이것은 vSemaphoreCreateBinary() 에 의해 반환된 핸들이다. |
- 반환값
세마포어가 해제되면 pdTRUE를 반환하고 에러가 발생하면 pdFALSE 가 발생한다. 세마포어는 큐를 이용하여 구현된다. 메시지를 위한 공간이 큐에 없을 경우 세마포어가 정상적으로 획득되지 않았다는 것을 표시하는 에러가 발생한다.
- 사용 예
xSemaphoreHandle xSemaphore = NULL; void vATask( void * pvParameters ) { // Create the semaphore to guard a shared resource. vSemaphoreCreateBinary( xSemaphore ); if( xSemaphore != NULL ) { if( xSemaphoreGive( xSemaphore ) != pdTRUE ) { // We would expect this call to fail because we cannot give // a semaphore without first "taking" it! } // Obtain the semaphore - don't block if the semaphore is not // immediately available. if( xSemaphoreTake( xSemaphore, ( portTickType ) 0 ) ) { // We now have the semaphore and can access the shared resource. // ... // We have finished accessing the shared resource so can free the // semaphore. if( xSemaphoreGive( xSemaphore ) != pdTRUE ) { // We would not expect this call to fail because we must have // obtained the semaphore to get here. } } } }
xSemaphoreGiveFromISR
xSemaphoreGiveFromISR( | xSemaphoreHandle xSemaphore, |
portBASE_TYPE xTaskPreviouslyWoken | |
); |
세마포어를 놓아주기 위한 매크로 함수. 이 매크로를 수행하기 전에 vSemaphoreCreateBinary() 함수로 세마포어가 생성되어 있어야 하고 xSemaphoreTake() 를 사용해서 세마포어를 사용하고 있는 상태여야 한다. 이 매크로는 ISR에서 사용할 수 있다.
- 전달 인자
xSemaphore | 놓아줄 세마포어에 대한 핸들. 이것은 vSemaphoreCreateBinary () 으로부터 얻은 핸들이다. |
xTaskPreviouslyWoken | 이것이 포함되면 ISR 은 하나의 인터럽트로 여러 번의 xSemaphoreGiveFromISR()을 호출할 수 있다. 첫 번째 호출은 항상 pdFALSE 로 전달한다. 이 후의 호출은 이전의 호출에서 반환된 값을 전달한다. xSemaphoreGiveFromISR() 의 적절한 사용법은 PC port 내부의 serial .c를 참고하라. |
- 반환값
만약 세마포어를 놓아준 뒤 어떠한 이유로 더 높은 우선순위의 태스크가 깨어나면 pdTRUE를 반환한다. 이것은 ISR 이후에 컨텍스트 스위치가 필요할지 여부를 결정하는데 사용한다.
- 사용 예
#define LONG_TIME 0xffff #define TICKS_TO_WAIT 10 xSemaphoreHandle xSemaphore = NULL; // Repetitive task. void vATask( void * pvParameters ) { for( ;; ) { // We want this task to run every 10 ticks or a timer. The semaphore // was created before this task was started // Block waiting for the semaphore to become available. if( xSemaphoreTake( xSemaphore, LONG_TIME ) == pdTRUE ) { // It is time to execute. // ... // We have finished our task. Return to the top of the loop where // we will block on the semaphore until it is time to execute // again. } } } // Timer ISR void vTimerISR( void * pvParameters ) { static unsigned portCHAR ucLocalTickCount = 0; static portBASE_TYPE xTaskWoken = pdFALSE; // A timer tick has occurred. // ... Do other time functions. // Is it time for vATask () to run? ucLocalTickCount++; if( ucLocalTickCount >= TICKS_TO_WAIT ) { // Unblock the task by releasing the semaphore. xTaskWoken = xSemaphoreGiveFromISR( xSemaphore, xTaskWoken ); // Reset the count so we release the semaphore again in 10 ticks time. ucLocalTickCount = 0; } // If xTaskWoken was set to true you may want to yield (force a switch) // here. }
Co-routine specific
xCoRoutineCreate
portBASE_TYPE xCoRoutineCreate( | crCOROUTINE_CODE pxCoRoutineCode, |
unsigned portBASE_TYPE uxPriority, | |
unsigned portBASE_TYPE uxIndex | |
); |
새로운 코루틴을 생성하고 실행 준비 리스트에 추가한다.
- 전달 인자
pxCoRoutineCode | 코루틴 함수에 대한 포인터. 코루틴 함수는 특별한 문법이 필요하다. 자세한 것은 웹 문서를 참고하라. |
uxPriority | 다른 코루틴에 대한 상대적인 우선순위uxIndex 같은 함수 안에서 실행되는 서로 다른 코루틴을 구분하기 위해 사용. |
- 반환값
만약 코루틴이 성공적으로 생성되고 준비 리스트에 추가되면 pdPASS를 반환하고 그렇지 않으면 ProjDefs.h 에 정의된 에러 코드를 반환한다.
- 사용 예
// Co-routine to be created. void vFlashCoRoutine( xCoRoutineHandle xHandle, unsigned portBASE_TYPE uxIndex ) { // Variables in co-routines must be declared static if they must maintain value across a blocking call. // This may not be necessary for const variables. static const char cLedToFlash[ 2 ] = { 5, 6 }; static const portTickType xTimeToDelay[ 2 ] = { 200, 400 }; // Must start every co-routine with a call to crSTART(); crSTART( xHandle ); for( ;; ) { // This co-routine just delays for a fixed period, then toggles // an LED. Two co-routines are created using this function, so // the uxIndex parameter is used to tell the co-routine which // LED to flash and how long to delay. This assumes xQueue has // already been created. vParTestToggleLED( cLedToFlash[ uxIndex ] ); crDELAY( xHandle, uxFlashRates[ uxIndex ] ); } // Must end every co-routine with a call to crEND(); crEND(); } // Function that creates two co-routines. void vOtherFunction( void ) { unsigned char ucParameterToPass; xTaskHandle xHandle; // Create two co-routines at priority 0. The first is given index 0 // so (from the code above) toggles LED 5 every 200 ticks. The second // is given index 1 so toggles LED 6 every 400 ticks. for( uxIndex = 0; uxIndex < 2; uxIndex++ ) { xCoRoutineCreate( vFlashCoRoutine, 0, uxIndex ); } }
xCoRoutineHandle
코루틴이 참조되는 자료형. 코루틴 핸들은 자동적으로 코루틴 함수에 전달된다.
crDELAY
void crDELAY( | xCoRoutineHandle xHandle, |
portTickType xTicksToDelay | |
); |
crDELAY 는 매크로 함수이다. 그래서 위의 원형에 있는 자료형은 오직 참조용으로만 쓰이는 것이다.
crDELAY 는 코루틴 함수 자체에서만 호출될 수 있지 코루틴 함수에 의해 호출되는 함수 안에서는 사용될 수 없다. 왜냐하면 코루틴은 자신의 스택을 유지시키지 않기 때문이다.
- 전달 인자
xHandle | 지연시킬 코루틴의 핸들. 이것은 코루틴 함수의 xHandle 매개변수이다. |
xTickToDelay | 코루틴이 지연될 틱의 수를 지정. 이것의 실제의 시간은 FreeRTOSConfig.h 에 정의되어 있는 configTICK_RATE_HZ 에 의해 정의된다. portTICK_RATE_MS 는 tick를 밀리초(ms) 단위로 변환하기 위해 사용된다. |
- 사용 예
// Co-routine to be created. void vACoRoutine( xCoRoutineHandle xHandle, unsigned portBASE_TYPE uxIndex ) { // Variables in co-routines must be declared static // if they must maintain value across a blocking call. // This may not be necessary for const variables. // We are to delay for 200ms. static const xTickType xDelayTime = 200 / portTICK_RATE_MS; // Must start every co-routine with a call to crSTART(); crSTART( xHandle ); for( ;; ) { // Delay for 200ms. crDELAY( xHandle, xDelayTime ); // Do something here. } // Must end every co-routine with a call to crEND(); crEND(); }
crQUEUE_SEND
crQUEUE_SEND( | xCoRoutineHandle xHandle, |
xQueueHandle pxQueue, | |
void *pvItemToQueue, | |
portTickType xTicksToWait, | |
portBASE_TYPE *pxResult | |
); |
crQUEUE_SEND 는 매크로 함수이다. 그래서 위의 원형에 있는 자료형들은 오직 참조를 위한 것이다. crQUEUE_SEND() 와 crQUEUE_RECEIVE() 매크로는 태스크가 사용하던 xQueueSend() 와 xQueueReceive() 함수와 기능이 동일하다. crQUEUE_SEND 와 crQUEUE_RECEIVE 는 코루틴에서만 쓰이고 xQueueSend() 와 xQueueReceive() 는 오직 태스크에서만 쓰인다. crQUEUE_SEND 는 코루틴 함수 자체에서만 호출될 수 있지 코루틴에 의해 호출되는 함수 안에서는 사용될 수 없다. 왜냐하면 코루틴은 자신의 스택을 유지하지 않기 때문이다.
- 전달 인자
xHandle | 코루틴을 호출하는 핸들. 이것은 코루틴 함수의 핸들 매개변수이다. |
pxQueue | 데이터가 전송될 큐의 핸들. 이 핸들은 큐가 xQueueCreate() API 함수를 사용하여 생성될 때 반환값으로 얻을 수 있다. |
pvItemToQueue | 큐에 전송된 자료에 대한 포인터. 큐에 전송될 각각의 항목의 바이트 수는 큐가 생성될 때 정의된다. 이만큼의 바이트가 pvItemToQueue 로부터 queue 에 전송된다. |
xTickToDelay | 큐에 에 남은 용량이 없을 경우 사용가능해질 때 까지 코루틴이 대기 상태로 기다릴 틱의 수. 이것의 실제 시간은 FreeRTOSConfig.h 안에 있는 portTICK_RATE_MS 에 정의되어 있다. 상수 portTICK_RATE_MS 는 틱을 밀리초(ms) 단위로 변환하는데 사용된다. |
pxResult | 큐에 자료를 넣는데 성공하면 pdPASS를, 그렇지 않으면 ProjDefs.h. 에 정의된 에러값을 가진다. |
- 사용 예
// Co-routine function that blocks for a fixed period then posts a number onto // a queue. static void prvCoRoutineFlashTask( xCoRoutineHandle xHandle, unsigned portBASE_TYPE uxIndex ) { // Variables in co-routines must be declared static // if they must maintain value across a blocking call. static portBASE_TYPE xNumberToPost = 0; static portBASE_TYPE xResult; // Co-routines must begin with a call to crSTART(). crSTART( xHandle ); for( ;; ) { // This assumes the queue has already been created. crQUEUE_SEND( xHandle, xCoRoutineQueue, &xNumberToPost, NO_DELAY, &xResult ); if( xResult != pdPASS ) { // The message was not posted! } // Increment the number to be posted onto the queue. xNumberToPost++; // Delay for 100 ticks. crDELAY( xHandle, 100 ); } // Co-routines must end with a call to crEND(). crEND(); }
crQUEUE_RECEIVE
void crQUEUE_RECEIVE( | xCoRoutineHandle xHandle, |
xQueueHandle pxQueue, | |
void *pvBuffer, | |
portTickType xTicksToWait, | |
portBASE_TYPE *pxResult | |
); |
crQUEUE_RECEIVE 은 매크로 함수이다. 그래서 위의 원형에 있는 자료형들은 오직 참조를 위한 것이다. crQUEUE_SEND() 와 crQUEUE_RECEIVE() 매크로는 태스크가 사용하던 xQueueSend() 와 xQueueReceive() 함수와 기능이 동일하다. crQUEUE_SEND 와 crQUEUE_RECEIVE 는 코루틴 에서만 쓰이고 xQueueSend() 와 xQueueReceive() 는 오직 태스크에서만 쓰인다. crQUEUE_RECEIVE 는 코루틴 함수 자체에서만 호출될 수 있지 코루틴에 의해 호출되는 함수 안에서는 사용될 수 없다. 왜냐하면 코루틴은 자신의 스택을 유지시키지 않기 때문이다.
- 전달 인자
xHandle | 코루틴의 핸들. 이것은 코루틴 함수의 xHandle 매개변수이다. |
pxQueue | 데이터를 전송받을 큐의 핸들. 핸들은 큐가 xQueueCreate() API 함수를 사용하여 생성될 때 반환값으로 얻을 수 있다. |
pvBuffer | 받은 항목을 복사할 버퍼. 큐에 있는 항목의 바이트 수는 큐가 생성될 때 명시된다. 이 숫자만큼의 바이트가 pvBuffer 에 복사된다. |
xTickToDelay | 큐에 항목이 없을 경우 사용가능할 때 까지 코루틴이 대기 상태로 기다릴 틱의 수. 이것의 실제 시간은 FreeRTOSConfig.h 안에 있는 portTICK_RATE_MS 에 정의되어 있다. 상수 portTICK_RATE_MS 는 틱을 밀리초(ms) 단위로 변환하는데 사용된다. |
pxResult | 큐에서 자료를 성공적으로 가져올 경우 pdPASS를, 그렇지 않으면 ProjDefs.h. 에 정의된 에러값을 가진다. |
- 사용 예
// A co-routine receives the number of an LED to flash from a queue. It // blocks on the queue until the number is received. static void prvCoRoutineFlashWorkTask( xCoRoutineHandle xHandle, unsigned portBASE_TYPE uxIndex ) { // Variables in co-routines must be declared static if they must maintain value across a blocking call. static portBASE_TYPE xResult; static unsigned portBASE_TYPE uxLEDToFlash; // All co-routines must start with a call to crSTART(). crSTART( xHandle ); for( ;; ) { // Wait for data to become available on the queue. crQUEUE_RECEIVE( xHandle, xCoRoutineQueue, &uxLEDToFlash, portMAX_DELAY, &xResult ); if( xResult == pdPASS ) { // We received the LED to flash - flash it! vParTestToggleLED( uxLEDToFlash ); } } crEND(); }
crQUEUE_SEND_FROM_ISR
portBASE_TYPE crQUEUE_SEND_FROM_ISR( | xQueueHandle pxQueue, |
void *pvItemToQueue, | |
portBASE_TYPE xCoRoutinePreviouslyWoken | |
); |
crQUEUE_SEND_FROM_ISR() 은 매크로 함수이다. 그래서 위의 원형에 있는 자료형들은 오직 참조를 위한 것이다. crQUEUE_SEND_FROM_ISR() 과 crQUEUE_RECEIVE_FROM_ISR() 매크로는 태스크가 사용하던 xQueueSendFromISR() 와 xQueueReceiveFromISR() 함수와 기능이 동일하다. crQUEUE_SEND_FROM_ISR() 와 crQUEUE_RECEIVE_FROM_ISR() 는 코루틴과 ISR 사이에 자료를 전달하는 데에만 쓰이는 반면에 xQueueSendFromISR() 과 xQueueReceiveFromISR() 은 오직 태스크와 ISR 사이에서만 쓰인다. crQUEUE_SEND_FROM_ISR 은 ISR에서만 호출될 수 있다.
- 전달 인자
xQueue | 항목이 들어있는 큐의 핸들. |
pvItemToQueue | 큐에 들어갈 항목에 대한 포인터. 큐가 가질 항목의 크기는 큐가 생성될 때 정의 된다. 그래서 이만큼의 바이트가 pvItemToQueue 으로부터 큐 저장 영역으로 복사된다. |
xCoRoutinePreviouslyWoken | ISR 이 하나의 인터럽트를 받아서 같은 큐에 여러 번 자료를 전송할 수 있게 해준다. 첫 번째 호출 때는 항상 pdFALSE를 넘겨주어야 하고 그다음 호출부터는 이전의 호출에서 받은 값을 넘겨준다. |
- 반환값
큐에 자료를 보냄으로 인해 코루틴이 깨어나서 문맥 전환이 필요해지면 pdTRUE를 반환한다. 이것은 ISR 수행 후에 문맥 전환이 필요한지를 판단하는데 사용된다.
- 사용 예
// A co-routine that blocks on a queue waiting for characters to be received. static void vReceivingCoRoutine( xCoRoutineHandle xHandle, unsigned portBASE_TYPE uxIndex ) { portCHAR cRxedChar; portBASE_TYPE xResult; // All co-routines must start with a call to crSTART(). crSTART( xHandle ); for( ;; ) { // Wait for data to become available on the queue. This assumes the // queue xCommsRxQueue has already been created! crQUEUE_RECEIVE( xHandle, xCommsRxQueue, &uxLEDToFlash, portMAX_DELAY, &xResult ); // Was a character received? if( xResult == pdPASS ) { // Process the character here. } } // All co-routines must end with a call to crEND(). crEND(); } // An ISR that uses a queue to send characters received on a serial port to // a co-routine. void vUART_ISR( void ) { portCHAR cRxedChar; portBASE_TYPE xCRWokenByPost = pdFALSE; // We loop around reading characters until there are none left in the UART. while( UART_RX_REG_NOT_EMPTY() ) { // Obtain the character from the UART. cRxedChar = UART_RX_REG; // Post the character onto a queue. xCRWokenByPost will be pdFALSE // the first time around the loop. If the post causes a co-routine // to be woken (unblocked) then xCRWokenByPost will be set to pdTRUE. // In this manner we can ensure that if more than one co-routine is // blocked on the queue only one is woken by this ISR no matter how // many characters are posted to the queue. xCRWokenByPost = crQUEUE_SEND_FROM_ISR( xCommsRxQueue, &cRxedChar, xCRWokenByPost ); } }
crQUEUE_RECEIVE_FROM_ISR
portBASE_TYPE crQUEUE_SEND_FROM_ISR( | xQueueHandle pxQueue, |
void *pvBuffer, | |
portBASE_TYPE * pxCoRoutineWoken | |
); |
crQUEUE_SEND_FROM_ISR() 과 crQUEUE_RECEIVE_FROM_ISR() 매크로는 태스크가 사용하던 xQueueSendFromISR() 및 xQueueReceiveFromISR() 함수와 기능이 동일하다. crQUEUE_SEND_FROM_ISR() 과 crQUEUE_RECEIVE_FROM_ISR() 는 코루틴과 ISR 사이에 자료를 전달하는 데만 쓰이는 반면에 xQueueSendFromISR() 과 xQueueReceiveFromISR() 는 오직 태스크와 ISR 사이에서만 쓰인다. crQUEUE_SEND_FROM_ISR 은 코루틴 안에서만 호출될 수 있다.
- 전달 인자
xQueue | 항목이 들어있는 큐의 핸들. |
pvBuffer | 항목을 가져와서 복사할 버퍼에 대한 포인터. 큐가 가질 수 있는 항목의 크기는 큐가 생성될 때 정의되어 있다. 그래서 그 크기만큼 큐에서 pvBuffer 로 복사될 수 있다. |
pxCoRoutineWoken | 큐에 사용가능한 공간이 없을 때 코루틴은 공간이 생길 때까지 대기 상태로 있을 수 있다. 만약 crQUEUE_RECEIVE_FROM_ISR 이 코루틴의 대기 상태를 해제시킨다면 *pxCoRoutineWoken 은 pdTRUE 가 된다. 그렇지 않으면 *pxCoRoutineWoken 는 바뀌지 않고 그대로이다. |
- 반환값
큐에서 자료를 받아오는데 성공하면 pdTRUE를 반환하고 그렇지 않으면 pdFALSE를 반환한다.
- 사용 예
// A co-routine that posts a character to a queue then blocks for a fixed // period. The character is incremented each time. static void vSendingCoRoutine( xCoRoutineHandle xHandle, unsigned portBASE_TYPE uxIndex ) { // cChar holds its value while this co-routine is blocked and must therefore // be declared static. static portCHAR cCharToTx = 'a'; portBASE_TYPE xResult; // All co-routines must start with a call to crSTART(). crSTART( xHandle ); for( ;; ) { // Send the next character to the queue. crQUEUE_SEND( xHandle, xCoRoutineQueue, &cCharToTx, NO_DELAY, &xResult ); if( xResult == pdPASS ) { // The character was successfully posted to the queue. } else { // Could not post the character to the queue. } // Enable the UART Tx interrupt to cause an interrupt in this // hypothetical UART. The interrupt will obtain the character // from the queue and send it. ENABLE_RX_INTERRUPT(); // Increment to the next character then block for a fixed period. // cCharToTx will maintain its value across the delay as it is // declared static. cCharToTx++; if( cCharToTx > 'x' ) { cCharToTx = 'a'; } crDELAY( 100 ); } // All co-routines must end with a call to crEND(). crEND(); } // An ISR that uses a queue to receive characters to send on a UART. void vUART_ISR( void ) { portCHAR cCharToTx; portBASE_TYPE xCRWokenByPost = pdFALSE; while( UART_TX_REG_EMPTY() ) { // Are there any characters in the queue waiting to be sent? // xCRWokenByPost will automatically be set to pdTRUE if a co-routine // is woken by the post - ensuring that only a single co-routine is // woken no matter how many times we go around this loop. if( crQUEUE_RECEIVE_FROM_ISR( pxQueue, &cCharToTx, &xCRWokenByPost ) ) { SEND_CHARACTER( cCharToTx ); } } }
vCoRoutineSchedule
void vCoRoutineSchedule( | void |
); |
코루틴을 실행시킨다. vCoRoutineSchedule() 은 실행 가능하고 가장 우선순위가 높은 코루틴을 실행시킨다. 코루틴은 대기 상태가 되거나 태스크에 의해 선점될 때까지 실행된다. 코루틴은 협동적으로 실행하기 때문에 하나의 코루틴이 다른 것에 의해 선점되지 않는다. 하지만 태스크에 의해 선점된다.
만약 응용프로그램이 태스크와 코루틴 모두를 포함한다면 vCoRoutineSchedule 은 idle 태스크 훅 내부에서 호출 되어야 한다.
- 사용 예
void vApplicationIdleHook( void ) { vCoRoutineSchedule( void ); }
다른 방법으로는 만약 idle 태스크가 다른 기능을 수행하지 않는다면 아래와 같이 무한루프로 vCoRoutineSchedule()을 호출하는 것이 효과적이다.
void vApplicationIdleHook( void ) { for( ;; ) { vCoRoutineSchedule( void ); } }
'OS 포팅' 카테고리의 다른 글
ATmega128에 FreeRTOS 올리기 (0) | 2013.06.20 |
---|---|
FreeRTOS 분석 - 고급운영체제 (0) | 2013.06.20 |
FreeRTOS 구조 (0) | 2013.06.20 |
FreeRTOS 문맥 전환 과정 (AVR Port) (0) | 2013.06.20 |
FreeRTOS 소개 (0) | 2013.06.20 |