Cortex-A53 Xilinx UltraScale MPSoC
64-bit RTOS Demo
The Xilinx SDK
(Software Development Kit) includes wizards that create FreeRTOS projects for
all the cores found on the
Zynq UltraScale MPSoC, which includes ARM Cortex-A53 (64-bit), ARM Cortex-R5, and Microblaze processors.
This page documents a FreeRTOS demo application that targets a 64-bit ARM Cortex-A53
core on a Xilinx Zynq UltraScale+ MPSoC. A similar project that targets an
ARM Cortex-R5 core on the same device is provided separately.
The demo uses a standalone BSP (which is
the Board Support Package generated by the SDK), and builds FreeRTOS as part of
the application. The hardware design project targets the ZCU102 Evaluation Kit.
FreeRTOS is also distributed as part of the Xilinx SDK package, and the SDK
includes wizards to generate FreeRTOS for the UltraScale+ MPSoC’s 64-bit ARM Cortex-A53, ARM Cortex-R5
and Microblaze cores. When the SDK generates a project FreeRTOS is built as part of the
BSP, rather than part of the application. Instructions for this are also provided.
The 64-bit ARM Cortex-A53 FreeRTOS port implements a full interrupt nesting model,
and supports the floating point unit (FPU).
IMPORTANT! Notes on using the FreeRTOS 64-bit ARM Cortex-A53 port
Please read all the following points before using this RTOS port.
Also see the FAQ My application does not run, what could be wrong?, and
the page that provides instruction on using FreeRTOS on ARM Cortex-A embedded processors.
- Source Code Organisation
- The Demo Application Functionality
- Build Instructions
- RTOS Configuration and Usage Details
Source Code Organization
The FreeRTOS download contains the source code for all the FreeRTOS ports, and
every demo application. That means it contains many more files than are required
to use the Zynq UltraScale+ Cortex-A53 MPSoC port and demo application.
See the Source Code Organization
section of this web site for a description of the downloaded files, and
information on creating a new project.
The directory structure used by the demo application is shown and described
below. The root CORTEX_A53_64-bit_UltraScale_MPSoC directory is itself
located in FreeRTOS/Demo.
+-RTOSDemo_A53 Contains the SDK project and C files specific to the demo.
+-RTOSDemo_A53_bsp Contains the hardware board support package.
+-ZynqMP_ZCU102_hw_platform The ZCU102 hardware description.
Notes relating to the directory structure:
The projects contained in the ZynqMP_ZCU102_hw_platform and RTOSDemo_A53_bsp directories
were created by the Xilinx SDK.
The RTOSDemo_A53 directory only contains the source files that are specific
to the Zynq UltraScale+ MPSoC demo. The FreeRTOS source files, and the source files that
implement tasks that are common to all demo applications, are located
elsewhere in the directory tree.
Therefore the project will only build when the default directory structure
is unchanged. Also see the page that describes
how to use virtual and linked paths in
the Eclipse project explorer.
The Zynq UltraScale+ MPSoC ARM Cortex-A53 Demo Application
The constant mainSELECTED_APPLICATION, which is #defined at the top
of main.c, is used to switch between a simply Blinky style demo and a more
comprehensive test and demo application.
Functionality with mainSELECTED_APPLICATION set to 0
If mainSELECTED_APPLICATION is set to 0 then main() will call
main_blinky(), which is implemented in main_blinky.c.
main_blinky() creates a very simple demo that includes two tasks and one queue.
One task uses the queue to repeatedly send the value 100 to the other task.
The receiving task prints a message to the USB UART port (J83) each time the
message is received. 115200 baud is used.
The message is sent to the queue every 200 milliseconds, so the message is printed
to the UART every 200 milliseconds.
Functionality with mainSELECTED_APPLICATION set to 1
If mainSELECTED_APPLICATION is set to 1 then main() will call main_full(),
which is implemented in main_full.c.
main_full() creates a comprehensive application that tests the RTOS port and
Most of the tasks created by the demo are from the set of standard demo
tasks. These are used by all FreeRTOS demo applications, and
have no specific functionality or purpose other than to demonstrate the FreeRTOS
API being used, and test the RTOS port.
The following tasks are created in addition to the standard demo tasks:
Interrupt nesting test tasks
Two timers are used to test interrupt nesting, and test RTOS queues being used
from nested interrupts.
Register test tasks
The register test tasks test the RTOS context switch mechanism by first
filling each ARM Cortex-A53 register (including the floating point registers)
with a known and unique value, then repeatedly checking that the value
originally written to the register remains in the register for
the lifetime of the task. The nature of
these tasks necessitates that they are written in assembly.
A ‘check’ task
The check task periodically queries the standard demo tasks, and the
register test tasks, to ensure they are functioning as intended – then
prints a status message to the USB UART (J83). 115200 baud is used.
The output generated by the full demo
All four switches on bank SW6 need to be set toward the centre of the board in
order to enable downloading and executing over the JTAG interface.
Build Instructions – Using the Official FreeRTOS Demo
This section describes how to build the demo described immediately above.
The section that follows after describes how to use the Xilinx SDK to create and build a
Importing the demo application project into the SDK Eclipse workspace
To import the Xilinx Software Development Kit (SDK) projects into an existing or new Eclipse Workspace:
Select “Import” from the SDK “File” menu. The dialogue box shown below
will appear. Select General->Existing Project into Workspace, as shown in the image.
The dialogue box that appears when “Import” is first clicked
In the next dialogue box, select FreeRTOS/Demo/CORTEX_A53_64-bit_UltraScale_MPSoC
as the root directory. Then, make sure the RTOSDemo_A53, RTOSDemo_A53_bsp and
ZynqMP_ZCU102_hw_platform projects are checked in the “Projects” area,
and that the Copy Projects Into
Workspace box is not checked, before clicking
the Finish button (see the image below for the correct check box states).
Make sure all three projects are checked, and “Copy projects into workspace” is not checked
Once all three projects have been imported, the project explorer window of the SDK IDE
will appear as shown below.
The ZynqMP_ZCU102_hw_platform and RTOSDemo_A53_bsp projects are dependencies of the
RTOSDemo_A53 project, so only the RTOSDemo_A53 project needs to be built explicitly.
All three projects imported into the workspace
Building the demo application
Open the project’s main.c file, and set mainSELECTED_APPLICATION
to generate the simple blinky demo, or the full test and demo
application, as required.
Select ‘Rebuild All’ from the Eclipse IDE ‘Project’ menu.
Starting a debug session
Ensure the ZCU102 evaluation board is powered up and
connected to the host computer using an appropriate debug interface.
Ensure all four switches on bank SW6 are set such that they are toward
the centre of the board. This enables JTAG booting.
Select ‘Debug Configurations…’ from the IDE’s ‘Run’ menu. The
Debug Configurations dialogue box will appear. Double click
‘Xilinx C/C++ application (System Debugger)’ to create a new debug
Configure the ‘Target Setup’ tab as shown in the image below.
The required settings on the Target Setup tab
Configure the ‘Application’ tab as shown in the image below.
The required settings on the Application tab
All the other tabs in the ‘Debug Configurations’ dialogue can be left
with their default settings.
Click the “Debug” button to commence debugging. The application will be
downloaded to RAM and the debugger will break on entry to main(). It
may be necessary to select the correct ARM Cortex-A53 core in the Debug
window in order to see the correct source code, and use the debugging
Selecting the ARM Cortex-A53 #0 core in the debug window
Build Instructions – Creating a Basic Project Using the SDK
The previous section described how to build
the official FreeRTOS project that comes in the main FreeRTOS zip file download.
FreeRTOS also ships with the Xilinx SDK. This section describes how to create a
FreeRTOS project using the SDK.
Creating a new FreeRTOS project
Select “New->Application Project” from the SDK “File” menu. The New
Project dialogue box will appear.
Selecting the New Application Project menu item
In the New Project dialogue box, first select “psu_cortexa53_0” as the
processor, then select the hardware platform as appropriate, and finally
select freertos as the OS platform before clicking “Next”. The New Project
Templates dialogue will appear.
The required New Project dialogue settings
Select the FreeRTOS Hello World template, then click “Finish”. The SDK
will create a hardware description project, a BSP project, and an application
project. The FreeRTOS source code is built as part of the BSP.
Selecting the FreeRTOS template
Configuring a FreeRTOS BSP
The official FreeRTOS demo uses a standalone BSP, and builds FreeRTOS as part of
the application. When this is done FreeRTOS is configured by manually editing the
FreeRTOSConfig.h header file.
Projects created by the
SDK (as just described) build FreeRTOS as part of the BSP. When this is done
the FreeRTOSConfig.h header file is not edited manually, and instead FreeRTOS
is configured using a dialogue box within the SDK environment.
Follow the instructions above to have a FreeRTOS Hello World
application created by the SDK.
Select “Board Support Package Settings” from the SDK “Xilinx Tools” menu.
The Board Support Package Settings dialogue will appear.
Select freertos in the left pane of the Board Support Package Settings dialogue,
then use the table in the right pane of the same dialogue to configure
FreeRTOS as required.
Using the Board Support Package Settings dialogue to configure FreeRTOS
FreeRTOS ARM Cortex-A port specific configuration
Attention please!: Refer to the the page that provides
instruction on using FreeRTOS on ARM Cortex-A embedded processors,
paying particular attention to the value and meaning of the
configMAX_API_CALL_INTERRUPT_PRIORITY setting, and
the special notes regarding using the floating point unit with GCC.
Configuration items specific to this demo are contained in /FreeRTOS/Demo/CORTEX_A53_64-bit_UltraScale_MPSoC/RTOSDemo_A53/src/FreeRTOSConfig.h.
The constants defined in this file can be edited to suit your application.
Interrupt vector table
By default, SDK projects define the interrupt vector table as part of the BSP. This
makes it difficult to install the FreeRTOS handlers using the methods described
on the page about
running FreeRTOS on ARM Cortex-A embedded processors. Therefore, this demo
defines its own interrupt vector table in FreeRTOS_asm_vectors.S. The
vector table defined by the BSP is automatically replaced by the vector table defined in
FreeRTOS_asm_vectors.S when the scheduler is started.
[Application Defined] Interrupt service routines
Unlike when running the RTOS on the Zynq 7000, you cannot re-enable
interrupts in the ARM Cortex-A53 port until after the source of the
interrupt has been cleared.
This demo uses drivers provided by Xilinx to configure the interrupt controller,
and install application defined interrupts. Examples can be found in
which implements and installs the interrupt service routines used by the interrupt
The Xilinx drivers require interrupt
service routines (ISRs) to accept a void * parameter, although the parameter
is not always used. The required ISR prototype is therefore:
void Interrupt_Handler( void *pvUnusedParameter );
If an ISR causes a task of equal or higher priority than the currently executing
task to leave the Blocked state then the ISR must request a context switch before
the ISR exits. When this is done the interrupt will interrupt one RTOS task,
but return to a different RTOS task.
The macros portYIELD_FROM_ISR() (or portEND_SWITCHING_ISR()) can be used to
request a context switch from within an ISR.
The following source code snippet is provided as an example. The example ISR
uses a direct to task notification to synchronise with a task (not shown), and calls portYIELD_FROM_ISR()
to ensure the interrupt returns directly to the task.
void Dummy_IRQHandler( void *pvUnusedInThisExample )
long lHigherPriorityTaskWoken = pdFALSE;
/* The parameter is not used in this case. */
( void ) pvUnusedInThisExample;
/* Clear the interrupt if necessary. */
/* This interrupt does nothing more than demonstrate how to synchronise a
task with an interrupt. A direct to task notification is used for this
purpose. Note lHigherPriorityTaskWoken is initialised to pdFALSE. */
vTaskNotifyGiveFromISR( xTaskToNotify, &lHigherPriorityTaskWoken );
/* If the task referenced by xTaskToNotify was blocked waiting for the
notification, and sending the notification caused the task to unblock, and
the unblocked task has a priority higher than or equal to the currently
Running task (the task that this interrupt interrupted), then
lHigherPriorityTaskWoken will have been set to pdTRUE internally within
vTaskNotifyGiveFromISR(). Passing pdTRUE into the portYIELD_FROM_ISR() macro
will result in a context switch being pended to ensure this interrupt returns
directly to the unblocked, higher priority, task. Passing pdFALSE into
portYIELD_FROM_ISR() has no effect. */
portYIELD_FROM_ISR( lHigherPriorityTaskWoken );
Only FreeRTOS API functions that end in “FromISR” can be called from an
interrupt service routine – and then only if the priority of the interrupt
is less than or equal to that set by the configMAX_API_CALL_INTERRUPT_PRIORITY
configuration constant (meaning a numerically higher value).
Resources used by FreeRTOS
Information is provided on the Using FreeRTOS on ARM Cortex-A Embedded Processors page.
This demo is configured to generate the tick interrupt from a TTT channel.
The FreeRTOSConfig.h header file used by the demo has both
configSUPPORT_STATIC_ALLOCATION and configSUPPORT_DYNAMIC_ALLOCATION
defined, and the demo shows both methods being used.
Source/Portable/MemMang/heap_4.c is included in the 64-bit ARM Cortex-A53 demo application project to provide the memory
allocation required when objects are created using dynamic memory allocation.
Please refer to the Memory Management section of the API documentation for
Note that vPortEndScheduler() has not been implemented.
Copyright (C) Amazon Web Services, Inc. or its affiliates. All rights reserved.