Beaglebone PRU compilation
29-07-2023
Prerequisites
All commands should be ran as sudo.
Update the kernel by moving to the /opt/scripts/tools/ folder, running
git pull, and then running ./update_kernel.sh. If you're not running
a TI kernel, make sure to include \--ti-kernel or \--ti-channel in
the command. An example:
cd /opt/scripts/tools
git pull
./update_kernel.sh \--lts-5_10\--ti-kernel
Make sure you've got PSSP 6.0.0 or later. You can check by viewing
the README or the HTML page in
/usr/lib/ti/pru-software-support-package. If it's not 6.0.0, download
the PRU support
package
and extract it to the folder mentioned. For some reason, 6.1.0 has some
quirks too, and headers used in 6.0.0 might not work.
You'll also need the TI compiler, version 2.3.3 or later. Download the
installer
(click on "Download Options"), chmod +x it and run.
Compiling it with clpru
The following Makefile will compile all C and ASM files in the folder, so they can be linked further on.
You also don't have to set the PSSP location inside the Makefile, the
compiler looks for it in the PRU_SDK_DIR environment variable, but I'm
doing it for clarity purposes.
However, you should set PRU_C_DIR to the location of your libraries.
The value /usr/share/ti/cgt-pru/include;/usr/share/ti/cgt-pru/lib
works in default installations.
PSSP = /usr/lib/ti/pru-software-support-package
CC = clpru
CFLAGS = \--include_path=\$(PSSP)/include \\
\--include_path=\$(PSSP)/include/am335x \\
-v3 -O2 \--opt_for_speed=5 \--endian=little
SRCS = \$(wildcard \*.c)
PROGS = \$(patsubst %.c,%,\$(SRCS))
ASM_SRCS = \$(wildcard \*.asm)
ASM_PROGS = \$(patsubst %.asm,%,\$(ASM_SRCS))
all: \$(PROGS) \$(ASM_PROGS) pru1.out
%: %.c
\$(CC) \$(CFLAGS) \$\< \--output_file \$@
%: %.asm
\$(CC) \$(CFLAGS) \$\< \--output_file \$@
As for each flag:
-v3stands for silicon version 3, which is the one in all am335x Beaglebones.\--opt_for_speed=5just means we're maximizing speed in detriment of file size. You can change that as well.-O2uses optimization level 2, but feel free to use more agressive optimizations. Valid values are O0, O1, O2, O3 and O4.-endian=littleJust sets the endianness to little, as is the case with the PRU. This is implicit, but avoids confusion. Little endian just means we're going to store the least significant bytes before the most significant ones.\--include_pathis where we're telling the compiler to search for include files, you might need to change or add more paths depending on your use case.
Other useful flags:
-genables debugging flags. Useful for, well, debugging.
Linking with lnkpru
First of all, I'm going to recommend having a .cmd file to orchestrate the linking process. You can find examples in /usr/lib/ti/pru-software-support-package/examples/<your architecture>. This part of the Makefile assumes your .cmd file is placed inside the same folder as the rest of the code.
LD = lnkpru
LDFLAGS = AM335x_PRU.cmd
pru1.out: \$(ASM_PROGS) \$(PROGS)
\$(LD) \$(LDFLAGS) \$\^ -o \$@*
The only flag here is describing where we can find our linker command file, change it if you rename or move it.
After that, you should have a valid, ready-to-go PRU binary. Here's the completed Makefile:
PSSP = /usr/lib/ti/pru-software-support-package
CC = clpru
LD = lnkpru
CFLAGS = \--include_path=\$(PSSP)/include \\
\--include_path=\$(PSSP)/include/am335x \\
-v3 -O4 \--opt_for_speed=5 \--endian=little
LDFLAGS = AM335x_PRU.cmd
SRCS = \$(wildcard \*.c)
PROGS = \$(patsubst %.c,%,\$(SRCS))
ASM_SRCS = \$(wildcard \*.asm)
ASM_PROGS = \$(patsubst %.asm,%,\$(ASM_SRCS))
all: \$(PROGS) \$(ASM_PROGS) pru1.out
%: %.c
\$(CC) \$(CFLAGS) \$\< \--output_file \$@
%: %.asm
\$(CC) \$(CFLAGS) \$\< \--output_file \$@
pru1.out: \$(ASM_PROGS) \$(PROGS)
\$(LD) \$(LDFLAGS) \$\^ -o \$@
clean:
rm -f pru1.out \$(ASM_PROGS) \$(PROGS)*
What else?
As it might not be clear enough, some of these Makefile tricks that I've
used make life easier. We're using wildcard to grab all C and ASM
files, and then patsubst to create our output locations by replacing
our suffix (%.c or %.asm) with no suffix at all (%).
Then, we compile all of those (all) by setting the targets of all to
our expected output files, then our final compiled binary, pru1.out.
\$\< is going to replace itself with the first dependency (a single
file in this case), and \$@ with the target (our output). Then, \$\^
replaces itself with all dependencies, space separated.