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