Приложение D. Шпаргалка FreeRTOS API
Сигнатуры — одной страницей, без пояснений. Пояснения и правила
вызова — в разделе 34, механика — в разделах 23–33. Все имена
собраны с ядром 10.5.1 в _verify/rtos_macros.c.
Обозначения: ticks — 0, pdMS_TO_TICKS(n) или portMAX_DELAY;
*woken — BaseType_t, инициализировать pdFALSE, после — portYIELD_FROM_ISR(woken).
D.1 Задачи
BaseType_t xTaskCreate(TaskFunction_t fn, const char *name, uint16_t depthWords,
void *arg, UBaseType_t prio, TaskHandle_t *h);
TaskHandle_t xTaskCreateStatic(fn, name, depthWords, arg, prio,
StackType_t *stack, StaticTask_t *tcb);
void vTaskDelete(TaskHandle_t h); /* NULL — себя */
void vTaskStartScheduler(void); /* не возвращается */
void vTaskDelay(TickType_t ticks); /* от момента вызова */
BaseType_t xTaskDelayUntil(TickType_t *last, TickType_t period);
TickType_t xTaskGetTickCount(void);
TickType_t xTaskGetTickCountFromISR(void);
void taskYIELD(void);
void vTaskSuspend(TaskHandle_t h);
void vTaskResume(TaskHandle_t h);
BaseType_t xTaskResumeFromISR(TaskHandle_t h);
void vTaskPrioritySet(TaskHandle_t h, UBaseType_t prio);
UBaseType_t uxTaskPriorityGet(TaskHandle_t h);
eTaskState eTaskGetState(TaskHandle_t h);
char *pcTaskGetName(TaskHandle_t h);
UBaseType_t uxTaskGetStackHighWaterMark(TaskHandle_t h); /* в словах */
TaskHandle_t xTaskGetCurrentTaskHandle(void);
BaseType_t xTaskGetSchedulerState(void);
UBaseType_t uxTaskGetNumberOfTasks(void);
void vTaskGetInfo(TaskHandle_t h, TaskStatus_t *st, BaseType_t getStack, eTaskState hint);
UBaseType_t uxTaskGetSystemState(TaskStatus_t *arr, UBaseType_t size, uint32_t *totalRun);
void vTaskSuspendAll(void);
BaseType_t xTaskResumeAll(void);
void taskENTER_CRITICAL(void);
void taskEXIT_CRITICAL(void);
UBaseType_t taskENTER_CRITICAL_FROM_ISR(void);
void taskEXIT_CRITICAL_FROM_ISR(UBaseType_t saved);
void portYIELD_FROM_ISR(BaseType_t woken);
D.2 Уведомления задачи
BaseType_t xTaskNotifyGive(TaskHandle_t h);
void vTaskNotifyGiveFromISR(TaskHandle_t h, BaseType_t *woken);
uint32_t ulTaskNotifyTake(BaseType_t clearOnExit, TickType_t ticks);
BaseType_t xTaskNotify(TaskHandle_t h, uint32_t value, eNotifyAction action);
BaseType_t xTaskNotifyFromISR(TaskHandle_t h, uint32_t value, eNotifyAction action,
BaseType_t *woken);
BaseType_t xTaskNotifyWait(uint32_t clearOnEntry, uint32_t clearOnExit,
uint32_t *value, TickType_t ticks);
BaseType_t xTaskNotifyStateClear(TaskHandle_t h);
uint32_t ulTaskNotifyValueClear(TaskHandle_t h, uint32_t mask);
/* eNotifyAction: eNoAction, eSetBits, eIncrement,
eSetValueWithOverwrite, eSetValueWithoutOverwrite */
D.3 Очереди
QueueHandle_t xQueueCreate(UBaseType_t len, UBaseType_t itemSize);
QueueHandle_t xQueueCreateStatic(len, itemSize, uint8_t *storage, StaticQueue_t *buf);
BaseType_t xQueueSend(QueueHandle_t q, const void *item, TickType_t ticks);
BaseType_t xQueueSendToBack(q, item, ticks);
BaseType_t xQueueSendToFront(q, item, ticks);
BaseType_t xQueueOverwrite(q, item); /* только len == 1 */
BaseType_t xQueueReceive(q, void *item, ticks);
BaseType_t xQueuePeek(q, void *item, ticks);
BaseType_t xQueueSendFromISR(q, item, BaseType_t *woken);
BaseType_t xQueueSendToBackFromISR(q, item, woken);
BaseType_t xQueueSendToFrontFromISR(q, item, woken);
BaseType_t xQueueOverwriteFromISR(q, item, woken);
BaseType_t xQueueReceiveFromISR(q, item, woken);
BaseType_t xQueuePeekFromISR(q, item);
UBaseType_t uxQueueMessagesWaiting(q);
UBaseType_t uxQueueMessagesWaitingFromISR(q);
UBaseType_t uxQueueSpacesAvailable(q);
BaseType_t xQueueIsQueueEmptyFromISR(q);
BaseType_t xQueueIsQueueFullFromISR(q);
BaseType_t xQueueReset(q);
void vQueueDelete(q);
void vQueueAddToRegistry(q, const char *name); /* имя для отладчика */
D.4 Семафоры и мьютексы
SemaphoreHandle_t xSemaphoreCreateBinary(void);
SemaphoreHandle_t xSemaphoreCreateBinaryStatic(StaticSemaphore_t *buf);
SemaphoreHandle_t xSemaphoreCreateCounting(UBaseType_t max, UBaseType_t initial);
SemaphoreHandle_t xSemaphoreCreateCountingStatic(max, initial, buf);
SemaphoreHandle_t xSemaphoreCreateMutex(void);
SemaphoreHandle_t xSemaphoreCreateMutexStatic(buf);
SemaphoreHandle_t xSemaphoreCreateRecursiveMutex(void);
SemaphoreHandle_t xSemaphoreCreateRecursiveMutexStatic(buf);
BaseType_t xSemaphoreTake(SemaphoreHandle_t s, TickType_t ticks);
BaseType_t xSemaphoreTakeFromISR(s, BaseType_t *woken); /* не мьютекс */
BaseType_t xSemaphoreGive(s);
BaseType_t xSemaphoreGiveFromISR(s, woken); /* не мьютекс */
BaseType_t xSemaphoreTakeRecursive(s, ticks);
BaseType_t xSemaphoreGiveRecursive(s);
UBaseType_t uxSemaphoreGetCount(s);
TaskHandle_t xSemaphoreGetMutexHolder(s); /* INCLUDE_xSemaphoreGetMutexHolder */
void vSemaphoreDelete(s);
D.5 Программные таймеры
TimerHandle_t xTimerCreate(const char *name, TickType_t period, BaseType_t autoReload,
void *id, TimerCallbackFunction_t cb);
TimerHandle_t xTimerCreateStatic(name, period, autoReload, id, cb, StaticTimer_t *buf);
BaseType_t xTimerStart(TimerHandle_t t, TickType_t ticksToWaitForQueue);
BaseType_t xTimerStop(t, ticks);
BaseType_t xTimerReset(t, ticks);
BaseType_t xTimerChangePeriod(t, TickType_t newPeriod, ticks); /* запускает */
BaseType_t xTimerDelete(t, ticks);
BaseType_t xTimerStartFromISR(t, BaseType_t *woken);
BaseType_t xTimerStopFromISR(t, woken);
BaseType_t xTimerResetFromISR(t, woken);
BaseType_t xTimerChangePeriodFromISR(t, newPeriod, woken);
BaseType_t xTimerIsTimerActive(t);
TickType_t xTimerGetPeriod(t);
TickType_t xTimerGetExpiryTime(t);
void *pvTimerGetTimerID(t);
void vTimerSetTimerID(t, void *id);
BaseType_t xTimerGetReloadMode(t);
void vTimerSetReloadMode(t, BaseType_t autoReload);
TaskHandle_t xTimerGetTimerDaemonTaskHandle(void);
BaseType_t xTimerPendFunctionCall(PendedFunction_t fn, void *arg1, uint32_t arg2, ticks);
BaseType_t xTimerPendFunctionCallFromISR(fn, arg1, arg2, BaseType_t *woken);
/* обратный вызов: void cb(TimerHandle_t t) — не блокироваться */
D.6 Группы событий
EventGroupHandle_t xEventGroupCreate(void);
EventGroupHandle_t xEventGroupCreateStatic(StaticEventGroup_t *buf);
EventBits_t xEventGroupSetBits(EventGroupHandle_t eg, EventBits_t bits);
BaseType_t xEventGroupSetBitsFromISR(eg, bits, BaseType_t *woken); /* через демона */
EventBits_t xEventGroupClearBits(eg, bits);
BaseType_t xEventGroupClearBitsFromISR(eg, bits);
EventBits_t xEventGroupGetBits(eg);
EventBits_t xEventGroupGetBitsFromISR(eg);
EventBits_t xEventGroupWaitBits(eg, EventBits_t bits, BaseType_t clearOnExit,
BaseType_t waitAll, TickType_t ticks);
EventBits_t xEventGroupSync(eg, EventBits_t set, EventBits_t waitFor, ticks);
void vEventGroupDelete(eg);
/* биты 0..23; возвращаемое значение — группа в момент пробуждения */
D.7 Буферы потоков и сообщений
StreamBufferHandle_t xStreamBufferCreate(size_t bytes, size_t trigger);
StreamBufferHandle_t xStreamBufferCreateStatic(bytes, trigger, uint8_t *storage /* bytes+1 */,
StaticStreamBuffer_t *buf);
size_t xStreamBufferSend(StreamBufferHandle_t sb, const void *data, size_t len, TickType_t ticks);
size_t xStreamBufferSendFromISR(sb, data, len, BaseType_t *woken);
size_t xStreamBufferReceive(sb, void *data, size_t max, ticks);
size_t xStreamBufferReceiveFromISR(sb, data, max, woken);
size_t xStreamBufferBytesAvailable(sb);
size_t xStreamBufferSpacesAvailable(sb);
BaseType_t xStreamBufferIsEmpty(sb);
BaseType_t xStreamBufferIsFull(sb);
BaseType_t xStreamBufferSetTriggerLevel(sb, size_t trigger);
BaseType_t xStreamBufferReset(sb);
void vStreamBufferDelete(sb);
MessageBufferHandle_t xMessageBufferCreate(size_t bytes);
MessageBufferHandle_t xMessageBufferCreateStatic(bytes, uint8_t *storage, StaticMessageBuffer_t *buf);
size_t xMessageBufferSend(MessageBufferHandle_t mb, const void *data, size_t len, ticks);
size_t xMessageBufferSendFromISR(mb, data, len, woken);
size_t xMessageBufferReceive(mb, void *data, size_t max, ticks); /* max ≥ самого длинного */
size_t xMessageBufferReceiveFromISR(mb, data, max, woken);
size_t xMessageBufferSpaceAvailable(mb);
BaseType_t xMessageBufferIsEmpty(mb);
BaseType_t xMessageBufferIsFull(mb);
BaseType_t xMessageBufferReset(mb);
void vMessageBufferDelete(mb);
D.8 Куча
void *pvPortMalloc(size_t bytes);
void vPortFree(void *p);
size_t xPortGetFreeHeapSize(void);
size_t xPortGetMinimumEverFreeHeapSize(void); /* heap_4, heap_5 */
void vPortGetHeapStats(HeapStats_t *stats); /* heap_4, heap_5 */
void vPortDefineHeapRegions(const HeapRegion_t *regions); /* heap_5, по возрастанию */
D.9 Ловушки — пишете вы
void vApplicationStackOverflowHook(TaskHandle_t task, char *name);
void vApplicationMallocFailedHook(void);
void vApplicationIdleHook(void); /* не блокироваться */
void vApplicationTickHook(void); /* только FromISR */
void vApplicationGetIdleTaskMemory(StaticTask_t **tcb, StackType_t **stack, uint32_t *size);
void vApplicationGetTimerTaskMemory(StaticTask_t **tcb, StackType_t **stack, uint32_t *size);
D.10 Константы
pdMS_TO_TICKS(ms) portTICK_PERIOD_MS portMAX_DELAY
pdTRUE pdFALSE pdPASS pdFAIL errQUEUE_FULL == errQUEUE_EMPTY == 0
tskIDLE_PRIORITY == 0 configMAX_PRIORITIES configMINIMAL_STACK_SIZE /* слова */
D.11 Минимальный FreeRTOSConfig.h
Три строки — configUSE_IDLE_HOOK, configUSE_TICK_HOOK и
configUSE_16_BIT_TICKS — ядро требует всегда: без них FreeRTOS.h
останавливает сборку с #error Missing definition. Остальные добавки
включают то, чем пользуются D.1–D.6: снимок задач
(configUSE_TRACE_FACILITY), реестр очередей, смену и чтение приоритета,
состояние задачи, владельца мьютекса и отложенный вызов через демона
таймеров — на нём стоит xEventGroupSetBitsFromISR.
#define configUSE_PREEMPTION 1
#define configUSE_IDLE_HOOK 0
#define configUSE_TICK_HOOK 0
#define configUSE_16_BIT_TICKS 0
#define configCPU_CLOCK_HZ 72000000u
#define configTICK_RATE_HZ 1000u
#define configMAX_PRIORITIES 5
#define configMINIMAL_STACK_SIZE 128
#define configTOTAL_HEAP_SIZE (10 * 1024)
#define configUSE_MUTEXES 1
#define configUSE_RECURSIVE_MUTEXES 1
#define configUSE_COUNTING_SEMAPHORES 1
#define configUSE_TIMERS 1
#define configTIMER_TASK_PRIORITY (configMAX_PRIORITIES - 1)
#define configTIMER_QUEUE_LENGTH 10
#define configTIMER_TASK_STACK_DEPTH 256
#define configSUPPORT_STATIC_ALLOCATION 1
#define configSUPPORT_DYNAMIC_ALLOCATION 1
#define configCHECK_FOR_STACK_OVERFLOW 2
#define configUSE_MALLOC_FAILED_HOOK 1
#define configUSE_TRACE_FACILITY 1
#define configQUEUE_REGISTRY_SIZE 8
#define configPRIO_BITS 4
#define configLIBRARY_LOWEST_INTERRUPT_PRIORITY 15
#define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY 5
#define configKERNEL_INTERRUPT_PRIORITY (configLIBRARY_LOWEST_INTERRUPT_PRIORITY << (8 - configPRIO_BITS))
#define configMAX_SYSCALL_INTERRUPT_PRIORITY (configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY << (8 - configPRIO_BITS))
#define configASSERT(x) if ((x) == 0) { taskDISABLE_INTERRUPTS(); for (;;); }
#define INCLUDE_vTaskDelay 1
#define INCLUDE_xTaskDelayUntil 1
#define INCLUDE_vTaskDelete 1
#define INCLUDE_vTaskSuspend 1
#define INCLUDE_uxTaskGetStackHighWaterMark 1
#define INCLUDE_xTaskGetSchedulerState 1
#define INCLUDE_vTaskPrioritySet 1
#define INCLUDE_uxTaskPriorityGet 1
#define INCLUDE_eTaskGetState 1
#define INCLUDE_xSemaphoreGetMutexHolder 1
#define INCLUDE_xTimerPendFunctionCall 1
#define vPortSVCHandler SVC_Handler
#define xPortPendSVHandler PendSV_Handler
#define xPortSysTickHandler SysTick_Handler
Три последние строки отдают ядру SVC, PendSV и SysTick (раздел 24.4,
шаг 1) и в таком виде годятся для проекта на регистрах. В проекте с HAL
заготовки этих обработчиков уже лежат в stm32f1xx_it.c (у F4 —
stm32f4xx_it.c), и их убирают. Но в заготовке SysTick_Handler стоит
HAL_IncTick: без него встанут HAL_Delay и тайм-ауты HAL. Поэтому тик HAL
переводят на свободный таймер своей HAL_InitTick. Образец лежит в самом HAL:
stm32f1xx_hal_timebase_tim_template.c на TIM2, у F4 такой же файл — на TIM6.
В примерах ST с FreeRTOS сделано так же, только третья строка там
закомментирована, а свой SysTick_Handler вызывает обработчик ядра.