TI supports developing PRU projects either in CCS, or in the OpenPRU repository.
This document discusses the steps to create a new PRU firmware project in the OpenPRU repo.
For a detailed, processor-specific example of creating a new project in the OpenPRU repo, or for documentation about how to create a PRU project in the CCS development environment, please refer to the PRU Academy > Getting Started Labs > Lab 1: How to Create a PRU Project.
Commands throughout this document will be given in the format used by the Linux terminal, or a Windows application like Git Bash.
Before creating a new OpenPRU project, set up the OpenPRU repo by following the steps at Getting Started with OpenPRU.
Before making any changes, ensure that all projects in the OpenPRU repo build
and clean successfully. Follow the instructions in the make help command:
$ cd /path/to/open-pru
$ make help
# build the projects and inspect the output
# afterwards, clean projects before copying anything
If the projects do not build, there is probably an issue with your imports.mak
file. Fix the issue before moving forward.
Save all development work in a dedicated branch:
$ git branch <author>_<subject>
$ git checkout <author>_<subject>
Save changes often with git add and git commit. Squash multiple commits
later using git rebase -i.
The easiest way to create a new project in the OpenPRU repo is to copy an existing project into a new directory. This copied project serves as a starting point for development.
Note
The "empty" projects are the default starting point for new development, though any existing OpenPRU project may be used. A PRU project from outside of the OpenPRU repo may also be used as a starting point, like projects from the PRU Software Support Package, or the Beaglebone community. To create a project within OpenPRU that is based on code from outside of the OpenPRU repo, first create a new OpenPRU project from an "empty" project, and then copy specific files from the external project into the new OpenPRU project.
The OpenPRU repo has two "empty" starting projects:
examples/empty— PRU firmware programmed in assemblyexamples/empty_c— PRU firmware programmed in C or mixed C and assembly
If using an "empty" project, select the project that matches your language. The
rest of this document is written as if development is based on examples/empty.
For example, copy examples/empty to examples/<project_name>.
If <existing_project> and <new_project> are in the same parent directory,
the path to imports.mak does not need be updated. However, if the folder depth
changed, the path to imports.mak needs to be updated
in all files that include imports.mak.
For example, this combination of <existing_project> and <new_project>
requires updating the imports.mak path:
<existing_project>:examples/fft/split_radix_fft_4k_single_core<new_project>:examples/<project_name>
Once the path to imports.mak is correct, <project_name> can be built from the
project directory after updating any paths that use the project name. This is
discussed more in section
Rename the project and update paths.
$ cd /path/to/open-pru/examples/<project_name>
$ make -s
These are the only "critical" steps. You can now start development on
<project_name>.
The rest of this document discusses how to customize and clean up your project. If you will create a pull request to add your project to the main branch, you must follow ALL of the steps in this document to ensure that your project can be maintained into the future.
If the project contains processors, boards, or cores that will not be used in your project, you should remove the unused components.
If your project uses processors, boards, or cores that were not in the original project, you will need to add them or modify existing files. If you are using an existing OpenPRU project as your template other than one of the "empty" projects, and that does not have the processors, boards, or cores that your project needs, you may get the infrastructure for those processors, boards, or cores from the appropriate "empty" project. Just keep in mind that the steps in section Rename the project and update paths will need to be run twice: Once to update the code from the template project, and once to update the code from the "empty" project.
Note
Many PRU projects can be ported from one processor to another. However, sometimes a project will use features of the PRU subsystem that cannot be ported to other PRU subsystems. For example, PRU_ICSSG subsystems include accelerators and additional PRU cores that do not exist on PRU-ICSSM or PRUSS subsystems.
We suggest checking that all the desired features exist before porting a project to a new processor.
Check the portability tables before porting an example to another processor:
examples/readme.md§ "Supported processors per-project"academy/readme.md§ "Supported processors per-project"
Useful app notes:
These are the files & directories to modify or delete:
<project_name>/makefile<project_name>/<board>or<project_name>/<os>/<board><project_name>/firmware/<board>
The OpenPRU repo uses a hierarchical makefile structure. Each level calls the levels below it.
| Level | File | Modifications for a new project |
|---|---|---|
| Repo root | open-pru/makefile |
None |
| Parent directory | open-pru/examples/makefile |
Add project to SUBDIRS |
| Project | open-pru/examples/<project_name>/makefile |
Most modifications (see below) |
| PRU core | firmware/<board>/<core>/ti-pru-cgt/makefile |
Update build outputs and paths |
| Non-PRU core | <os>/<board>/<core>/<toolchain>/makefile or <board>/<core>/<toolchain>/makefile |
Update in a later step |
Remove non-PRU code for cores or operating systems that will not be used in your project. For example, if your project targets a Linux host, remove any MCU+ directory. If your project targets an MCU+ host, remove any Linux directory. If your project has no host code at all, remove all non-PRU code.
The non-PRU code is in a different directory than the PRU firmware. For the directory structure, see OpenPRU Organization.
Within the firmware/ subdirectory, remove EVM board directories that will not
be used in your project.
After cleanup, firmware/ should contain only the boards your project supports.
Find and replace the old project name and path with the new project name and path throughout the project. These references may be modified by hand, with a bulk find/replace, or with a script or AI agent.
First, find all references to the old project name:
$ cd /path/to/open-pru/examples/<project_name>
# search for filenames from the template project, in this case `empty`
$ find -name "*empty*"
# search for mentions within files
$ grep -r empty
Warning
Inspect the output carefully before running any bulk find/replace command, script, or AI agent. Review all changes before committing. Avoid replacing strings in unintended locations.
Within the project folder, there is a project makefile, and then makefiles for each core. There is a separate core makefile for every combination of processor and board. The project makefile calls all the other makefiles.
Every directory above the project folder also includes a makefile. This allows us to build the project from higher level directories.
Update PROJECT_NAME, SUPPORTED_PROCESSORS, PRU_DEPENDENCIES, and
NON_PRU_DEPENDENCIES.
SUPPORTED_PROCESSORS — List the processors this project supports. When
make runs, it builds the target that matches $(DEVICE) in imports.mak.
If $(DEVICE) is not in this list, make prints a message and exits without
building anything.
PRU_DEPENDENCIES — List any dependencies of the PRU firmware on code
outside the OpenPRU repo. For example, add mcuplus here if the PRU firmware
includes headers from the MCU+ SDK.
NON_PRU_DEPENDENCIES — List the non-PRU code this project should build.
Examples:
mcuplus— builds MCU+ R5F code alongside PRU firmware (AM243x, AM64x)linux— builds Linux userspace code alongside PRU firmware (AM62x, AM64x)- If
NON_PRU_DEPENDENCIESis empty, only PRU firmware is built
Add a target for each processor in SUPPORTED_PROCESSORS. Non-PRU targets use
the pattern <device>_<host> (for example, am243x_mcuplus, am62x_linux).
Example — MCU+ host (AM243x or AM64x):
am243x:
$(MAKE) -C firmware/am243x-evm/icss_g0_pru0_fw/ti-pru-cgt $(ARGUMENTS_PRU)
$(MAKE) -C firmware/am243x-evm/icss_g0_pru1_fw/ti-pru-cgt $(ARGUMENTS_PRU)
am243x_mcuplus:
$(MAKE) -C mcuplus/am243x-evm/r5fss0-0_freertos/ti-arm-clang $(ARGUMENTS_MCUPLUS)Note
Update the path to match your project's actual MCU+ directory structure.
Some projects place MCU+ code under mcuplus/<board>/ (e.g., examples/empty);
others place it directly under <board>/ at the project root
(e.g., academy/intc/intc_mcu).
Top-level make calls every project makefile. Prebuild checks ensure a project
only builds when imports.mak has the correct settings.
The DEVICE_NON_PRU variable is built up from NON_PRU_DEPENDENCIES:
- If
BUILD_MCUPLUS=yinimports.makandmcuplusis inNON_PRU_DEPENDENCIES, then$(DEVICE)_mcuplusis added toDEVICE_NON_PRU. - If
BUILD_LINUX=yinimports.makandlinuxis inNON_PRU_DEPENDENCIES, then$(DEVICE)_linuxis added toDEVICE_NON_PRU.
The all target then runs:
all: pre_build_message
$(MAKE) pru # builds $(DEVICE) — all PRU firmware
$(MAKE) host # builds each target in $(DEVICE_NON_PRU)If NON_PRU_DEPENDENCIES is empty, host is a no-op and only PRU firmware is
built.
Update:
- The include path for
imports.mak - Section Define build outputs
The makefile includes important information that you may need to modify later in development, like
- Where to search for source files
- Include paths
- Compiler flags
- Linker flags
- Defines
Update OUTPUT_NAME to match the new project name:
OUTPUT_NAME := <project_name>_am243x-evm_icss_g0_pru0_fwFor projects with a MCU+ host, also update the hex array output variables:
MCU_HEX_NAME := pru0_load_bin.h
HEX_ARRAY_PREFIX := PRU0Firmware
MCU_HEX_PATH := $(OPEN_PRU_PATH)/examples/<project_name>/firmware/am243x-evm/$(MCU_HEX_NAME)Note
If the new project is in a different parent directory than the source
project, update MCU_HEX_PATH accordingly — the relative depth to
$(OPEN_PRU_PATH) will have changed.
For projects with a Linux host (e.g., AM62x) or no host at all
(standalone PRU), MCU_HEX_PATH is not used by any host project. Only
OUTPUT_NAME requires updating.
Note
For projects without an MCU+ host, leave postBuildStep in
example.projectspec empty or omit it. The postBuildStep is only needed
when an MCU+ project must consume the generated hex array header from the
CCS workspace.
Important
Stop here. Verify that the PRU firmware builds successfully before making any further changes.
$ cd /path/to/open-pru/examples/<project_name>
# remove previous build outputs
$ make -s clean
# build with all output visible (no -s) to catch any errors
$ make
# if no errors, clean again before continuing
$ make -s clean
Add <project_name> to the makefile in the parent directory. That allows the
project to build from a top-level make command.
You already verified that the PRU code builds from the project directory in the Build checkpoint section. Now, check that the project make builds from the top-level directory.
$ cd /path/to/open-pru
$ make -s clean
$ make -s
This section discusses how to update the project files which are used to import the PRU project from the OpenPRU repo, into the CCS workspace.
For steps to import, rename, and build a CCS PRU project in the CCS IDE, refer to the PRU Academy > Getting Started Labs > Lab 1: How to Create a PRU Project > Creating a CCS PRU Project.
When a CCS project is created or imported from an OpenPRU project, CCS reads
example.projectspec to configure the project.
PRU projects which are written only in assembly code require different linker flags than PRU projects that include C code. Refer to the comment at the top of the example.projectspec file for guidance on whether that file uses the template for assembly code, or C / mixed C and assembly code:
<?xml version="1.0" encoding="UTF-8"?>
<!-- This example.projectspec file is for PRU projects written in assembly -->
or
<?xml version="1.0" encoding="UTF-8"?>
<!-- This example.projectspec file is for PRU projects written in C, or mixed C and assembly -->
Choose the flags that match your project:
| Flag | ASM (examples/empty) |
C (examples/empty_c) |
|---|---|---|
--disable_auto_rts |
yes | no |
--entry_point=main |
yes | no |
--stack_size, --heap_size |
no | yes |
-i${CG_TOOL_ROOT}/lib, -i${CG_TOOL_ROOT}/include |
no | yes |
--library=libc.a |
no | yes |
Compiler build options are identical between ASM and C projects.
Update the name attribute and the map file name to match
the new project. For example:
<project
title="<New Project Title>"
name = "<project_name>_am243x-evm_icss_g0_pru0_fw_ti-pru-cgt"
...
linkerBuildOptions="
-m=<project_name>.${ConfigName}.map
Both must stay consistent with PROJECT_NAME in makefile_projectspec.
The postBuildStep is used to generate a PRU hex array binary file, and then
write that binary file to a known location. If the project uses an MCU+ core,
the MCU+ project then takes the hex array file from that known location.
Note
In pru_rules.mak, post-build writes the hex array file to a location
within the OpenPRU repo, called TARGET_HEX. On the
other hand, in example.projectspec, the hex array file is written to a
location within the CCS workspace. postBuildStep writes the hex array file
to the root directory of the PRU project, one level above the
Debug/Release build output directory.
Example postBuildStep in PRU example.projectspec:
postBuildStep="
$(CG_TOOL_ROOT)/bin/hexpru --diag_wrap=off --array --array:name_prefix=PRU0Firmware -o ../pru0_load_bin.h ${BuildArtifactFileBaseName}.out;
"
The MCU+ project's example.projectspec must include the CCS workspace path
to the PRU hex arrays, like this:
compilerBuildOptions="
...
-I${WORKSPACE_LOC}/<project_name>_am243x-evm_icss_g0_pru0_fw_ti-pru-cgt
-I${WORKSPACE_LOC}/<project_name>_am243x-evm_icss_g0_pru1_fw_ti-pru-cgt
We discuss more about creating an MCU+ project in the OpenPRU repo in Adding MCU+ Code to a New Project in the OpenPRU Repo.
If the device changed, update:
-I${OPEN_PRU_PATH}/source/include/<device>
makefile_projectspec is used to build or export CCS projects from the
command line.
Update:
PROJECT_NAME— must match thenameattribute inexample.projectspecOPEN_PRU_PATH— same folder-depth rule asmakefile: if the new project is at a different directory depth than the template project, update the number of..levels accordingly
- Will the PRU be controlled by a core running MCU+ SDK? Continue to Adding MCU+ Code to a New Project in the OpenPRU Repo.
- Are you done creating your PRU project? Continue to the PRU Academy > Getting Started Labs > Lab 2: How to Write PRU Firmware.