os_port_freertos.c
Go to the documentation of this file.
1 /**
2  * @file os_port_freertos.c
3  * @brief RTOS abstraction layer (FreeRTOS)
4  *
5  * @section License
6  *
7  * SPDX-License-Identifier: GPL-2.0-or-later
8  *
9  * Copyright (C) 2010-2025 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.5.0
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_freertos.h"
37 #include "debug.h"
38 
39 //Default task parameters
41 {
42 #if (configSUPPORT_STATIC_ALLOCATION == 1)
43  NULL, //Task control block
44  NULL, //Stack
45 #endif
46  configMINIMAL_STACK_SIZE, //Size of the stack
47  tskIDLE_PRIORITY + 1 //Task priority
48 };
49 
50 
51 /**
52  * @brief Kernel initialization
53  **/
54 
55 void osInitKernel(void)
56 {
57 }
58 
59 
60 /**
61  * @brief Start kernel
62  **/
63 
64 void osStartKernel(void)
65 {
66  //Start the scheduler
67  vTaskStartScheduler();
68 }
69 
70 
71 /**
72  * @brief Create a task
73  * @param[in] name NULL-terminated string identifying the task
74  * @param[in] taskCode Pointer to the task entry function
75  * @param[in] arg Argument passed to the task function
76  * @param[in] params Task parameters
77  * @return Task identifier referencing the newly created task
78  **/
79 
80 OsTaskId osCreateTask(const char_t *name, OsTaskCode taskCode, void *arg,
81  const OsTaskParameters *params)
82 {
83  size_t stackSize;
84  portBASE_TYPE status;
85  TaskHandle_t handle;
86 
87 #ifdef IDF_VER
88  //The stack size is specified in bytes
89  stackSize = params->stackSize * sizeof(uint32_t);
90 #else
91  stackSize = params->stackSize;
92 #endif
93 
94 #if (configSUPPORT_STATIC_ALLOCATION == 1)
95  //Static allocation?
96  if(params->tcb != NULL && params->stack != NULL)
97  {
98  //Create a new task
99  handle = xTaskCreateStatic((TaskFunction_t) taskCode, name,
100  stackSize, arg, params->priority, (StackType_t *) params->stack,
101  params->tcb);
102  }
103  else
104 #endif
105  //Dynamic allocation?
106  {
107  //Create a new task
108  status = xTaskCreate((TaskFunction_t) taskCode, name, stackSize, arg,
109  params->priority, &handle);
110 
111  //Failed to create task?
112  if(status != pdPASS)
113  {
114  handle = OS_INVALID_TASK_ID;
115  }
116  }
117 
118  //Return the handle referencing the newly created task
119  return (OsTaskId) handle;
120 }
121 
122 
123 /**
124  * @brief Delete a task
125  * @param[in] taskId Task identifier referencing the task to be deleted
126  **/
127 
128 void osDeleteTask(OsTaskId taskId)
129 {
130  //Delete the specified task
131  vTaskDelete((TaskHandle_t) taskId);
132 }
133 
134 
135 /**
136  * @brief Delay routine
137  * @param[in] delay Amount of time for which the calling task should block
138  **/
139 
141 {
142  //Delay the task for the specified duration
143  vTaskDelay(OS_MS_TO_SYSTICKS(delay));
144 }
145 
146 
147 /**
148  * @brief Yield control to the next task
149  **/
150 
151 void osSwitchTask(void)
152 {
153  //Force a context switch
154  taskYIELD();
155 }
156 
157 
158 /**
159  * @brief Suspend scheduler activity
160  **/
161 
163 {
164  //Make sure the operating system is running
165  if(xTaskGetSchedulerState() != taskSCHEDULER_NOT_STARTED)
166  {
167  //Suspend all tasks
168  vTaskSuspendAll();
169  }
170 }
171 
172 
173 /**
174  * @brief Resume scheduler activity
175  **/
176 
178 {
179  //Make sure the operating system is running
180  if(xTaskGetSchedulerState() != taskSCHEDULER_NOT_STARTED)
181  {
182  //Resume all tasks
183  xTaskResumeAll();
184  }
185 }
186 
187 
188 /**
189  * @brief Create an event object
190  * @param[in] event Pointer to the event object
191  * @return The function returns TRUE if the event object was successfully
192  * created. Otherwise, FALSE is returned
193  **/
194 
196 {
197 #if (configSUPPORT_STATIC_ALLOCATION == 1)
198  //Create a binary semaphore
199  event->handle = xSemaphoreCreateBinaryStatic(&event->buffer);
200 #else
201  //Create a binary semaphore
202  event->handle = xSemaphoreCreateBinary();
203 #endif
204 
205  //Check whether the returned handle is valid
206  if(event->handle != NULL)
207  {
208  return TRUE;
209  }
210  else
211  {
212  return FALSE;
213  }
214 }
215 
216 
217 /**
218  * @brief Delete an event object
219  * @param[in] event Pointer to the event object
220  **/
221 
222 void osDeleteEvent(OsEvent *event)
223 {
224  //Make sure the handle is valid
225  if(event->handle != NULL)
226  {
227  //Properly dispose the event object
228  vSemaphoreDelete(event->handle);
229  }
230 }
231 
232 
233 /**
234  * @brief Set the specified event object to the signaled state
235  * @param[in] event Pointer to the event object
236  **/
237 
238 void osSetEvent(OsEvent *event)
239 {
240  //Set the specified event to the signaled state
241  xSemaphoreGive(event->handle);
242 }
243 
244 
245 /**
246  * @brief Set the specified event object to the nonsignaled state
247  * @param[in] event Pointer to the event object
248  **/
249 
250 void osResetEvent(OsEvent *event)
251 {
252  //Force the specified event to the nonsignaled state
253  xSemaphoreTake(event->handle, 0);
254 }
255 
256 
257 /**
258  * @brief Wait until the specified event is in the signaled state
259  * @param[in] event Pointer to the event object
260  * @param[in] timeout Timeout interval
261  * @return The function returns TRUE if the state of the specified object is
262  * signaled. FALSE is returned if the timeout interval elapsed
263  **/
264 
266 {
267  portBASE_TYPE ret;
268 
269  //Wait until the specified event is in the signaled state or the timeout
270  //interval elapses
271  if(timeout == INFINITE_DELAY)
272  {
273  //Infinite timeout period
274  ret = xSemaphoreTake(event->handle, portMAX_DELAY);
275  }
276  else
277  {
278  //Wait for the specified time interval
279  ret = xSemaphoreTake(event->handle, OS_MS_TO_SYSTICKS(timeout));
280  }
281 
282  //The return value tells whether the event is set
283  return ret;
284 }
285 
286 
287 /**
288  * @brief Set an event object to the signaled state from an interrupt service routine
289  * @param[in] event Pointer to the event object
290  * @return TRUE if setting the event to signaled state caused a task to unblock
291  * and the unblocked task has a priority higher than the currently running task
292  **/
293 
295 {
296  portBASE_TYPE flag = FALSE;
297 
298  //Set the specified event to the signaled state
299  xSemaphoreGiveFromISR(event->handle, &flag);
300 
301  //A higher priority task has been woken?
302  return flag;
303 }
304 
305 
306 /**
307  * @brief Create a semaphore object
308  * @param[in] semaphore Pointer to the semaphore object
309  * @param[in] count The maximum count for the semaphore object. This value
310  * must be greater than zero
311  * @return The function returns TRUE if the semaphore was successfully
312  * created. Otherwise, FALSE is returned
313  **/
314 
316 {
317 #if (configSUPPORT_STATIC_ALLOCATION == 1)
318  //Create a semaphore
319  semaphore->handle = xSemaphoreCreateCountingStatic(count, count,
320  &semaphore->buffer);
321 #else
322  //Create a semaphore
323  semaphore->handle = xSemaphoreCreateCounting(count, count);
324 #endif
325 
326  //Check whether the returned handle is valid
327  if(semaphore->handle != NULL)
328  {
329  return TRUE;
330  }
331  else
332  {
333  return FALSE;
334  }
335 }
336 
337 
338 /**
339  * @brief Delete a semaphore object
340  * @param[in] semaphore Pointer to the semaphore object
341  **/
342 
344 {
345  //Make sure the handle is valid
346  if(semaphore->handle != NULL)
347  {
348  //Properly dispose the specified semaphore
349  vSemaphoreDelete(semaphore->handle);
350  }
351 }
352 
353 
354 /**
355  * @brief Wait for the specified semaphore to be available
356  * @param[in] semaphore Pointer to the semaphore object
357  * @param[in] timeout Timeout interval
358  * @return The function returns TRUE if the semaphore is available. FALSE is
359  * returned if the timeout interval elapsed
360  **/
361 
363 {
364  portBASE_TYPE ret;
365 
366  //Wait until the specified semaphore becomes available
367  if(timeout == INFINITE_DELAY)
368  {
369  //Infinite timeout period
370  ret = xSemaphoreTake(semaphore->handle, portMAX_DELAY);
371  }
372  else
373  {
374  //Wait for the specified time interval
375  ret = xSemaphoreTake(semaphore->handle, OS_MS_TO_SYSTICKS(timeout));
376  }
377 
378  //The return value tells whether the semaphore is available
379  return ret;
380 }
381 
382 
383 /**
384  * @brief Release the specified semaphore object
385  * @param[in] semaphore Pointer to the semaphore object
386  **/
387 
389 {
390  //Release the semaphore
391  xSemaphoreGive(semaphore->handle);
392 }
393 
394 
395 /**
396  * @brief Create a mutex object
397  * @param[in] mutex Pointer to the mutex object
398  * @return The function returns TRUE if the mutex was successfully
399  * created. Otherwise, FALSE is returned
400  **/
401 
403 {
404 #if (configSUPPORT_STATIC_ALLOCATION == 1)
405  //Create a mutex object
406  mutex->handle = xSemaphoreCreateMutexStatic(&mutex->buffer);
407 #else
408  //Create a mutex object
409  mutex->handle = xSemaphoreCreateMutex();
410 #endif
411 
412  //Check whether the returned handle is valid
413  if(mutex->handle != NULL)
414  {
415  return TRUE;
416  }
417  else
418  {
419  return FALSE;
420  }
421 }
422 
423 
424 /**
425  * @brief Delete a mutex object
426  * @param[in] mutex Pointer to the mutex object
427  **/
428 
429 void osDeleteMutex(OsMutex *mutex)
430 {
431  //Make sure the handle is valid
432  if(mutex->handle != NULL)
433  {
434  //Properly dispose the specified mutex
435  vSemaphoreDelete(mutex->handle);
436  }
437 }
438 
439 
440 /**
441  * @brief Acquire ownership of the specified mutex object
442  * @param[in] mutex Pointer to the mutex object
443  **/
444 
446 {
447  //Obtain ownership of the mutex object
448  xSemaphoreTake(mutex->handle, portMAX_DELAY);
449 }
450 
451 
452 /**
453  * @brief Release ownership of the specified mutex object
454  * @param[in] mutex Pointer to the mutex object
455  **/
456 
458 {
459  //Release ownership of the mutex object
460  xSemaphoreGive(mutex->handle);
461 }
462 
463 
464 /**
465  * @brief Retrieve system time
466  * @return Number of milliseconds elapsed since the system was last started
467  **/
468 
470 {
471  systime_t time;
472 
473  //Get current tick count
474  time = xTaskGetTickCount();
475 
476  //Convert system ticks to milliseconds
477  return OS_SYSTICKS_TO_MS(time);
478 }
479 
480 
481 /**
482  * @brief Allocate a memory block
483  * @param[in] size Bytes to allocate
484  * @return A pointer to the allocated memory block or NULL if
485  * there is insufficient memory available
486  **/
487 
488 __weak_func void *osAllocMem(size_t size)
489 {
490  void *p;
491 
492  //Allocate a memory block
493  p = pvPortMalloc(size);
494 
495  //Debug message
496  TRACE_DEBUG("Allocating %" PRIuSIZE " bytes at 0x%08" PRIXPTR "\r\n",
497  size, (uintptr_t) p);
498 
499  //Return a pointer to the newly allocated memory block
500  return p;
501 }
502 
503 
504 /**
505  * @brief Release a previously allocated memory block
506  * @param[in] p Previously allocated memory block to be freed
507  **/
508 
509 __weak_func void osFreeMem(void *p)
510 {
511  //Make sure the pointer is valid
512  if(p != NULL)
513  {
514  //Debug message
515  TRACE_DEBUG("Freeing memory at 0x%08" PRIXPTR "\r\n", (uintptr_t) p);
516 
517  //Free memory block
518  vPortFree(p);
519  }
520 }
521 
522 
523 #if (configSUPPORT_STATIC_ALLOCATION == 1 && !defined(IDF_VER))
524 
525 /**
526  * @brief Provide the memory that is used by the idle task
527  **/
528 
529 void vApplicationGetIdleTaskMemory(StaticTask_t **ppxIdleTaskTCBBuffer,
530  StackType_t **ppxIdleTaskStackBuffer, uint32_t *pulIdleTaskStackSize)
531 {
532  static StaticTask_t xIdleTaskTCB;
533  static StackType_t uxIdleTaskStack[configMINIMAL_STACK_SIZE];
534 
535  *ppxIdleTaskTCBBuffer = &xIdleTaskTCB;
536  *ppxIdleTaskStackBuffer = uxIdleTaskStack;
537  *pulIdleTaskStackSize = configMINIMAL_STACK_SIZE;
538 }
539 
540 #endif
541 
542 
543 #if 0
544 
545 /**
546  * @brief FreeRTOS stack overflow hook
547  **/
548 
549 void vApplicationStackOverflowHook(TaskHandle_t pxTask, char *pcTaskName)
550 {
551  (void) pcTaskName;
552  (void) pxTask;
553 
554  taskDISABLE_INTERRUPTS();
555 
556  while(1)
557  {
558  }
559 }
560 
561 
562 /**
563  * @brief Trap FreeRTOS errors
564  **/
565 
566 void vAssertCalled(const char *pcFile, unsigned long ulLine)
567 {
568  volatile unsigned long ul = 0;
569 
570  (void) pcFile;
571  (void) ulLine;
572 
573  taskENTER_CRITICAL();
574 
575  //Set ul to a non-zero value using the debugger to step out of this function
576  while(ul == 0)
577  {
578  portNOP();
579  }
580 
581  taskEXIT_CRITICAL();
582 }
583 
584 #endif
OsTaskId osCreateTask(const char_t *name, OsTaskCode taskCode, void *arg, const OsTaskParameters *params)
Create a task.
void osResetEvent(OsEvent *event)
Set the specified event object to the nonsignaled state.
void osDeleteEvent(OsEvent *event)
Delete an event object.
int bool_t
Definition: compiler_port.h:61
void osSuspendAllTasks(void)
Suspend scheduler activity.
SemaphoreHandle_t handle
uint8_t p
Definition: ndp.h:300
#define TRUE
Definition: os_port.h:50
#define OS_INVALID_TASK_ID
Event object.
void osReleaseMutex(OsMutex *mutex)
Release ownership of the specified mutex object.
bool_t osCreateMutex(OsMutex *mutex)
Create a mutex object.
portInt8Type buffer[portQUEUE_OVERHEAD_BYTES *2]
char_t name[]
void osAcquireMutex(OsMutex *mutex)
Acquire ownership of the specified mutex object.
systime_t osGetSystemTime(void)
Retrieve system time.
Semaphore object.
void osSetEvent(OsEvent *event)
Set the specified event object to the signaled state.
portInt8Type buffer[portQUEUE_OVERHEAD_BYTES *2]
bool_t osWaitForEvent(OsEvent *event, systime_t timeout)
Wait until the specified event is in the signaled state.
#define FALSE
Definition: os_port.h:46
void osStartKernel(void)
Start kernel.
__weak_func void * osAllocMem(size_t size)
Allocate a memory block.
void(* OsTaskCode)(void *arg)
Task routine.
void osInitKernel(void)
Kernel initialization.
#define OS_SYSTICKS_TO_MS(n)
const OsTaskParameters OS_TASK_DEFAULT_PARAMS
#define OS_MS_TO_SYSTICKS(n)
void osDeleteMutex(OsMutex *mutex)
Delete a mutex object.
Task parameters.
portInt8Type buffer[portQUEUE_OVERHEAD_BYTES *2]
RTOS abstraction layer (FreeRTOS)
void osDeleteSemaphore(OsSemaphore *semaphore)
Delete a semaphore object.
void osResumeAllTasks(void)
Resume scheduler activity.
Mutex object.
uint32_t systime_t
System time.
#define TRACE_DEBUG(...)
Definition: debug.h:119
char char_t
Definition: compiler_port.h:55
bool_t osSetEventFromIsr(OsEvent *event)
Set an event object to the signaled state from an interrupt service routine.
uint32_t time
SemaphoreHandle_t handle
void osDeleteTask(OsTaskId taskId)
Delete a task.
bool_t osCreateEvent(OsEvent *event)
Create an event object.
__weak_func void osFreeMem(void *p)
Release a previously allocated memory block.
void osReleaseSemaphore(OsSemaphore *semaphore)
Release the specified semaphore object.
void osSwitchTask(void)
Yield control to the next task.
thread_t * OsTaskId
Task identifier.
#define PRIuSIZE
unsigned int uint_t
Definition: compiler_port.h:57
bool_t osWaitForSemaphore(OsSemaphore *semaphore, systime_t timeout)
Wait for the specified semaphore to be available.
RTOS abstraction layer.
void osDelayTask(systime_t delay)
Delay routine.
bool_t osCreateSemaphore(OsSemaphore *semaphore, uint_t count)
Create a semaphore object.
Debugging facilities.
#define INFINITE_DELAY
Definition: os_port.h:75
SemaphoreHandle_t handle