Posix/Linux Simulator Demo for FreeRTOS
using GCC
[RTOS Ports]
Note: Due to recent updates to enable its use on Mac computers and in the Windows Subsystem for Linux (WSL)
the Linux/POSIX port in FreeRTOS V10.4.0 is considered to be a release candidate only. Please provide feedback in the FreeRTOS support forum.
The FreeRTOS port documented on this page allows FreeRTOS to run on Linux just as the
FreeRTOS Windows port (often
referred to as the FreeRTOS Windows simulator) has always allowed FreeRTOS to run on Windows. The port was contributed by David
Vrabel, and inspired by William Davy’s original 2008 Linux port.
The implementation of the port layer uses POSIX threading, so the port is also referred to as the POSIX port. It should not be confused
with the FreeRTOS+POSIX library – they do completely different things.
FreeRTOS+POSIX provides a POSIX threading wrapper for the native FreeRTOS API, whereas the implementation of the Linux
port uses the POSIX threading API provided by the host operating system.
Just like the Windows port, the FreeRTOS Linux port provides a convenient environment in which you can
experiment with FreeRTOS and develop FreeRTOS applications intended for later porting to real embedded hardware – but it will not exhibit real-time behaviour.
IMPORTANT! Notes on using the Posix/Linux Simulator Demo for FreeRTOS
Please read all the following points before using the simulator demo.
Also see the FAQ My application does not run, what could be wrong?.
Source Code Organization
The FreeRTOS zip file download contains the source code for all the FreeRTOS ports and demo
applications – so it contains many more files than are required to build and run the pre-configured demo that uses
the FreeRTOS Linux port. See the Source Code Organization page for information on the zip file’s
directory structure.
The Posix/Linux Simulator Demo
Functionality
The constant mainSELECTED_APPLICATION
, which is
#defined at the top of main.c
, is used to switch between a simple Blinky style demo, a more comprehensive test
and demo application, and a tcp echo client application, as described in the next three sections.
- Blinky demo functionality
-
If mainSELECTED_APPLICATION
is set to BLINKY_DEMO
, then main()
will call main_blinky()
, which is implemented in
main_blinky.c
. main_blinky()
creates a very simple demo that includes two tasks, a software timer, and a
queue. One task repeatedly sends the value 100 at a frequency of 200 milliseconds to the other task through the queue, while the timer sends the value 200 every 2000ms to the same
queue. The receiving task prints out a message each time it receives either of the values from the queue.
- Comprehensive demo functionality
-
If mainSELECTED_APPLICATION
is set to FULL_DEMO
, then main()
will call main_full()
, which is implemented in
main_full.c
. The demo created by main_full()
consists mainly of the standard demo tasks which don’t perform any particular functionality other than testing the
port and demonstrating how the FreeRTOS API can be used.
The full demo includes a ‘check’ that executes every (simulated)
ten seconds, but has the highest priority to ensure it gets processing time. Its main function is to check
all the standard demo tasks are still operational. The check task maintains a status string that is output to the
console each time it executes. If all the standard demo tasks are running without error, then the string contains
“OK” and the current tick count. If an error has been detected, then the string contains a message that indicates
which task reported the error.
- Echo client functionality
-
If mainSELECTED_APPLICATION
is set to ECHO_CLIENT_DEMO
, then main()
will call
main_tcp_echo_client_tasks()
, which is is implemented in main_networking.c
.
The TCP echo demo uses the FreeRTOS+TCP TCP/IP stack to connect and communicate with a
standard TCP echo server on TCP port 7.
The FreeRTOS+TCP network interface for Linux uses libpcap to access the network.
To configure the TCP/IP stack for use with the demo:
-
Follow the instructions under the
Software Setup #1, Software Setup #2, and Software Setup #4 sections
on the page that describes using FreeRTOS+TCP on Windows hosts (the steps under Software Setup #3 are not required).
-
Set the constants
configECHO_SERVER_ADDR0
to configECHO_SERVER_ADDR3
to the address of the echo server in FreeRTOSConfig.h
.
It is common for TCP port 7 (the standard echo port) to be blocked by firewalls. If this is the case then
change the port number used by both the FreeRTOS application and the echo server to a high but valid
number, such as 5200. The port number used by the FreeRTOS application is set by the echoECHO_PORT
constant in TCPEchoClient_SingleTasks.c.
If you create a TCP echo server using the nc
command in Linux then the port number is set using the -l
switch:
$ sudo nc -l 7
Network troubleshooting
ARP responses may not get sent if the echo server is running on the same computer as the FreeRTOS demo, resulting in the demo not being able to connect to the echo server. If this is an issue then run the echo server on a different computer.
Building the Posix/Linux Simulator Demo
GDB Debugging Tips
This section assumes that you have installed and are familiar with gdb.
You can find the gdb documentation here.
The port layer uses two process signals: SIGUSR1
, and SIGALRM
. If a pthread is not waiting on
the signal, then GDB will pause the process when it receives the signal. GDB must be told to ignore (and not print) the
signal SIGUSR1
because it is received asynchronously by each thread. In GDB, enter
$ handle SIGUSR1 nostop noprint pass
to ensure that debugging is not interrupted by the signals. See
$ man signal
for more information.
Alternatively, create a file in your home directory called .gdbinit
and place the following two lines in it:
handle SIGUSR1 nostop noignore noprint
handle SIGALRM nostop noignore noprint
When you add these two lines to the .gdbinit
file, it tells GDB to not break on those signals.
There are three different timers available for use as the System tick: ITIMER_REAL
, ITIMER_VIRTUAL
and ITIMER_PROF
. The default timer is ITIMER_VIRTUAL
because it only counts when the process is
executing in user space, so it will stop when a break-point is hit. ITIMER_PROF
is equivalent to
ITIMER_VIRTUAL
but it includes the time spent executing system calls. ITIMER_REAL
continues
counting even when the process is not executing at all, so it represents real-time. ITIMER_REAL
is the only
usable option because the other timers don't tick unless the process is actually running. For that reason, if
nanosleep
is called in the IDLE task hook, the time reported by the non-real timers will hardly ever
increase.
Port-Layer Design Methodology Justification
A simple implementation of a FreeRTOS Simulator would simply wrap the platform native threads, and all calls to switch Task
contexts would call the OS suspend and resume thread API. This simulator uses the Posix condition variables and Signals to
control the execution of the underlying Posix threads. Signals can be delivered to the threads asynchronously, so that they
interrupt the execution of the target thread, while suspended threads wait on condition variables to resume.
Typically, when designing a multi-threaded process, we use multiple threads to allow for concurrent execution and to
implement a degree of non-blocking on IO tasks. This simulator does not use the threads to achieve concurrent execution,
but only to store the context of the execution. Signals, mutexes and condition variables are used to synchronize context
switching, but ultimately, the decision to change the context is driven by the FreeRTOS scheduler.
When a new Task is created, a pthread is created as the context for the execution of that Task. The pthread immediately
suspends itself, and returns the execution to the creator. When a pthread is suspended, it is waiting in a call to
pthread_cond_wait
, which is blocked until it receives a resume signalpthread_cond_signal
.
FreeRTOS Tasks can be switched in two ways, co-operatively by calling taskYIELD()
or pre-emptively as part
of the System Tick. In this simulator, the Task contexts are switched by resuming the next task context (decided by the
FreeRTOS Scheduler) and suspending the current context (with a brief handshake between the two).
The System tick is generated using an ITIMER
and the signal is delivered (only to) the currently executing
pthread. The System Tick Signal Handler increments the tick and selects the next context. It resumes that thread and sends a
signal to itself to suspend. The suspend is only processed when the System Tick Signal Handler exits, because signals are
queued.
Known Issues
pthread_create
and pthread_exit/cancel
are system intensive calls which can rapidly saturate the
processing time.
If you call system and library functions that block (printf), this could cause the whole process to halt. If it is necessary
to make system calls, all signals on that thread must be masked, then re-allowed after the system call finishes execution.
Additional threads could be created to simulate interrupts, but signals should be masked in those threads as well, so that
they do not receive signals and so be scheduled to execute by the FreeRTOS scheduler and become part of the regular FreeRTOS
tasks.
To prevent the process from stealing all of the Idle execution time of the Host OS, use nano_sleep()
. It doesn't
use any signals in its implementation but will abort from the sleep/suspend process immediately to service a signal.
Therefore, the best way to use it is to set a sleep time longer than a FreeRTOS execution time-slice and call it from the
Idle task so that the process suspends until the next tick.
Copyright (C) Amazon Web Services, Inc. or its affiliates. All rights reserved.