Quality RTOS & Embedded Software

KERNEL

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

  • Pre-requisites (the output below shows the versions used during testing):
    1. gcc

      $ gcc --version
      gcc (GCC) 9.2.0
    2. make

      $ make --version
      GNU Make 3.81
      Copyright (C) 2006  Free Software Foundation, Inc.
    3. libpcap (for networking support)

      $ version: libpcap-devel-1.5.3-11.x86_64 
      To install on ubuntu run
      $ sudo apt-get install libpcap-dev
      To install on rpm based system run
      $ sudo yum install libpcap-devel
      or
      $ sudo dnf install libpcap-devel
      To install on MacOS run
      $ brew install libpcap
      Alternatively, it is possible to install from source follow the instructions at INSTALL.md

  • Building the source code:
    1. Navigate to the Demo Directory at: Demo source

       $ cd cd FreeRTOS/Demo/Posix_GCC/
    2. To build run:
      $ make
    3. To clean run:
      $ make clean
  • Running the Demo (check the instructions above on how to choose between the available demos)

    1. Navigate to the newly created “build” directory
      $ cd build 
    2. Run the demo (blinky and full)

      $ ./posix_demo
    3. Run the Networking demo:

      Run an echo server on a different machine

      $ sudo nc -l 7

      Run on your machine

      $ sudo ./posix_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.