os_port_cmsis_rtos.c
Go to the documentation of this file.
1 /**
2  * @file os_port_cmsis_rtos.c
3  * @brief RTOS abstraction layer (CMSIS-RTOS)
4  *
5  * @section License
6  *
7  * SPDX-License-Identifier: GPL-2.0-or-later
8  *
9  * Copyright (C) 2010-2024 Oryx Embedded SARL. All rights reserved.
10  *
11  * This program is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU General Public License
13  * as published by the Free Software Foundation; either version 2
14  * of the License, or (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software Foundation,
23  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
24  *
25  * @author Oryx Embedded SARL (www.oryx-embedded.com)
26  * @version 2.4.4
27  **/
28 
29 //Switch to the appropriate trace level
30 #define TRACE_LEVEL TRACE_LEVEL_OFF
31 
32 //Dependencies
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include "os_port.h"
36 #include "os_port_cmsis_rtos.h"
37 #include "debug.h"
38 
39 //Default task parameters
41 {
42  256, //Size of the stack
43  osPriorityNormal //Task priority
44 };
45 
46 
47 /**
48  * @brief Kernel initialization
49  **/
50 
51 void osInitKernel(void)
52 {
53 #if (osCMSIS >= 0x10001)
54  //Initialize the kernel
55  osKernelInitialize();
56 #endif
57 }
58 
59 
60 /**
61  * @brief Start kernel
62  **/
63 
64 void osStartKernel(void)
65 {
66 #if (osCMSIS >= 0x10001)
67  //Start the kernel
68  osKernelStart();
69 #else
70  //Start the kernel
71  osKernelStart(NULL, NULL);
72 #endif
73 }
74 
75 
76 /**
77  * @brief Create a task
78  * @param[in] name NULL-terminated string identifying the task
79  * @param[in] taskCode Pointer to the task entry function
80  * @param[in] arg Argument passed to the task function
81  * @param[in] params Task parameters
82  * @return Task identifier referencing the newly created task
83  **/
84 
85 OsTaskId osCreateTask(const char_t *name, OsTaskCode taskCode, void *arg,
86  const OsTaskParameters *params)
87 {
88  osThreadId threadId;
89  osThreadDef_t threadDef;
90 
91  //Initialize thread parameters
92  memset(&threadDef, 0, sizeof(threadDef));
93 
94  //Set thread parameters
95 #if defined(osCMSIS_RTX) && (osCMSIS_RTX < 0x50000)
96  threadDef.pthread = (os_pthread) taskCode;
97  threadDef.tpriority = (osPriority) params->priority;
98  threadDef.instances = 1;
99  threadDef.stacksize = params->stackSize * sizeof(uint32_t);
100 #elif defined(osCMSIS_RTX) && (osCMSIS_RTX >= 0x50000)
101  threadDef.pthread = (os_pthread) taskCode;
102  threadDef.attr.name = name;
103  threadDef.attr.attr_bits = 0;
104  threadDef.attr.cb_mem = NULL;
105  threadDef.attr.cb_size = 0;
106  threadDef.attr.stack_mem = NULL;
107  threadDef.attr.stack_size = params->stackSize * sizeof(uint32_t);
108  threadDef.attr.priority = (osPriority_t) params->priority;
109  threadDef.attr.tz_module = 0;
110 #elif defined(osCMSIS_FreeRTOS)
111  threadDef.pthread = (os_pthread) taskCode;
112  threadDef.attr.name = name;
113  threadDef.attr.attr_bits = 0;
114  threadDef.attr.cb_mem = NULL;
115  threadDef.attr.cb_size = 0;
116  threadDef.attr.stack_mem = NULL;
117  threadDef.attr.stack_size = params->stackSize * sizeof(uint32_t);
118  threadDef.attr.priority = (osPriority_t) params->priority;
119  threadDef.attr.tz_module = 0;
120 #else
121  threadDef.name = (char_t *) name;
122  threadDef.pthread = (os_pthread) taskCode;
123  threadDef.tpriority = (osPriority) params->priority;
124  threadDef.instances = 1;
125  threadDef.stacksize = params->stackSize;
126 #endif
127 
128  //Create a new thread
129  threadId = osThreadCreate(&threadDef, arg);
130 
131  //Return the handle referencing the newly created thread
132  return (OsTaskId) threadId;
133 }
134 
135 
136 /**
137  * @brief Delete a task
138  * @param[in] taskId Task identifier referencing the task to be deleted
139  **/
140 
141 void osDeleteTask(OsTaskId taskId)
142 {
143 #if (osCMSIS >= 0x20000)
144  //Delete the specified thread
145  if(taskId == OS_SELF_TASK_ID)
146  {
147  osThreadExit();
148  }
149  else
150  {
151  osThreadTerminate((osThreadId_t) taskId);
152  }
153 #else
154  //Delete the specified thread
155  osThreadTerminate((osThreadId) taskId);
156 #endif
157 }
158 
159 
160 /**
161  * @brief Delay routine
162  * @param[in] delay Amount of time for which the calling task should block
163  **/
164 
166 {
167  //Delay the thread for the specified duration
168  osDelay(delay);
169 }
170 
171 
172 /**
173  * @brief Yield control to the next task
174  **/
175 
176 void osSwitchTask(void)
177 {
178  //Force a context switch
179  osThreadYield();
180 }
181 
182 
183 /**
184  * @brief Suspend scheduler activity
185  **/
186 
188 {
189 #if defined(osCMSIS_RTX) || defined(osCMSIS_FreeRTOS)
190  //Not implemented
191 #else
192  //Make sure the operating system is running
193  if(osKernelRunning())
194  {
195  //Suspend all threads
196  osThreadSuspendAll();
197  }
198 #endif
199 }
200 
201 
202 /**
203  * @brief Resume scheduler activity
204  **/
205 
207 {
208 #if defined(osCMSIS_RTX) || defined(osCMSIS_FreeRTOS)
209  //Not implemented
210 #else
211  //Make sure the operating system is running
212  if(osKernelRunning())
213  {
214  //Resume all threads
215  osThreadResumeAll();
216  }
217 #endif
218 }
219 
220 
221 /**
222  * @brief Create an event object
223  * @param[in] event Pointer to the event object
224  * @return The function returns TRUE if the event object was successfully
225  * created. Otherwise, FALSE is returned
226  **/
227 
229 {
230  osSemaphoreDef_t semaphoreDef;
231 
232 #if defined(osCMSIS_RTX) && (osCMSIS_RTX < 0x50000)
233  semaphoreDef.semaphore = event->cb;
234 #elif defined(osCMSIS_RTX) && (osCMSIS_RTX >= 0x50000)
235  semaphoreDef.name = NULL;
236  semaphoreDef.attr_bits = 0;
237  semaphoreDef.cb_mem = NULL;
238  semaphoreDef.cb_size = 0;
239 #elif defined(osCMSIS_FreeRTOS)
240  semaphoreDef.name = NULL;
241  semaphoreDef.attr_bits = 0;
242  semaphoreDef.cb_mem = NULL;
243  semaphoreDef.cb_size = 0;
244 #else
245  semaphoreDef.dummy = 0;
246 #endif
247 
248  //Create a binary semaphore object
249  event->id = osSemaphoreCreate(&semaphoreDef, 1);
250 
251  //Check whether the returned semaphore ID is valid
252  if(event->id != NULL)
253  {
254  //Force the specified event to the nonsignaled state
255  osSemaphoreWait(event->id, 0);
256  //Event successfully created
257  return TRUE;
258  }
259  else
260  {
261  //Failed to create event object
262  return FALSE;
263  }
264 }
265 
266 
267 /**
268  * @brief Delete an event object
269  * @param[in] event Pointer to the event object
270  **/
271 
272 void osDeleteEvent(OsEvent *event)
273 {
274  //Make sure the semaphore ID is valid
275  if(event->id != NULL)
276  {
277  //Properly dispose the event object
278  osSemaphoreDelete(event->id);
279  }
280 }
281 
282 
283 /**
284  * @brief Set the specified event object to the signaled state
285  * @param[in] event Pointer to the event object
286  **/
287 
288 void osSetEvent(OsEvent *event)
289 {
290  //Set the specified event to the signaled state
291  osSemaphoreRelease(event->id);
292 }
293 
294 
295 /**
296  * @brief Set the specified event object to the nonsignaled state
297  * @param[in] event Pointer to the event object
298  **/
299 
300 void osResetEvent(OsEvent *event)
301 {
302 #if defined(osCMSIS_RTX) && (osCMSIS_RTX < 0x50000)
303  //Force the specified event to the nonsignaled state
304  while(osSemaphoreWait(event->id, 0) > 0)
305  {
306  }
307 #else
308  //Force the specified event to the nonsignaled state
309  osSemaphoreWait(event->id, 0);
310 #endif
311 }
312 
313 
314 /**
315  * @brief Wait until the specified event is in the signaled state
316  * @param[in] event Pointer to the event object
317  * @param[in] timeout Timeout interval
318  * @return The function returns TRUE if the state of the specified object is
319  * signaled. FALSE is returned if the timeout interval elapsed
320  **/
321 
323 {
324  int32_t ret;
325 
326  //Wait until the specified event is in the signaled state or the timeout
327  //interval elapses
328  if(timeout == INFINITE_DELAY)
329  {
330  //Infinite timeout period
331  ret = osSemaphoreWait(event->id, osWaitForever);
332  }
333  else
334  {
335 #if defined(osCMSIS_RTX) && (osCMSIS_RTX < 0x50000)
336  systime_t n;
337 
338  //Loop until the assigned time period has elapsed
339  do
340  {
341  //Limit the timeout value
342  n = MIN(timeout, 10000);
343  //Wait for the specified time interval
344  ret = osSemaphoreWait(event->id, n);
345  //Decrement timeout value
346  timeout -= n;
347 
348  //Check timeout value
349  } while(ret == 0 && timeout > 0);
350 #else
351  //Wait for the specified time interval
352  ret = osSemaphoreWait(event->id, timeout);
353 #endif
354  }
355 
356 #if defined(osCMSIS_RTX) && (osCMSIS_RTX < 0x50000)
357  //Check return value
358  if(ret > 0)
359  {
360  //Force the event back to the nonsignaled state
361  while(osSemaphoreWait(event->id, 0) > 0)
362  {
363  }
364 
365  //The specified event is in the signaled state
366  return TRUE;
367  }
368  else
369  {
370  //The timeout interval elapsed
371  return FALSE;
372  }
373 #elif defined(osCMSIS_RTX) && (osCMSIS_RTX >= 0x50000)
374  //Check return value
375  if(ret > 0)
376  {
377  return TRUE;
378  }
379  else
380  {
381  return FALSE;
382  }
383 #elif defined(osCMSIS_FreeRTOS)
384  //Check return value
385  if(ret > 0)
386  {
387  return TRUE;
388  }
389  else
390  {
391  return FALSE;
392  }
393 #else
394  //Check return value
395  if(ret == osOK)
396  {
397  return TRUE;
398  }
399  else
400  {
401  return FALSE;
402  }
403 #endif
404 }
405 
406 
407 /**
408  * @brief Set an event object to the signaled state from an interrupt service routine
409  * @param[in] event Pointer to the event object
410  * @return TRUE if setting the event to signaled state caused a task to unblock
411  * and the unblocked task has a priority higher than the currently running task
412  **/
413 
415 {
416  //Set the specified event to the signaled state
417  osSemaphoreRelease(event->id);
418 
419  //The return value is not relevant
420  return FALSE;
421 }
422 
423 
424 /**
425  * @brief Create a semaphore object
426  * @param[in] semaphore Pointer to the semaphore object
427  * @param[in] count The maximum count for the semaphore object. This value
428  * must be greater than zero
429  * @return The function returns TRUE if the semaphore was successfully
430  * created. Otherwise, FALSE is returned
431  **/
432 
434 {
435  osSemaphoreDef_t semaphoreDef;
436 
437 #if defined(osCMSIS_RTX) && (osCMSIS_RTX < 0x50000)
438  semaphoreDef.semaphore = semaphore->cb;
439 #elif defined(osCMSIS_RTX) && (osCMSIS_RTX >= 0x50000)
440  semaphoreDef.name = NULL;
441  semaphoreDef.attr_bits = 0;
442  semaphoreDef.cb_mem = NULL;
443  semaphoreDef.cb_size = 0;
444 #elif defined(osCMSIS_FreeRTOS)
445  semaphoreDef.name = NULL;
446  semaphoreDef.attr_bits = 0;
447  semaphoreDef.cb_mem = NULL;
448  semaphoreDef.cb_size = 0;
449 #else
450  semaphoreDef.dummy = 0;
451 #endif
452 
453  //Create a semaphore object
454  semaphore->id = osSemaphoreCreate(&semaphoreDef, count);
455 
456  //Check whether the returned semaphore ID is valid
457  if(semaphore->id != NULL)
458  {
459  return TRUE;
460  }
461  else
462  {
463  return FALSE;
464  }
465 }
466 
467 
468 /**
469  * @brief Delete a semaphore object
470  * @param[in] semaphore Pointer to the semaphore object
471  **/
472 
474 {
475  //Make sure the semaphore ID is valid
476  if(semaphore->id != NULL)
477  {
478  //Properly dispose the specified semaphore
479  osSemaphoreDelete(semaphore->id);
480  }
481 }
482 
483 
484 /**
485  * @brief Wait for the specified semaphore to be available
486  * @param[in] semaphore Pointer to the semaphore object
487  * @param[in] timeout Timeout interval
488  * @return The function returns TRUE if the semaphore is available. FALSE is
489  * returned if the timeout interval elapsed
490  **/
491 
493 {
494  int32_t ret;
495 
496  //Wait until the semaphore is available or the timeout interval elapses
497  if(timeout == INFINITE_DELAY)
498  {
499  //Infinite timeout period
500  ret = osSemaphoreWait(semaphore->id, osWaitForever);
501  }
502  else
503  {
504 #if defined(osCMSIS_RTX) && (osCMSIS_RTX < 0x50000)
505  systime_t n;
506 
507  //Loop until the assigned time period has elapsed
508  do
509  {
510  //Limit the timeout value
511  n = MIN(timeout, 10000);
512  //Wait for the specified time interval
513  ret = osSemaphoreWait(semaphore->id, n);
514  //Decrement timeout value
515  timeout -= n;
516 
517  //Check timeout value
518  } while(ret == 0 && timeout > 0);
519 #else
520  //Wait for the specified time interval
521  ret = osSemaphoreWait(semaphore->id, timeout);
522 #endif
523  }
524 
525 #if defined(osCMSIS_RTX) || defined(osCMSIS_FreeRTOS)
526  //Check return value
527  if(ret > 0)
528  {
529  return TRUE;
530  }
531  else
532  {
533  return FALSE;
534  }
535 #else
536  //Check return value
537  if(ret == osOK)
538  {
539  return TRUE;
540  }
541  else
542  {
543  return FALSE;
544  }
545 #endif
546 }
547 
548 
549 /**
550  * @brief Release the specified semaphore object
551  * @param[in] semaphore Pointer to the semaphore object
552  **/
553 
555 {
556  //Release the semaphore
557  osSemaphoreRelease(semaphore->id);
558 }
559 
560 
561 /**
562  * @brief Create a mutex object
563  * @param[in] mutex Pointer to the mutex object
564  * @return The function returns TRUE if the mutex was successfully
565  * created. Otherwise, FALSE is returned
566  **/
567 
569 {
570  osMutexDef_t mutexDef;
571 
572 #if defined(osCMSIS_RTX) && (osCMSIS_RTX < 0x50000)
573  mutexDef.mutex = mutex->cb;
574 #elif defined(osCMSIS_RTX) && (osCMSIS_RTX >= 0x50000)
575  mutexDef.name = NULL;
576  mutexDef.attr_bits = 0;
577  mutexDef.cb_mem = NULL;
578  mutexDef.cb_size = 0;
579 #elif defined(osCMSIS_FreeRTOS)
580  mutexDef.name = NULL;
581  mutexDef.attr_bits = 0;
582  mutexDef.cb_mem = NULL;
583  mutexDef.cb_size = 0;
584 #else
585  mutexDef.dummy = 0;
586 #endif
587 
588  //Create a mutex object
589  mutex->id = osMutexCreate(&mutexDef);
590 
591  //Check whether the returned mutex ID is valid
592  if(mutex->id != NULL)
593  {
594  return TRUE;
595  }
596  else
597  {
598  return FALSE;
599  }
600 }
601 
602 
603 /**
604  * @brief Delete a mutex object
605  * @param[in] mutex Pointer to the mutex object
606  **/
607 
608 void osDeleteMutex(OsMutex *mutex)
609 {
610  //Make sure the mutex ID is valid
611  if(mutex->id != NULL)
612  {
613  //Properly dispose the specified mutex
614  osMutexDelete(mutex->id);
615  }
616 }
617 
618 
619 /**
620  * @brief Acquire ownership of the specified mutex object
621  * @param[in] mutex Pointer to the mutex object
622  **/
623 
625 {
626  //Obtain ownership of the mutex object
627  osMutexWait(mutex->id, osWaitForever);
628 }
629 
630 
631 /**
632  * @brief Release ownership of the specified mutex object
633  * @param[in] mutex Pointer to the mutex object
634  **/
635 
637 {
638  //Release ownership of the mutex object
639  osMutexRelease(mutex->id);
640 }
641 
642 
643 /**
644  * @brief Retrieve system time
645  * @return Number of milliseconds elapsed since the system was last started
646  **/
647 
649 {
650  systime_t time;
651 
652 #if defined(osCMSIS_RTX) && (osCMSIS_RTX < 0x50000)
653  //Forward function declaration
654  extern uint32_t rt_time_get(void);
655 
656  //Get current tick count
657  time = rt_time_get();
658 #elif defined(osCMSIS_RTX) && (osCMSIS_RTX >= 0x50000)
659  time = osKernelGetTickCount();
660 #elif defined(osCMSIS_FreeRTOS)
661  time = osKernelGetTickCount();
662 #else
663  //Get current tick count
664  time = osKernelSysTick();
665 #endif
666 
667  //Convert system ticks to milliseconds
668  return OS_SYSTICKS_TO_MS(time);
669 }
670 
671 
672 /**
673  * @brief Allocate a memory block
674  * @param[in] size Bytes to allocate
675  * @return A pointer to the allocated memory block or NULL if
676  * there is insufficient memory available
677  **/
678 
679 __weak_func void *osAllocMem(size_t size)
680 {
681  void *p;
682 
683  //Enter critical section
685  //Allocate a memory block
686  p = malloc(size);
687  //Leave critical section
689 
690  //Debug message
691  TRACE_DEBUG("Allocating %" PRIuSIZE " bytes at 0x%08" PRIXPTR "\r\n",
692  size, (uintptr_t) p);
693 
694  //Return a pointer to the newly allocated memory block
695  return p;
696 }
697 
698 
699 /**
700  * @brief Release a previously allocated memory block
701  * @param[in] p Previously allocated memory block to be freed
702  **/
703 
704 __weak_func void osFreeMem(void *p)
705 {
706  //Make sure the pointer is valid
707  if(p != NULL)
708  {
709  //Debug message
710  TRACE_DEBUG("Freeing memory at 0x%08" PRIXPTR "\r\n", (uintptr_t) p);
711 
712  //Enter critical section
714  //Free memory block
715  free(p);
716  //Leave critical section
718  }
719 }
const OsTaskParameters OS_TASK_DEFAULT_PARAMS
RTOS abstraction layer (CMSIS-RTOS)
int bool_t
Definition: compiler_port.h:53
void osSwitchTask(void)
Yield control to the next task.
uint8_t p
Definition: ndp.h:300
bool_t osWaitForEvent(OsEvent *event, systime_t timeout)
Wait until the specified event is in the signaled state.
#define TRUE
Definition: os_port.h:50
bool_t osWaitForSemaphore(OsSemaphore *semaphore, systime_t timeout)
Wait for the specified semaphore to be available.
Event object.
bool_t osCreateSemaphore(OsSemaphore *semaphore, uint_t count)
Create a semaphore object.
__weak_func void * osAllocMem(size_t size)
Allocate a memory block.
char_t name[]
osSemaphoreId id
#define OS_SELF_TASK_ID
Semaphore object.
__weak_func void osFreeMem(void *p)
Release a previously allocated memory block.
void osResumeAllTasks(void)
Resume scheduler activity.
#define FALSE
Definition: os_port.h:46
void osSuspendAllTasks(void)
Suspend scheduler activity.
bool_t osCreateMutex(OsMutex *mutex)
Create a mutex object.
void(* OsTaskCode)(void *arg)
Task routine.
void osAcquireMutex(OsMutex *mutex)
Acquire ownership of the specified mutex object.
osSemaphoreId id
#define OS_SYSTICKS_TO_MS(n)
void osDeleteSemaphore(OsSemaphore *semaphore)
Delete a semaphore object.
osMutexId id
void osDeleteMutex(OsMutex *mutex)
Delete a mutex object.
Task parameters.
#define MIN(a, b)
Definition: os_port.h:63
systime_t osGetSystemTime(void)
Retrieve system time.
Mutex object.
uint32_t systime_t
System time.
void osReleaseSemaphore(OsSemaphore *semaphore)
Release the specified semaphore object.
#define TRACE_DEBUG(...)
Definition: debug.h:107
char char_t
Definition: compiler_port.h:48
uint32_t time
void osReleaseMutex(OsMutex *mutex)
Release ownership of the specified mutex object.
uint8_t n
OsTaskId osCreateTask(const char_t *name, OsTaskCode taskCode, void *arg, const OsTaskParameters *params)
Create a task.
void osInitKernel(void)
Kernel initialization.
void osDeleteEvent(OsEvent *event)
Delete an event object.
void osDeleteTask(OsTaskId taskId)
Delete a task.
thread_t * OsTaskId
Task identifier.
bool_t osSetEventFromIsr(OsEvent *event)
Set an event object to the signaled state from an interrupt service routine.
void osDelayTask(systime_t delay)
Delay routine.
#define PRIuSIZE
unsigned int uint_t
Definition: compiler_port.h:50
void osSetEvent(OsEvent *event)
Set the specified event object to the signaled state.
bool_t osCreateEvent(OsEvent *event)
Create an event object.
void osStartKernel(void)
Start kernel.
RTOS abstraction layer.
void osResetEvent(OsEvent *event)
Set the specified event object to the nonsignaled state.
Debugging facilities.
#define INFINITE_DELAY
Definition: os_port.h:75