Многие аспекты ядра могут настраиваться, и параметры конфигурации упоминаются там, где это применимо.
Запуск системы
Поскольку основная функция main()
больше не является потоком, RTX5 не мешает запуску системы до тех пор, пока не будет достигнута основная функция main()
. Как только запуск достигнет основной функции main()
, рекомендуется выполнить инициализацию аппаратного обеспечения и запустить ядро. Это также отражено в файле шаблона кода пользователя «Основная функция» CMSIS-RTOS2, поставляемом с компонентом RTX5.
Основная функция main()
в вашем приложении должна реализовать как минимум следующие действия:
- Инициализация и настройка аппаратных средств включающая периферию, память, пины микроконтроллера, систему тактирования и прерывания.
- Обновить систему тактирования ядра используя соотвествующую CMSIS-Core (Cortex-M) или CMSIS-Core (Cortex-A) функцию.
- Инициализировать ядро CMSIS-RTOS используя osKernelInitialize.
- Опционально, создать новый поток
app_main
, который используется как главный поток используя osThreadNew. Альтернативно, потоки можно создавать вmain()
напрямую. - Запустите планировщик RTOS используя функци osKernelStart. Эта функция не возвращается в случае успешного выполнения. Любой код приложения написанный после osKernelStart не будет исполнен, кроме случая когда osKernelStart не запуститься.
- Примечание
- Прерывания (например SVC) используемые ядром инициализируются в osKernelInitialize. Если приоритеты или группы NVIC будут изменены приложением после указанной выше последовательности, может потребоваться новый вызов фукнции osKernelInitialize. Вы можете это наблюдать например получая события osRtxErrorNotify или события вызывающие серьезные ошибки типо HARD FAULT.
- Таймер тиков настраивается в функции osKernelStart.
- Интервал тиков рассчитывается на основе переменной
SystemCoreClock
.
Scheduler (планировщик)
RTX5 реализует вытесняющий планировщик с минимальной задержкой (низкая латентность). Основные части RTX5 выполняются в режиме обработчика, такие как:
- SysTick_Handler используется для планирования времени.
- SVC_Handler используется для планирования на основе блокировки.
- PendSV_Handler используется для планирования на основе прерываний.
In order to be low-latency with respect to ISR execution those system exceptions are configured to use the lowest priority groups available. The priorities are configured such that no preemption happens between them. Thus no interrupt critical sections (i.e. interrupt locks) are needed to protect the scheduler.
Планирование потоков и выполнение прерываний
Планировщик объединяет приоритетное и циклическое переключение контекста.
На маркере 4 происходит прерывание (ISR) и вытесняет SysTick_Handler. RTX не добавляет задержки на выполнение службы прерывания. The ISR routine uses an RTOS-call that unblocks thread 4. Instead of switching to thread 4 immediately the PendSV flag is set to defer the context switching. The PendSV_Handler is executed right after the SysTick_Handler returns and the defered context switch to thread 4 is carried out. As soon as highest priority thread 4 blocks again by using a blocking RTOS-call execution is switched back to thread 3 immidiately during time index 5.
At time index 5 thread 3 uses a blocking RTOS-call as well. Thus the scheduler switches back to thread 2 for time index 6. At time index 7 the scheduler uses the round-robin mechanism to switch to thread 1 and so on.
Memory Allocation (выделение памяти)
Объекты RTX5 (поток, мьютекс, семафор, таймер, очередь сообщений, флаги потоков и событий, а также пул памяти) требуют выделения оперативной памяти ОЗУ. Объекты могут быть созданы с помощью вызова osObjectNew() и удалены с помощью вызова osObjectDelete(). Выделенная память объекта должна быть доступна в течение всего жизненного цикла объекта.
RTX5 предлагает три различных способа выделения памяти для объектов:
- Глобальный пул памяти использует один глобальный пул памяти для всех объектов. Его легко настроить, но может иметь недостаток в фрагментации памяти, когда объекты с разными размерами создаются и уничтожаются.
- Обьектно-ориентированный пул памяти использует пул памяти фиксированного размера для каждого типа объекта. Метод является детерминированным по времени и позволяет избежать фрагментации памяти.
- Static Object Memory резервирует память во время компиляции и полностью избегает того, что системе может не хватить памяти. Обычно это требуется для безопасности некоторых критически важных систем.
Можно смешивать все методы выделения памяти в одном приложении.
Global Memory Pool (глобальный пул памяти)
Глобальный пул памяти выделяет все объекты из области памяти. Этот метод выделения памяти является настройкой конфигурации RTX5 по умолчанию.
Глобальный пул памяти для всех объектов
Когда пул памяти не обеспечивает достаточную память, создание объекта завершается сбоем, а связанная с ним функция osObjectNew() возвращает NULL.
Включено в Настройка системы.
Object-specific Memory Pools (обьектно-ориентированный пул памяти)
Объектно-ориентированные пулы памяти позволяют избежать фрагментации памяти с помощью специального управления памятью фиксированного размера для каждого типа объекта. Этот тип пула памяти полностью детерминирован по времени, это означает, что создание и уничтожение объектов всегда имеют одинаковую фиксированную величину времени. Поскольку пул памяти фиксированного размера специфичен для типа объекта, упрощается обработка ситуаций с нехваткой памяти.
Объектно-ориентированные пулы памяти выборочно активируются для каждого типа объекта, например: мьютекс или поток, используя файл конфигурации RTX:
- Enabled in Thread Configuration for thread objects.
- Enabled in Timer Configuration for timer objects.
- Enabled in Event Flags Configuration for event objects.
- Enabled in Mutex Configuration for mutex objects.
- Enabled in Semaphore Configuration for semaphore.
- Enabled in Memory Pool Configuration for memory pools.
- Enabled in Message Queue Configuration for message objects.
Когда пул памяти не обеспечивает достаточную память, создание объекта завершается сбоем, а связанная с ним функция osObjectNew() возвращает NULL.
Static Object Memory (статическая память)
В отличии от динамической памяти, статическая память требует выделения памяти во время компиляции.
In order to allow RTX5 aware debugging, i.e. Component Viewer, to recognize control blocks these needs to be placed in individual memory sections, i.e. using __attribute__((section(...)))
.
RTX Object | Linker Section |
---|---|
Thread | .bss.os.thread.cb |
Timer | .bss.os.timer.cb |
Event Flags | .bss.os.evflags.cb |
Mutex | .bss.os.mutex.cb |
Semaphore | .bss.os.semaphore.cb |
Memory Pool | .bss.os.mempool.cb |
Message Queue | .bss.os.msgqueue.cb |
В следующем примере кода показано, как создать объект ОС с использованием статической памяти.
Пример кода:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 | /*---------------------------------------------------------------------------- * CMSIS-RTOS 'main' function template *---------------------------------------------------------------------------*/ #include "RTE_Components.h" #include CMSIS_device_header #include "cmsis_os2.h" //include rtx_os.h for types of RTX objects #include "rtx_os.h" //The thread function instanced in this example void worker(void *arg) { while(1) { //work osDelay(10000); } } // Define objects that are statically allocated for worker thread 1 __attribute__((section(".bss.os.thread.cb"))) osRtxThread_t worker_thread_tcb_1; // Reserve two areas for the stacks of worker thread 1 // uint64_t makes sure the memory alignment is 8 uint64_t worker_thread_stk_1[64]; // Define the attributes which are used for thread creation // Optional const saves RAM memory and includes the values in periodic ROM tests const osThreadAttr_t worker_attr_1 = { "wrk1", osThreadJoinable, &worker_thread_tcb_1, sizeof(worker_thread_tcb_1), &worker_thread_stk_1[0], sizeof(worker_thread_stk_1), osPriorityAboveNormal, 0 }; // Define ID object for thread osThreadId_t th1; /*---------------------------------------------------------------------------- * Application main thread *---------------------------------------------------------------------------*/ void app_main (void *argument) { uint32_t param = NULL; // Create an instance of the worker thread with static resources (TCB and stack) th1 = osThreadNew(worker, ¶m, &worker_attr_1); for (;;) {} } int main (void) { // System Initialization SystemCoreClockUpdate(); // ... osKernelInitialize(); // Initialize CMSIS-RTOS osThreadNew(app_main, NULL, NULL); // Create application main thread osKernelStart(); // Start thread execution for (;;) {} } |
Thread Stack Management (управление стеком потока)
Для процессоров Cortex-M без блока с плавающей точкой контекст потока требует 64 байта в локальном стеке.
- Примечание
- Для Cortex-M4 / M7 с плавающей точкой контекст потока требует 200 байт в локальном стеке. Для этих устройств пространство стека по умолчанию должно быть увеличено до минимума 300 байтов.
Каждый поток имеет отдельный стек, который содержит контекст потока и пространство стека для автоматических переменных и возвращаемые адреса для вложенных функций. Размеры стека для потоков RTX гибко настраивается, как описано в разделе Конфигурация потоков. RTX предлагает настраиваемую проверку переполнения стека и использования стека.
Low-Power Operation (работа с низким энергопотреблением)
Системный поток osRtxIdleThread может использоваться для переключения системы в режим с низким энергопотреблением. Самый простой способ войти в режим с низким энергопотреблением — это выполнение функции __WFE, которая переводит процессор в спящий режим, где он ждет события.
Пример кода:
1 2 3 4 5 6 7 8 9 10 11 | #include "RTE_Components.h" #include CMSIS_device_header /* Device definitions */ void osRtxIdleThread (void) { /* The idle demon is a system thread, running when no other thread is */ /* ready to run. */ for (;;) { __WFE(); /* Enter sleep mode */ } } |
RTX Kernel Timer Tick
RTX uses the generic OS Tick API to configure and control its periodic Kernel Tick.
To use an alternative timer as the Kernel Tick Timer one simply needs to implement a custom version of the OS Tick API.
- Note
- The OS Tick implementation provided must asure that the used timer interrupt uses the same (low) priority group as the service interrupts, i.e. interrupts used by RTX must not preempt each other. Refer to the Scheduler section for more details.
Tick-less Low-Power Operation
RTX5 provides extension for tick-less operation which is useful for applications that use extensively low-power modes where the SysTick timer is also disabled. To provide a time-tick in such power-saving modes, a wake-up timer is used to derive timer intervals. The CMSIS-RTOS2 functions osKernelSuspend and osKernelResume control the tick-less operation.
Using this functions allows the RTX5 thread scheduler to stop the periodic kernel tick interrupt. When all active threads are suspended, the system enters power-down and calculates how long it can stay in this power-down mode. In the power-down mode the processor and peripherals can be switched off. Only a wake-up timer must remain powered, because this timer is responsible to wake-up the system after the power-down period expires.
The tick-less operation is controlled from the osRtxIdleThread thread. The wake-up timeout value is set before the system enters the power-down mode. The function osKernelSuspend calculates the wake-up timeout measured in RTX Timer Ticks; this value is used to setup the wake-up timer that runs during the power-down mode of the system.
Once the system resumes operation (either by a wake-up time out or other interrupts) the RTX5 thread scheduler is started with the function osKernelResume. The parameter sleep_time specifies the time (in RTX Timer Ticks) that the system was in power-down mode.
Code Example:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 | #include "msp.h" // Device header /*---------------------------------------------------------------------------- * MSP432 Low-Power Extension Functions *---------------------------------------------------------------------------*/ static void MSP432_LP_Entry(void) { /* Enable PCM rude mode, which allows to device to enter LPM3 without waiting for peripherals */ PCM->CTL1 = PCM_CTL1_KEY_VAL | PCM_CTL1_FORCE_LPM_ENTRY; /* Enable all SRAM bank retentions prior to going to LPM3 */ SYSCTL->SRAM_BANKRET |= SYSCTL_SRAM_BANKRET_BNK7_RET; __enable_interrupt(); NVIC_EnableIRQ(RTC_C_IRQn); /* Do not wake up on exit from ISR */ SCB->SCR |= SCB_SCR_SLEEPONEXIT_Msk; /* Setting the sleep deep bit */ SCB->SCR |= (SCB_SCR_SLEEPDEEP_Msk); } static volatile unsigned int tc; static volatile unsigned int tc_wakeup; void RTC_C_IRQHandler(void) { if (tc++ > tc_wakeup) { SCB->SCR &= ~SCB_SCR_SLEEPONEXIT_Msk; NVIC_DisableIRQ(RTC_C_IRQn); NVIC_ClearPendingIRQ(RTC_C_IRQn); return; } if (RTC_C->PS0CTL & RTC_C_PS0CTL_RT0PSIFG) { RTC_C->CTL0 = RTC_C_KEY_VAL; // Unlock RTC key protected registers RTC_C->PS0CTL &= ~RTC_C_PS0CTL_RT0PSIFG; RTC_C->CTL0 = 0; SCB->SCR |= (SCB_SCR_SLEEPDEEP_Msk); } } uint32_t g_enable_sleep = 0; void osRtxIdleThread (void) { for (;;) { tc_wakeup = osKernelSuspend(); /* Is there some time to sleep? */ if (tc_wakeup > 0) { tc = 0; /* Enter the low power state */ MSP432_LP_Entry(); __WFE(); } /* Adjust the kernel ticks with the amount of ticks slept */ osKernelResume (tc); } } |
- Note
__WFE()
is not available in every Arm Cortex-M implementation. Check device manuals for availability. The alternative using__WFI()
has other issues, please take note of http://www.keil.com/support/docs/3591.htm as well.
RTX5 Header File
Every implementation of the CMSIS-RTOS2 API can bring its own additional features. RTX5 adds a couple of functions for the idle more, for error notifications, and special system timer functions. It also is using macros for control block and memory sizes.
If you require some of the RTX specific functions in your application code, #include the header file rtx_os.h:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 | /* * Copyright (c) 2013-2018 ARM Limited. All rights reserved. * * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the License); you may * not use this file except in compliance with the License. * You may obtain a copy of the License at * * www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an AS IS BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * ----------------------------------------------------------------------------- * * Project: CMSIS-RTOS RTX * Title: RTX OS definitions * * ----------------------------------------------------------------------------- */ #ifndef RTX_OS_H_ #define RTX_OS_H_ #include <stdint.h> #include <stddef.h> #include "cmsis_os2.h" #ifdef __cplusplus extern "C" { #endif /// Kernel Information #define osRtxVersionAPI 20010002 ///< API version (2.1.2) #define osRtxVersionKernel 50030000 ///< Kernel version (5.3.0) #define osRtxKernelId "RTX V5.3.0" ///< Kernel identification string // ==== Common definitions ==== /// Object Identifier definitions #define osRtxIdInvalid 0x00U #define osRtxIdThread 0x01U #define osRtxIdTimer 0x02U #define osRtxIdEventFlags 0x03U #define osRtxIdMutex 0x04U #define osRtxIdSemaphore 0x05U #define osRtxIdMemoryPool 0x06U #define osRtxIdMessage 0x07U #define osRtxIdMessageQueue 0x08U /// Object State definitions (except for Threads and Timers) #define osRtxObjectInactive 0x00U #define osRtxObjectActive 0x01U /// Object Flags definitions #define osRtxFlagSystemObject 0x01U #define osRtxFlagSystemMemory 0x02U // ==== Kernel definitions ==== /// Kernel State definitions #define osRtxKernelInactive ((uint8_t)osKernelInactive) #define osRtxKernelReady ((uint8_t)osKernelReady) #define osRtxKernelRunning ((uint8_t)osKernelRunning) #define osRtxKernelLocked ((uint8_t)osKernelLocked) #define osRtxKernelSuspended ((uint8_t)osKernelSuspended) // ==== Thread definitions ==== /// Thread State definitions (extending osThreadState) #define osRtxThreadStateMask 0x0FU #define osRtxThreadInactive ((uint8_t)osThreadInactive) #define osRtxThreadReady ((uint8_t)osThreadReady) #define osRtxThreadRunning ((uint8_t)osThreadRunning) #define osRtxThreadBlocked ((uint8_t)osThreadBlocked) #define osRtxThreadTerminated ((uint8_t)osThreadTerminated) #define osRtxThreadWaitingDelay ((uint8_t)(osRtxThreadBlocked | 0x10U)) #define osRtxThreadWaitingJoin ((uint8_t)(osRtxThreadBlocked | 0x20U)) #define osRtxThreadWaitingThreadFlags ((uint8_t)(osRtxThreadBlocked | 0x30U)) #define osRtxThreadWaitingEventFlags ((uint8_t)(osRtxThreadBlocked | 0x40U)) #define osRtxThreadWaitingMutex ((uint8_t)(osRtxThreadBlocked | 0x50U)) #define osRtxThreadWaitingSemaphore ((uint8_t)(osRtxThreadBlocked | 0x60U)) #define osRtxThreadWaitingMemoryPool ((uint8_t)(osRtxThreadBlocked | 0x70U)) #define osRtxThreadWaitingMessageGet ((uint8_t)(osRtxThreadBlocked | 0x80U)) #define osRtxThreadWaitingMessagePut ((uint8_t)(osRtxThreadBlocked | 0x90U)) /// Thread Flags definitions #define osRtxThreadFlagDefStack 0x10U ///< Default Stack flag /// Stack Marker definitions #define osRtxStackMagicWord 0xE25A2EA5U ///< Stack Magic Word (Stack Base) #define osRtxStackFillPattern 0xCCCCCCCCU ///< Stack Fill Pattern /// Thread Control Block typedef struct osRtxThread_s { uint8_t id; ///< Object Identifier uint8_t state; ///< Object State uint8_t flags; ///< Object Flags uint8_t attr; ///< Object Attributes const char *name; ///< Object Name struct osRtxThread_s *thread_next; ///< Link pointer to next Thread in Object list struct osRtxThread_s *thread_prev; ///< Link pointer to previous Thread in Object list struct osRtxThread_s *delay_next; ///< Link pointer to next Thread in Delay list struct osRtxThread_s *delay_prev; ///< Link pointer to previous Thread in Delay list struct osRtxThread_s *thread_join; ///< Thread waiting to Join uint32_t delay; ///< Delay Time int8_t priority; ///< Thread Priority int8_t priority_base; ///< Base Priority uint8_t stack_frame; ///< Stack Frame (EXC_RETURN[7..0]) uint8_t flags_options; ///< Thread/Event Flags Options uint32_t wait_flags; ///< Waiting Thread/Event Flags uint32_t thread_flags; ///< Thread Flags struct osRtxMutex_s *mutex_list; ///< Link pointer to list of owned Mutexes void *stack_mem; ///< Stack Memory uint32_t stack_size; ///< Stack Size uint32_t sp; ///< Current Stack Pointer uint32_t thread_addr; ///< Thread entry address uint32_t tz_memory; ///< TrustZone Memory Identifier } osRtxThread_t; // ==== Timer definitions ==== /// Timer State definitions #define osRtxTimerInactive 0x00U ///< Timer Inactive #define osRtxTimerStopped 0x01U ///< Timer Stopped #define osRtxTimerRunning 0x02U ///< Timer Running /// Timer Type definitions #define osRtxTimerPeriodic ((uint8_t)osTimerPeriodic) /// Timer Function Information typedef struct { osTimerFunc_t func; ///< Function Pointer void *arg; ///< Function Argument } osRtxTimerFinfo_t; /// Timer Control Block typedef struct osRtxTimer_s { uint8_t id; ///< Object Identifier uint8_t state; ///< Object State uint8_t flags; ///< Object Flags uint8_t type; ///< Timer Type (Periodic/One-shot) const char *name; ///< Object Name struct osRtxTimer_s *prev; ///< Pointer to previous active Timer struct osRtxTimer_s *next; ///< Pointer to next active Timer uint32_t tick; ///< Timer current Tick uint32_t load; ///< Timer Load value osRtxTimerFinfo_t finfo; ///< Timer Function Info } osRtxTimer_t; // ==== Event Flags definitions ==== /// Event Flags Control Block typedef struct { uint8_t id; ///< Object Identifier uint8_t state; ///< Object State uint8_t flags; ///< Object Flags uint8_t reserved; const char *name; ///< Object Name osRtxThread_t *thread_list; ///< Waiting Threads List uint32_t event_flags; ///< Event Flags } osRtxEventFlags_t; // ==== Mutex definitions ==== /// Mutex Control Block typedef struct osRtxMutex_s { uint8_t id; ///< Object Identifier uint8_t state; ///< Object State uint8_t flags; ///< Object Flags uint8_t attr; ///< Object Attributes const char *name; ///< Object Name osRtxThread_t *thread_list; ///< Waiting Threads List osRtxThread_t *owner_thread; ///< Owner Thread struct osRtxMutex_s *owner_prev; ///< Pointer to previous owned Mutex struct osRtxMutex_s *owner_next; ///< Pointer to next owned Mutex uint8_t lock; ///< Lock counter uint8_t padding[3]; } osRtxMutex_t; // ==== Semaphore definitions ==== /// Semaphore Control Block typedef struct { uint8_t id; ///< Object Identifier uint8_t state; ///< Object State uint8_t flags; ///< Object Flags uint8_t reserved; const char *name; ///< Object Name osRtxThread_t *thread_list; ///< Waiting Threads List uint16_t tokens; ///< Current number of tokens uint16_t max_tokens; ///< Maximum number of tokens } osRtxSemaphore_t; // ==== Memory Pool definitions ==== /// Memory Pool Information typedef struct { uint32_t max_blocks; ///< Maximum number of Blocks uint32_t used_blocks; ///< Number of used Blocks uint32_t block_size; ///< Block Size void *block_base; ///< Block Memory Base Address void *block_lim; ///< Block Memory Limit Address void *block_free; ///< First free Block Address } osRtxMpInfo_t; /// Memory Pool Control Block typedef struct { uint8_t id; ///< Object Identifier uint8_t state; ///< Object State uint8_t flags; ///< Object Flags uint8_t reserved; const char *name; ///< Object Name osRtxThread_t *thread_list; ///< Waiting Threads List osRtxMpInfo_t mp_info; ///< Memory Pool Info } osRtxMemoryPool_t; // ==== Message Queue definitions ==== /// Message Control Block typedef struct osRtxMessage_s { uint8_t id; ///< Object Identifier uint8_t state; ///< Object State uint8_t flags; ///< Object Flags uint8_t priority; ///< Message Priority struct osRtxMessage_s *prev; ///< Pointer to previous Message struct osRtxMessage_s *next; ///< Pointer to next Message } osRtxMessage_t; /// Message Queue Control Block typedef struct { uint8_t id; ///< Object Identifier uint8_t state; ///< Object State uint8_t flags; ///< Object Flags uint8_t reserved; const char *name; ///< Object Name osRtxThread_t *thread_list; ///< Waiting Threads List osRtxMpInfo_t mp_info; ///< Memory Pool Info uint32_t msg_size; ///< Message Size uint32_t msg_count; ///< Number of queued Messages osRtxMessage_t *msg_first; ///< Pointer to first Message osRtxMessage_t *msg_last; ///< Pointer to last Message } osRtxMessageQueue_t; // ==== Generic Object definitions ==== /// Generic Object Control Block typedef struct { uint8_t id; ///< Object Identifier uint8_t state; ///< Object State uint8_t flags; ///< Object Flags uint8_t reserved; const char *name; ///< Object Name osRtxThread_t *thread_list; ///< Threads List } osRtxObject_t; // ==== OS Runtime Information definitions ==== /// OS Runtime Information structure typedef struct { const char *os_id; ///< OS Identification uint32_t version; ///< OS Version struct { ///< Kernel Info uint8_t state; ///< State volatile uint8_t blocked; ///< Blocked uint8_t pendSV; ///< Pending SV uint8_t reserved; uint32_t tick; ///< Tick counter } kernel; int32_t tick_irqn; ///< Tick Timer IRQ Number struct { ///< Thread Info struct { ///< Thread Run Info osRtxThread_t *curr; ///< Current running Thread osRtxThread_t *next; ///< Next Thread to Run } run; osRtxObject_t ready; ///< Ready List Object osRtxThread_t *idle; ///< Idle Thread osRtxThread_t *delay_list; ///< Delay List osRtxThread_t *wait_list; ///< Wait List (no Timeout) osRtxThread_t *terminate_list; ///< Terminate Thread List struct { ///< Thread Round Robin Info osRtxThread_t *thread; ///< Round Robin Thread uint32_t tick; ///< Round Robin Time Tick uint32_t timeout; ///< Round Robin Timeout } robin; } thread; struct { ///< Timer Info osRtxTimer_t *list; ///< Active Timer List osRtxThread_t *thread; ///< Timer Thread osRtxMessageQueue_t *mq; ///< Timer Message Queue void (*tick)(void); ///< Timer Tick Function } timer; struct { ///< ISR Post Processing Queue uint16_t max; ///< Maximum Items uint16_t cnt; ///< Item Count uint16_t in; ///< Incoming Item Index uint16_t out; ///< Outgoing Item Index void **data; ///< Queue Data } isr_queue; struct { ///< ISR Post Processing functions void (*thread)(osRtxThread_t*); ///< Thread Post Processing function void (*event_flags)(osRtxEventFlags_t*); ///< Event Flags Post Processing function void (*semaphore)(osRtxSemaphore_t*); ///< Semaphore Post Processing function void (*memory_pool)(osRtxMemoryPool_t*); ///< Memory Pool Post Processing function void (*message)(osRtxMessage_t*); ///< Message Post Processing function } post_process; struct { ///< Memory Pools (Variable Block Size) void *stack; ///< Stack Memory void *mp_data; ///< Memory Pool Data Memory void *mq_data; ///< Message Queue Data Memory void *common; ///< Common Memory } mem; struct { ///< Memory Pools (Fixed Block Size) osRtxMpInfo_t *stack; ///< Stack for Threads osRtxMpInfo_t *thread; ///< Thread Control Blocks osRtxMpInfo_t *timer; ///< Timer Control Blocks osRtxMpInfo_t *event_flags; ///< Event Flags Control Blocks osRtxMpInfo_t *mutex; ///< Mutex Control Blocks osRtxMpInfo_t *semaphore; ///< Semaphore Control Blocks osRtxMpInfo_t *memory_pool; ///< Memory Pool Control Blocks osRtxMpInfo_t *message_queue; ///< Message Queue Control Blocks } mpi; } osRtxInfo_t; extern osRtxInfo_t osRtxInfo; ///< OS Runtime Information /// OS Runtime Object Memory Usage structure typedef struct { uint32_t cnt_alloc; ///< Counter for alloc uint32_t cnt_free; ///< Counter for free uint32_t max_used; ///< Maximum used } osRtxObjectMemUsage_t; /// OS Runtime Object Memory Usage variables extern osRtxObjectMemUsage_t osRtxThreadMemUsage; extern osRtxObjectMemUsage_t osRtxTimerMemUsage; extern osRtxObjectMemUsage_t osRtxEventFlagsMemUsage; extern osRtxObjectMemUsage_t osRtxMutexMemUsage; extern osRtxObjectMemUsage_t osRtxSemaphoreMemUsage; extern osRtxObjectMemUsage_t osRtxMemoryPoolMemUsage; extern osRtxObjectMemUsage_t osRtxMessageQueueMemUsage; // ==== OS API definitions ==== /// Object Limits definitions #define osRtxThreadFlagsLimit 31U ///< number of Thread Flags available per thread #define osRtxEventFlagsLimit 31U ///< number of Event Flags available per object #define osRtxMutexLockLimit 255U ///< maximum number of recursive mutex locks #define osRtxSemaphoreTokenLimit 65535U ///< maximum number of tokens per semaphore /// Control Block sizes #define osRtxThreadCbSize sizeof(osRtxThread_t) #define osRtxTimerCbSize sizeof(osRtxTimer_t) #define osRtxEventFlagsCbSize sizeof(osRtxEventFlags_t) #define osRtxMutexCbSize sizeof(osRtxMutex_t) #define osRtxSemaphoreCbSize sizeof(osRtxSemaphore_t) #define osRtxMemoryPoolCbSize sizeof(osRtxMemoryPool_t) #define osRtxMessageQueueCbSize sizeof(osRtxMessageQueue_t) /// Memory size in bytes for Memory Pool storage. /// \param block_count maximum number of memory blocks in memory pool. /// \param block_size memory block size in bytes. #define osRtxMemoryPoolMemSize(block_count, block_size) \ (4*(block_count)*(((block_size)+3)/4)) /// Memory size in bytes for Message Queue storage. /// \param msg_count maximum number of messages in queue. /// \param msg_size maximum message size in bytes. #define osRtxMessageQueueMemSize(msg_count, msg_size) \ (4*(msg_count)*(3+(((msg_size)+3)/4))) // ==== OS External Functions ==== /// OS Error Codes #define osRtxErrorStackUnderflow 1U ///< Stack overflow, i.e. stack pointer below its lower memory limit for descending stacks. #define osRtxErrorISRQueueOverflow 2U ///< ISR Queue overflow detected when inserting object. #define osRtxErrorTimerQueueOverflow 3U ///< User Timer Callback Queue overflow detected for timer. #define osRtxErrorClibSpace 4U ///< Standard C/C++ library libspace not available: increase \c OS_THREAD_LIBSPACE_NUM. #define osRtxErrorClibMutex 5U ///< Standard C/C++ library mutex initialization failed. /// OS Error Callback function extern uint32_t osRtxErrorNotify (uint32_t code, void *object_id); /// OS Idle Thread extern void osRtxIdleThread (void *argument); /// OS Exception handlers extern void SVC_Handler (void); extern void PendSV_Handler (void); extern void SysTick_Handler (void); // ==== OS External Configuration ==== /// OS Configuration flags #define osRtxConfigPrivilegedMode (1UL<<0) ///< Threads in Privileged mode #define osRtxConfigStackCheck (1UL<<1) ///< Stack overrun checking #define osRtxConfigStackWatermark (1UL<<2) ///< Stack usage Watermark /// OS Configuration structure typedef struct { uint32_t flags; ///< OS Configuration Flags uint32_t tick_freq; ///< Kernel Tick Frequency uint32_t robin_timeout; ///< Round Robin Timeout Tick struct { ///< ISR Post Processing Queue void **data; ///< Queue Data uint16_t max; ///< Maximum Items uint16_t padding; } isr_queue; struct { ///< Memory Pools (Variable Block Size) void *stack_addr; ///< Stack Memory Address uint32_t stack_size; ///< Stack Memory Size void *mp_data_addr; ///< Memory Pool Memory Address uint32_t mp_data_size; ///< Memory Pool Memory Size void *mq_data_addr; ///< Message Queue Data Memory Address uint32_t mq_data_size; ///< Message Queue Data Memory Size void *common_addr; ///< Common Memory Address uint32_t common_size; ///< Common Memory Size } mem; struct { ///< Memory Pools (Fixed Block Size) osRtxMpInfo_t *stack; ///< Stack for Threads osRtxMpInfo_t *thread; ///< Thread Control Blocks osRtxMpInfo_t *timer; ///< Timer Control Blocks osRtxMpInfo_t *event_flags; ///< Event Flags Control Blocks osRtxMpInfo_t *mutex; ///< Mutex Control Blocks osRtxMpInfo_t *semaphore; ///< Semaphore Control Blocks osRtxMpInfo_t *memory_pool; ///< Memory Pool Control Blocks osRtxMpInfo_t *message_queue; ///< Message Queue Control Blocks } mpi; uint32_t thread_stack_size; ///< Default Thread Stack Size const osThreadAttr_t *idle_thread_attr; ///< Idle Thread Attributes const osThreadAttr_t *timer_thread_attr; ///< Timer Thread Attributes const osMessageQueueAttr_t *timer_mq_attr; ///< Timer Message Queue Attributes uint32_t timer_mq_mcnt; ///< Timer Message Queue maximum Messages } osRtxConfig_t; extern const osRtxConfig_t osRtxConfig; ///< OS Configuration #ifdef __cplusplus } #endif #endif // RTX_OS_H_ |
Timeout Value
Timeout values are an argument to several osXxx functions to allow time for resolving a request. A timeout value of 0 means that the RTOS does not wait and the function returns instantly, even when no resource is available. A timeout value of osWaitForever means that the RTOS waits infinitely until a resource becomes available. Or one forces the thread to resume using osThreadResume which is discouraged.
The timeout value specifies the number of timer ticks until the time delay elapses. The value is an upper bound and depends on the actual time elapsed since the last timer tick.
Examples:
- timeout value 0 : the system does not wait, even when no resource is available the RTOS function returns instantly.
- timeout value 1 : the system waits until the next timer tick occurs; depending on the previous timer tick, it may be a very short wait time.
- timeout value 2 : actual wait time is between 1 and 2 timer ticks.
- timeout value osWaitForever : system waits infinite until a resource becomes available.
Calls from Interrupt Service Routines
The following CMSIS-RTOS2 functions can be called from threads and Interrupt Service Routines (ISR):
- osKernelGetInfo, osKernelGetState, osKernelGetTickCount, osKernelGetTickFreq, osKernelGetSysTimerCount, osKernelGetSysTimerFreq
- osThreadFlagsSet
- osEventFlagsSet, osEventFlagsClear, osEventFlagsGet, osEventFlagsWait
- osSemaphoreAcquire, osSemaphoreRelease, osSemaphoreGetCount
- osMemoryPoolAlloc, osMemoryPoolFree, osMemoryPoolGetCapacity, osMemoryPoolGetBlockSize, osMemoryPoolGetCount, osMemoryPoolGetSpace
- osMessageQueuePut, osMessageQueueGet, osMessageQueueGetCapacity, osMessageQueueGetMsgSize, osMessageQueueGetCount, osMessageQueueGetSpace
Functions that cannot be called from an ISR are verifying the interrupt status and return the status code osErrorISR, in case they are called from an ISR context. In some implementations, this condition might be caught using the HARD_FAULT vector.
Оставить ответ
Вы должны быть авторизованы чтобы размещать комментарии.