EmbeddedRelated.com
Blogs

Using the C language to program the am335x PRU

Introduction

Some weeks ago, I published an article on how we used the PRU to implement a power supply control loop having hard realtime constraints:

//www.embeddedrelated.com/showarticle/586.php

Writing this kind of logic in assembly language is not easy. First the assembly language itself may be difficult to learn depending on your background. Then, fixed and floating point arithmetics require lot of code. While macros help to handle the complexity, they still are error prone as you must be very careful to enforce rules as regard with register usage for instance. This is especially difficult in projects involving several people, who are not used to work together and not full time on the project. Even if the rules are well established, people tend to forget them when they come back in the project from time to time, several weeks apart.

This article is available in PDF format for easy printing

Someone pointed that TI introduced C support in the latest Code Composer Studio version. For me, using the C language clearly helps in the above issues so I started to investigate this feature. Several people contacted me to know if I made any progress on using the C language to program the PRU. My answer is that the toolchain proposed by TI, called CGT (Code Generation Tools) is very usable once the different tools and some details have been understood.

This article describes how to setup and use the PRU C toolchain, and includes a simple example.

Prerequisites

I have a GITHUB repository containing all the materials related to this article. Please clone it from here:

https://github.com/texane/pru_sdk

The build system assumes that the 2 following variables are correctly set (for instance, using the export shell command):

  • CROSS_COMPILE: points to your ARM toolchain,
  • PRU_SDK_DIR: points to the directory where you cloned the repo.

Refer to the previous article for more information on how to use it.

Installing the PRU C toolchain

The PRU C toolchain is too big for me to include it in the pru_sdk repo. Thus, you have to install it manually. The following describes how to do so.

First, you have to download the installer from here:

http://processors.wiki.ti.com/index.php/Download_CCS

Registration is required but it is free and runs on both LINUX and Windows. During the installation, you must enable PRU support. Please refer to the following link for more info:

http://www.element14.com/community/community/knode/single-board_computers/next-gen_beaglebone/blog/2014/04/30/bbb--pru-c-compiler

The toolchain is located in the CCS installation directory called pru_2.0.0B2. If you do not find it, you may have to start CCS and install missing components using the GUI menus. The pru_2.0.0B2 directory is self contained and can moved anywhere to be used as is. Please put it in the pru_sdk directory you created previously.

pru_2.0.0B2/bin contains the usual tools:

  • clpru: a C compiler,
  • asmpru: an assembler,
  • dispru: a disassembler,
  • lnkpru: a linker,
  • hexpru: an output file generation tool,
  • others tools to have information on binary (ELF) files.

Also, TI provides a C standard library and a runtime, with the sources included. It can be found in the pru_2.0.0B2/lib directory. More information can be found in the README.txt file and man pages in pru_2.0.0B2/man.

Installing the PRU loader

To load application and interact with the PRU from LINUX, I use the opensource library found here:

https://github.com/beagleboard/am335x_pru_package

One important feature is the loading and execution of PRU binary files. In our case, it must be noted that the starting address will not be 0. Rather, it is located at a symbol called _c_int00, which can be anywhere in the text section. Thus, I had to modify the loading library so that an address can be specified in the routine:

prussdrv_exec_program

This was done by adding a new routine, without breaking existing interfaces:

prussdrv_exec_program_at

It writes the PRU control register address fields, as specified in am335xPruReferenceGuide section 5.4. Refer to examples/pruss_c/host_main.c for an example.

I put the new library in the pru_sdk repo, and I will submit a patch to the official repository soon.

Compiling and running a program

I added an example for this article in the pru_sdk repo, directory example/pruss_c.

The code itself simply does a floating point multiplication on the PRU and puts the result into the memory shared, refer to pru_main.c The CPU reads and display the result, refer to host_main.c

I made a simple script that compiles everything, refer to example/pruss_c/build.sh .

I will integrate it to the pru_sdk build system later. The script works as follow:

  • invoke the compiler to produce object files from PRU C files,
  • link them to produce an ELF file,
  • extract code and data binary from the ELF file,
  • retrieve the start address,
  • compile the CPU program, to be run on the Beagle Bone Black.

At the end of the process, the following files are produced:

  • pru_enable-00A0.dtbo: the device tree overlay enabling the PRU,
  • main: the ELF program to be run on the CPU,
  • text.bin: the binary file to initialize the PRU code,
  • data.bin: the binary file to initialize the PRU data.

You must copy the following files to your BBB board:

  • pru_enable-00A0.dtbo into /lib/firmware,
  • run.sh,
  • main, text.bin and data.bin.

On the BBB, the program is then run using run.sh. It is a small wrapper taking care of loading the uio_pruss driver and enabling the PRU.

Using inline assembly

Accessing some parts of the hardware still require assembly code. Previously, we took care of wrapping this code inside macros. I am in the process of porting these macros into functions usable from C code.

The functions are kept minimal and implemented using inline assembly. The inline assembly support is not as advanced as the GCC one, especially lacking support to describe register usage.

One important thing is to know the calling convention and rules used by the PRU C compiler. They are described in the README.txt. To summarize:

  • r2 contains the stack pointer,
  • r3 contains the return address,
  • r14 to r29 are used for argument passing,
  • r14 is used for the return value,
  • r3 to r13 must be saved by the callee.

You can look at pru_hal.c for examples. It is still in progress, but gives the idea.

More to come

I am now in the process of rewriting the low level hardware related routines in C. I started with inline assembly, but it may be possible to use intrinsics instead. This is to be investigated.

Another thing to investigate is the generated code size, as the PRU program memory is limited to 8KB. From what I have seen, CLPRU does a good job and provides different optimization options to reduce the generated code size. I will soon see if it is enough.

One may argue about using the PRU C toolchain directly from command line instead of using the CCS software. It is a valid point, as CCS is freely available. Personnaly, I prefer the command line especially as I do not always have a usable X connection to the machine hosting the build system we use for the PRU.

Updates

A reader gave a link to download the PRU C compiler without the whole CCS software:

http://software-dl.ti.com/codegen/non-esd/downloads/beta.htm



[ - ]
Comment by verminskyJune 6, 2014
THANK YOU!!!! I have been struggling with this
for days, and just found your article. Your efforts are
very much appreciated. Please keep posting your progress

By the way, I found a link on TI's site where one can
Download just the PRU C Compiler ( without the whole CCS)

http://software-dl.ti.com/codegen/non-esd/downloads/beta.htm

[ - ]
Comment by texaneJune 6, 2014
I have updated the article with your link. Thanks for the tip !
[ - ]
Comment by ukindlerJune 10, 2014
Great tutorial - thank you very much. I'm very interested in using the C compiler for the PRU so I'm already googled a nice PRU C example:

https://github.com/BeaglePilot/PRUSS-C.

They also modified the am335x_pru_package to support loading the data.bin and text.bin files separately. But they do not provide an entry address like you do - so I'm not sure if this is really neccessary?!? There is a nice blinkled example in subfolder am335x_pru_package\pru_sw\example_apps\blinkled of this repository that shows how to execute a PRU programm compiled with the TI PRU C compiler.
[ - ]
Comment by texaneJune 10, 2014
Thanks for the tip. Actually, I do not know how they make it work without specifying an entry point. I guess that they managed (by chance, or by knowing it implicitly ...) to have the pre main initialization code at 0, esp. as they are using the stack for local variable 'int i' . In the example I show (float multiplication), the entry point is not at 0 (refer to the resulting MAP file). So specifying the entrypoint is required. There are other solution than changing the entrypoint, but I wanted to use the TI C library 'as is'. I hope it answers your question :)
[ - ]
Comment by longqiSeptember 16, 2014
I compiled then I got the error: http://pastebin.com/kcSsc7CN
but I did get the prumain.elf, data.bin and text.bin, So I guess the cross compiler is the wrong one, So I changed to another one which from CCS 6, but still have error http://pastebin.com/gRZNAJ48
Could you help me?
[ - ]
Comment by texaneSeptember 16, 2014
Hi,

I already replied to Marcus on this particular point:
Hi Marcus,

You have to install and use the modified am335x_pru_package
available in the pru_sdk repository, which provides the missing
routine.

Cheers,

Fabien.
[ - ]
Comment by dghenkeJune 6, 2014
Hugely helpful; many thanks. I knew about the PRU C compiler (thanks to prior communication with your previous commenter, actually) and had done some PRU assembly programming on the Beaglebone Black, but had not yet been able to connect the dots to get working C code on that platform. Like you, I prefer using command-line tools whenever possible.

Happy hacking!
[ - ]
Comment by ukindlerJune 10, 2014
Yes, indeed - you are right. If I compile the given blinkled example and link to the starteware library for pru, then my map file shows:

ENTRY POINT SYMBOL: "_c_int00_noinit_noargs_noexit" address: 000002d4

Your solution seemsto be the right one - great and many thanks :)
[ - ]
Comment by verminskyJune 13, 2014
Hello again. I'm still struggling with how one would load the data.bin file into PRU RAM. I noticed in your host_main.c program, you have this as a "TO DO". I also looked at the BeaglePilot/PRUSS-C blinked example on his github repo and see that he added functions to the libprussdrv.so to handle loading data files into PRU Data Ram. However, can't seem to find source code for these functions, or for the other functions in libprussdrv anywhere. Admittedly, I am no expert in any of this, but I am hoping that you might have written such a function for your libprussdrv, or could point me to information that might permit to attempt todo so.

Thanks.
[ - ]
Comment by texaneJune 14, 2014
Hi,

Actually it was left as a TODO until someone needed it. I integrated the support for data loading, as done in the BeaglePilot/PRUSS-C github repo. I am pretty confident it will work, but I did not test it yet. If you do please let me know if it works. Everything is in the latest branch of the pru_sdk repo. Thanks for your comments !
[ - ]
Comment by verminskyJune 13, 2014
Duh... I just found the source code for the prussdrv - I think I will be able to write a function to load the data.bin file into PRU_Dataram... we'll see :)
[ - ]
Comment by verminskyJune 14, 2014
Thank you! I just happened to look at your page again now and saw your reply, and the added data loading functions. I shall try this all out tomorrow and will let you know how it goes. I am continually surprised by the Linux/Beaglebone community and how people go out of their way to be so helpful. It gives one hope!
[ - ]
Comment by texaneJune 14, 2014
Yes, people in the BBB are quite reactive. Let me know about your progress!
[ - ]
Comment by verminskyJune 18, 2014
Well today, after getting distracted by non-lectronic, family related issues, I was finally able to compile the new libpruss libraries and get all the CROSS_COMPILE paths and exports working and successfully got your pruss_c
example to generate all the files. But I got an error message when the build script tried to generate the pru_enable.dtbo overlay file. It complains about a missing "(" in the .dts file. Didn't have time yet to track that down, but I did add some global variables to the pro_main.c file and manipulated them and they show up in the map file and the data.bin file size is larger. Tomorrow, hopefully, I can finish and actually load it onto my BBB and report back success! Thanks again.
[ - ]
Comment by texaneJune 18, 2014
Hi,

the DTC tool is used to generate the DTBO from DTS. The only reason I see it to fail is that I compiled DTC for a 64 bits architecture using shared libraries. It may fail to execute on your own platform, either because of the hardware architecture or missing dependencies. In this case, you may have to compile the DTC tool yourself.

I just added the DTC source code and a build.sh script in the pru_sdk repository. Please rebuild the DTC tool using the script, and put the resulting binary in the correct directory... I hope this should fix your issue.

Cheers !
[ - ]
Comment by verminskyJune 18, 2014
Hello again! Thanks for doing all this extra work. Indeed, I am running a 32bit version ofdebian on VirtualBox on the Windows side of an iMac boot camped into Windows 7... I had already downloaded and compiled a 32 bit version of DTC, so all that was necessary was for me to change your top.mk file in the build directory and I finally got everything to compile correctly.

I then scp'd all the necessary ties over to my debian BBB, and voila - it works!

Now, I still have much to learn, but thanks to you help, I have a working example to guide me. This has also forced me to learn more about make files and shell scripts, and has propelled me further on my journey of knowledge.

Thank you so very much for all your help and time
[ - ]
Comment by texaneJune 19, 2014
Hi,

I am glad it works and you have learned new things along the way. Also, it did improve the pru_sdk repo, so it was a good interaction.

Cheers,
[ - ]
Comment by olinMarch 16, 2015
Hi,
I cannot reply directly to texane's answer, so I'll post it here. The DTC tool in the pru_sdk/dtc_src (version 1.2.0-g37c0b6a) doesn't work properly even recompiled on my bbb. I get the same error as you had:
Syntax error: "(" enexpected.
When I modified the top.mk to use system default dtc tool (version 1.4.0 on debian wheezy) the dtbo compilation was OK.
[ - ]
Comment by Jason KridnerJune 24, 2014
You can download the C compiler (including for ARM to run on the BeagleBone Black itself) without installing CCS. See http://elinux.org/Ti_AM33XX_PRUSSv2#TI
[ - ]
Comment by texaneJune 25, 2014
Thanks. I already mentioned it in the updates section.
[ - ]
Comment by Nick WernickeJuly 24, 2014
Got it working! Thanks for doing all the legwork on this. I'm not sure if it is running correctly, it probably is since it ran at all, but it gives me more confidence if I can see the program outputs match. Do you have an example of the output? Here is what it said for me:
0xdeadbeef (-6259853398707798016.000000)
0x2b2b2c2d (0.000000)
0x41fb51ec (31.415001)
0x2404287b (0.000000)
0x9e9b6c26 (-0.000000)
0xad8883d0 (-0.000000)
0x56b5a8ac (99868022407168.000000)
0x2cd21c2e (0.000000)
[ - ]
Comment by texaneJuly 25, 2014
Hi Nick, the output is correct :)
[ - ]
Comment by marcus28August 5, 2014
Hi Sir :

I do every step you mention above, however, when I compile, there is an error message shows "undefined reference to 'prussdrv_load_datafile".

I google the error message, and someone says that libprussdrv.so causes this problem, so I change the file after I successfully compile app_loader.

But this problem still happens, could you give me some suggestions?

I use build.sh to build your example and should I modify top.mk?

My host is ubuntu 12.04 LTS 32-bit OS.

Thanks for your help!
[ - ]
Comment by texaneAugust 5, 2014
Hi Marcus,

You have to install and use the modified am335x_pru_package
available in the pru_sdk repository, which provides the missing
routine.
[ - ]
Comment by marcus28August 5, 2014
Hi texane :

It is my fault, now, I can compile successfully.

Thanks for your help!
[ - ]
Comment by turbobobAugust 17, 2014
I'm attempting to develop a project using the latest PRU compiler. I got the example code working, and as I work further I am uncovering bugs. Is there a contact at TI for bug reporting.

Anyone else having issues with the compiler?

Bob
[ - ]
Comment by texaneAugust 17, 2014
Hi,

Thanks for the info. You can contact TI using the community forums:
http://e2e.ti.com/support/arm/sitara_arm/default.aspx

When you have it, please post here the URL of your forum thread so
that others can know about the bugs you are mentioning, and the
eventual fixes.

Thanks !
[ - ]
Comment by turbobobAugust 22, 2014
The bugs were really instabilities in my toolchain, and old library code that was not working well with the latest compiler. Everything is working pretty well now.

You created an _at version of the exec functions, but it seems there is a way to force the linker to put the entry point at 0 (the latest TI examples show it)

putting the following in the linker command file (or using the latest example from TI) removes the need for presetting the PRU program counter, and allows the prudebug command line functions to work properly as well. (I'm debugging remotely)

.text:_c_int00* > 0x0, PAGE 0

I set up the build to create the header file so I can use the exec_code functions (the new compiler won't create them like pasm did)

this might make a good addition to your example code.

Bob
[ - ]
Comment by texaneAugust 22, 2014
Thanks for the tip, it will largely simplify the examples. I added
a todo to my repo so that I can work on it when I find some time.
[ - ]
Comment by navin40August 22, 2014
Hi Texane,

While compiling the code code i am getting lot of file inclusion error, because i am using ccs toolchain for ARM.
where can i download the toolchain arm-buildroot-linux-uclibcgnueabi . Please help me.

Navin
[ - ]
Comment by texaneAugust 22, 2014
Hi,

it depends on the platform you are on (Windows, Linux, 32 bits or not ...). A good
starting point to get a precompiled toolchain for Linux is:
http://elinux.org/ARMCompilers

You can also compile it by hand. I do it using crosstool-ng:
crosstool-ng.org/
[ - ]
Comment by texaneAugust 22, 2014
Also, have a look at you distribution package management system, it may provide
you with a default one.
[ - ]
Comment by navin40August 27, 2014
Hi Texane,

After successful compilation, I copied the files to BBB and I run the script run.sh. After I got the below error

FATAL: kernel too old
Segmentation fault

My BBB version ==> Linux beaglebone 3.8.13-bone50 #1 SMP Tue May 13 13:24:52 UTC 2014 armv7l GNU/Linux

Please help me.

Regards,
Navin

[ - ]
Comment by texaneAugust 27, 2014
Hi,

you must link against a C library that complies with your kernel. I can not help you
much on this particular point, sorry.

Texane.
[ - ]
Comment by longqiSeptember 16, 2014
Finally I make it. thank you so much.
[ - ]
Comment by texaneSeptember 16, 2014
Great, you are welcome
[ - ]
Comment by raymadiganSeptember 19, 2014
I got the pruss_c example to work and in an attempt to understand more I changed the pru_main.c file to write the entries at a different offset to the shared memory start. Something like:
{
shm_write_uint32(0x0120, 0xdeadbeef);
shm_write_uint32(0x0124, 0x2b2b2c2d);
shm_write_float(0x0128, x);
}

and not changing host_main at all, I built it and ran it and the answers were the same as if I had not written it to a different offset. I'm looking for the reference for how to read the registers from the c function calls. Or any hints to make some progress. Even what my mistake in thinking is?

Thanks
[ - ]
Comment by raymadiganSeptember 20, 2014
That was pretty silly, If I didn't erase it or reboot, why wouldn't it be there? Sorry for the bother.
[ - ]
Comment by texaneSeptember 21, 2014
Hi,

I do not know what the error is. Why are you using 0x120 offset to write your values ?
[ - ]
Comment by raymadiganSeptember 21, 2014
I just wanted to be general, when I write my app I will double buffer data into the shared memory. It works as it should, there is no error. I forgot that I didn't erase the memory at zero so it was still there. I write to offset 0x120 in the pru and read from the 30th uint32 in the host. It all works well.

I am now working on host to pru interrupts using WBS.

Thank you for all of your hard work
[ - ]
Comment by raymadiganSeptember 21, 2014
Do you know of a forum or place to share or get ideas why code doesn't seem to work? As an example I am trying to get the pruss to block waiting for the host to interrupt and I can't seem to find the right combination.
[ - ]
Comment by texaneSeptember 21, 2014
You can use the TI forums, for instance here:
http://e2e.ti.com/support/embedded/linux/f/354.aspx
[ - ]
Comment by raymadiganOctober 2, 2014
Sorry, I said that wrong, My question is when using the c language bindings many times the instructions that are used in different samples I find on the web won't compile. The one I posted above for instance.

I am trying to figure out how to clear an interrupt and I know what I wrote above isn't right, but it won't compile.

I am trying to clear the ARM_PRU0_INTERRUPT once pru0 responds to it. and I don't know if it is the right logic or if the compile is giving me grief. It seems easy enough.

The ARM_PRU0_INTERRUPT is 21
The STATCLRINT0 offset is 0x280

and what I want to do is:

" LDI R14, 21 \n"
" LDI R15, 0x280 \n"
" SBCO R14, C0, R15, 4 \n"

But the last line won't compile
[ - ]
Comment by aadavidsNovember 4, 2014
If you're still having trouble, I had the same problem and figured it out.

From the README:
6. Operands with a '&' prefix
The existing PASM assembler accepts operands with or without the &
symbol: LBBO &r0 or LBBO r0. The assembler in this release requires the
& for these operands.

You need the & if you're writing inline assembly. Try " SBCO &R14, C0, R15, 4 \n" and it should compile.
[ - ]
Comment by raymadiganOctober 2, 2014
First, thanks for all you did to get this started for me. I have done a few things but my biggest problem in trying things is that there are assembly instructions that result in Invalid instruction messages that people use in the assembler just fine. For example

" SBCO R14, c0, 0x24, 4 \n"

this is used often to clear system interrupts but it won't compile for me. The read me talks about some instructions, like MOV that can't be used in specific circumstances. Is there a place to look to find how to alter the instruction to work?
[ - ]
Comment by texaneOctober 2, 2014
[ - ]
Comment by elkNovember 8, 2014
Hello,
I am trying to compile your example directly on the Beaglebone Black (rev C). I downloaded the standalone compiler to the bbb as well as your repository. When I run your build script I am running into the following error:
/usr/bin/ld: error: main uses VFP register arguments, /home/..../pru_sdk/lib/libprussdrv.a(prussdrv.o) does not
/usr/bin/ld: failed to merge target specific data of file /home/...pru_sdk/lib/libprussdrv.a(prussdrv.o)

I tried compiling with gcc with different options such as -mfloat-abi=soft but it doesn't seem to make a difference.
Do you know how to compile your example on the bbb directly using gcc?
[ - ]
Comment by olinMarch 16, 2015
Hi,
I have the same problem. It looks the pre-built libraries in pru_sdk/lib are incorrect. Try entering pru_sdk/am335x_pru_package/pru_sw/app_loader/interface and running make. This should produce new libraries (in ../lib) which you copy into pru_sdk/lib. Then recompile the example - the linking stage should not fail this time.
[ - ]
Comment by SergejHeccNovember 11, 2014
Hi,

Have anyone tried to compile the example using the linaro toolchain? I tried to crosscompile the example under ubuntu 14.04 LTS and get a list of warnings/errors:

sergej@ubuntu:~/pru_sdk/example/pruss_c$ ./build.sh

Translating to Binary format...
"./pru_main.elf" .text ==> .text
rm -f host_main.o ../common/mio.o
rm -f
rm -f pru_enable-00A0.dtbo
rm -f main
/home/sergej/qt-bbb/gcc-linaro-arm-linux-gnueabihf-4.7-2013.04-20130415_linux/bin/gcc -DSTART_ADDR=0x0000032c -Wall -O2 -mtune=cortex-a8 -march=armv7-a -I/home/sergej/pru_sdk/include -c -o host_main.o host_main.c
host_main.c: In function ‘main’:
host_main.c:78:3: warning: implicit declaration of function ‘prussdrv_load_datafile’ [-Wimplicit-function-declaration]
host_main.c: At top level:
host_main.c:13:13: warning: ‘zero_words’ defined but not used [-Wunused-function]
/home/sergej/qt-bbb/gcc-linaro-arm-linux-gnueabihf-4.7-2013.04-20130415_linux/bin/gcc -DSTART_ADDR=0x0000032c -Wall -O2 -mtune=cortex-a8 -march=armv7-a -I/home/sergej/pru_sdk/include -c -o ../common/mio.o ../common/mio.c
/home/sergej/qt-bbb/gcc-linaro-arm-linux-gnueabihf-4.7-2013.04-20130415_linux/bin/gcc -static -o main host_main.o ../common/mio.o -L/home/sergej/pru_sdk/lib -lprussdrv
/home/sergej/qt-bbb/gcc-linaro-arm-linux-gnueabihf-4.7-2013.04-20130415_linux/bin/../lib/gcc/arm-linux-gnueabihf/4.7.3/../../../../arm-linux-gnueabihf/bin/ld: error: main uses VFP register arguments, /home/sergej/pru_sdk/lib/libprussdrv.a(prussdrv.o) does not
/home/sergej/qt-bbb/gcc-linaro-arm-linux-gnueabihf-4.7-2013.04-20130415_linux/bin/../lib/gcc/arm-linux-gnueabihf/4.7.3/../../../../arm-linux-gnueabihf/bin/ld: failed to merge target specific data of file /home/sergej/pru_sdk/lib/libprussdrv.a(prussdrv.o)
host_main.o: In function `main':
host_main.c:(.text.startup+0xaa): undefined reference to `prussdrv_load_datafile'
collect2: error: ld returned 1 exit status
make: *** [main] Error 1

What does it want?
[ - ]
Comment by Sergej30November 11, 2014
I tried to use am335x_pru_package from pru_sdk, but the error "undefined reference to `prussdrv_load_datafile'" still presents.
[ - ]
Comment by texaneNovember 11, 2014
I really do not know then ... do you use the latest repository commit ? I tried it last week, did not see you problem after proper recompilation of libprussdrv
[ - ]
Comment by Sergej30November 12, 2014
Finally I managed to launch your example. It turned out that I forgot to recompile prussdrv lib. Now everything is nice.
Thank you Fabien for your extremely useful job.
[ - ]
Comment by texaneNovember 12, 2014
Great, you are welcome !
[ - ]
Comment by Sergej30November 13, 2014
Inspite of of presence of TI C compiler it seems people prefer to use asm for PRU programming. I found only 2 examples on the web (1 is yours) using C code for BBB PRU. Why it is not widely used?
[ - ]
Comment by texaneNovember 13, 2014
Some people, especially those with realtime backgkround (ie. DSP, FPGA),
do not mind programming in assembly. And the PRU assembly is quite simple,
which makes it even more appealing to them. Also, the C compiler PRU support
is relatively recent.

That being said, I see more and more physics institutes interested in
using the PRU to replace MCU + DSP/FPGA based solutions. The main reasons
being costs reduction and the simplicity of hard and soft resource sharing
between the PRU and the MCU.

I hope the beagleboard platform will democratize this approach to more open
source projects. When needed, this is much more powerful than the competition
(RPI...)
[ - ]
Comment by navin40December 1, 2014
Hello Texane ,

Could you please share the GCC version used in crosstool-ng while building compiler.

My BBB version ==> Linux beaglebone 3.8.13-bone50 #1
ubuntu 12.04
[ - ]
Comment by texaneDecember 1, 2014
Hi,

At the time, I used this version:
texane@debian:~$ ~/repo/lfs/_work_bbb_home/src/crosstool-ng/ct-ng version
This is crosstool-NG version 1.18.0

The base configuration file is:
armv6-rpi-linux-gnueabi
[ - ]
Comment by olinMarch 16, 2015
Hi texane,

thanks for the tutorials and the source code. It works on my bbb, compiled directly on bbb!
Here is the summary of the issues I had:
- libs in pru_sdk/lib dont contain the load function (had to recompile and replace the libs)
- prus_sdk/dtc_src doesn't like the dts file - even recompiled (had to use more up-to-date dtc version 1.4.0)
- after copying pru_enable-00A0.dtbo into /lib/firmware and when running sudo ./run.sh I got error: prussdrv_open open failed. The solution is to restart the BBB (hasn't been mentioned) !

After that the pruss_c example compiles works fine. Thanks again.
[ - ]
Comment by texaneMarch 17, 2015
Thanks for the feedback !
[ - ]
Comment by jdcoburnMarch 17, 2015
Hi - I'm trying to get around TI's reluctance to share their code on the Industrial Control SDK for the PRU's. So, several of the header files contains the byte array of the PRU firmware. I copied and pasted it out of the text header file, converted it to a byte array and exported it to a bin file (labeled as .out) I don't know the byte order so I did it both ways (little endian and big endian), and then ran the disassembler. Either way, I get a segmentation fault in the disassembler. I assume there's a format issue with the download code and what the disassembler is expecting. can any one verify this?
thanks,
Jim
[ - ]
Comment by Sergej30April 7, 2015
Hello Fabien,

I'm trying to fight with the arm to pru memory writing. Your examples work fine and now I try to use shm_read function in this way (modifying your 1st c example):

shm_write_uint32(0, 0xdeadbeef);
shm_write_uint32(4, shm_read(0));
shm_write_float(8, x);

and I get the following output:

0xdeadbeef (-6259853398707798016.000000)
0x206f6f54 (0.000000)
0x41fb51ec (31.415001)
0x155e0900 (0.000000)
0x45db452b (7016.645996)

What's the reason?
I'm absolutely new for the asm and currently it is hard for me to find the problem.
[ - ]
Comment by SergejHeccApril 9, 2015
ok, I found my mistake. I wrote to another location and your shm_read works fine. Thanks again.
[ - ]
Comment by skm029April 19, 2015
Hi Febian,

I am trying to compile your sample example code using PRU C Compiler. But i'm facing the following issue,
On running ./build.sh, the script throws up error complaining about the missing top.mk file.
Error log below:
./build.sh

Translating to Binary format...
"./pru_main.elf" .text ==> .text
Makefile:6: /home/ti/ccsv6/tools/compiler//build/top.mk: No such file or directory
make: *** No rule to make target `/home/ti/ccsv6/tools/compiler//build/top.mk'. Stop.
Makefile:6: /home/ti/ccsv6/tools/compiler//build/top.mk: No such file or directory
make: *** No rule to make target `/home/ti/ccsv6/tools/compiler//build/top.mk'. Stop.

But the ccsv6 installed doesn't have any build directory at all where your script is looking for top.mk file.Please let me know if i have missed anything and help me in solving this.

Thanks
Keshav
[ - ]
Comment by skm029April 19, 2015
Hi ,

Sorry..my fault..was referring to wrong path. Issue fixed.

Thanks
Keshav
[ - ]
Comment by catalin_clujJuly 16, 2015
Thank you for a great intro. (or two) to the PRU.
I have some very specific needs that seem possible but would like confirmation, if possible, before I start digging:
I need to run a long sequence of hard-real-time events (output on GPIO).
The list contains periods between outputting things on GPIO and the GPIOs to output what on.
The list would be too long to reside in the PRU memory but could be buffered by it (circular buffer?).
The main processor would have the whole list and feed it to the PRU as it runs through the list.
The main processor would need to be able to synchronize other things (send SPI data for example) with the sequence. (Or the PRU could send data over SPI but it would need to get it from the main processor)
The whole sequence could run for a few days.
I need the timing to stay "correct" down to the clock cycle (no variable latency, etc)
Os this doable on the BBB?
Thanks,
Cat
[ - ]
Comment by texaneJuly 31, 2015
Hi,

There are 2 things to consider.

First, you can use the PRU dedicated GPIOs to solve the communication realtimeness problem. It applies for the SPI.

Regarding the memory space issue, you can put your list of actions into the DDR that is accessible from both the CPU and the PRU. However, note that the DDR accesses are not realtime since the bus is shared with the CPU. In practice, I doubt this is an issue for your application ...
[ - ]
Comment by navin40July 18, 2015
Hi Fabien ,

I am facing one strange issue while compiling my code. I downloaded ti-processor-sdk-linux-am335x-evm-01.00.00.03-Linux-x86-Install.bin from ti for my development . while compiling i am getting the following error.

Translating to Binary format...
"./pru_main.elf" .text ==> .text
rm -f host_main.o ../common/mio.o
rm -f
rm -f pru_enable-00A0.dtbo
rm -f main
/opt/linux-devkit/sysroots/i686-arago-linux/usr/arm-linux-gnueabihf/bin/gcc -DSTART_ADDR=0x0000032c -Wall -O2 -mtune=cortex-a8 -march=armv7-a -I/opt/pru_sdk-master//include -c -o host_main.o host_main.c
gcc: error trying to exec 'cc1': execvp: No such file or directory
make: *** [host_main.o] Error 1

I know it is the compiler preprocessing stage for converting c file to assembly . cc1 is available in my directory but compiler is not able to include . Did anyone faced this issue or please let me know how to give the reference for this.

I am using BBB revision 3 and ubuntu 12.04 for cross platform.

Thanks
Navin
[ - ]
Comment by navin40July 19, 2015
Sorry , I was wrongly pointed out the target path.
[ - ]
Comment by navin40July 19, 2015
Hi Febian ,

I am facing problem while linking with dtc


Translating to Binary format...
"./pru_main.elf" .text ==> .text
rm -f host_main.o ../common/mio.o
rm -f
rm -f pru_enable-00A0.dtbo
rm -f main
/opt/ti/linux-devkit/sysroots/i686-arago-linux/usr/bin/arm-linux-gnueabihf-gcc -DSTART_ADDR=0x0000032c -Wall -O2 -mtune=cortex-a8 -march=armv7-a -I/opt/pru_sdk-master//include -c -o host_main.o host_main.c
host_main.c:13:13: warning: ‘zero_words’ defined but not used [-Wunused-function]
/opt/ti/linux-devkit/sysroots/i686-arago-linux/usr/bin/arm-linux-gnueabihf-gcc -DSTART_ADDR=0x0000032c -Wall -O2 -mtune=cortex-a8 -march=armv7-a -I/opt/pru_sdk-master//include -c -o ../common/mio.o ../common/mio.c
/opt/ti/linux-devkit/sysroots/i686-arago-linux/usr/bin/arm-linux-gnueabihf-gcc -static -o main host_main.o ../common/mio.o -L/opt/pru_sdk-master//lib -lprussdrv
/opt/ti/linux-devkit/sysroots/i686-arago-linux/usr/bin/arm-linux-gnueabihf-strip main
/opt/pru_sdk-master//bin/dtc -@ -O dtb -o pru_enable-00A0.dtbo pru_enable-00A0.dts
/opt/pru_sdk-master//bin/dtc: 1: /opt/pru_sdk-master//bin/dtc: Syntax error: "(" unexpected
make: *** [pru_enable-00A0.dtbo] Error 2

Please let me know how to resolve this issue.

regards,
Navin
[ - ]
Comment by rathinAugust 12, 2015
Hi Thank you for fabulous article and excellent support.

I have one really silly doubt, that I cant find pruss_c or ./build.sh file any where in your repo!! and I am not able to follow anything!! can you help me with that? I have a BBB I have installed Ti's default PRU c compiler and have downloaded your repository, but I am stuck now!! I cant find my way out.

I am completely new to this domain, I have just started off in realtime and embedded thing so my question might sound silly, pardon me for that.

Rathin
[ - ]
Comment by rathinAugust 12, 2015
sorry I forgot to mention but I am trying to compile your code example on my BBB "make all" but still it says "arm-arago-linux-gnueabi-gcc:" not found!! I am already on my "target" platform so I am not supposed to have "cross_compiler", setup right?

I presuppose we need CorssCompiling only if we are developing on another machine and target is different!! Is my understanding wrong?

Rathin
[ - ]
Comment by rathinAugust 12, 2015
I sincerely APOLOGIZE, I was looking up & confusing with your another repo. hence I was not able to find build and run files..
Though I am bit clueless, i will try finding my way,( some guidance would be helpful, though :)

Thanks a lot and hats off to such magnanimous efforts!
Rathin
[ - ]
Comment by texaneAugust 12, 2015
Hi Rathin,

you are right, cross compiling is needed only if you are on
a machine which is not the target one.

I can help you, but as you guessed it will be easier for me
to have precise questions.

Cheers !
[ - ]
Comment by rathinAugust 12, 2015
Hi,
Thank you VERY much for prompt reply.
Yes, true - I also believe in self learning, Hence let me work on it and if I get stuck I will "trouble" you :)

Thanks in advance..
[ - ]
Comment by rathinAugust 14, 2015
Dear Febian,
I was finally able to setup the environment on my BBB. but I got stuck elsewhere, here is my status

I installed TI's PRU's cgt on BBB "ti_cgt_pru_2.1.1_armlinuxa8hf_busybox_installer.sh"
so I have all necessary headers, libs and compilers ( clpru, pasm etc).

Now I took your code repo and tried compiling the pruss_c files, using "./build.sh" but being designed for crossCompilaition, it gave me error for CGT & SDK paths, hence I manually passed parameters to my CLPRU like this "clpru --silicon_version=2 --hardware_mac=on -i/usr/lib/ -i/usr/include -c pru_hal.c".

I also tried simply compiling the code "clpru pru_main.c" (I know it sounds silly!! but I felt its worth a try)

but even after this i am not able to compile it, it says "/usr/include/features.h", line 323: fatal error: cannot open source file "bits/predefs.h"

or without argument it says " couldn't open source file 'stdint.h' "
Can you guide, where I am going wrong!

hope I am sufficiently clear, and I am really sorry If you find my query very novice, If so can you recommend me some resources as well to clear my basics as well!

Thanks a lot!

Regards


[ - ]
Comment by SergejHeccSeptember 23, 2015
Hi Febian,

why the size of th? .text section in AM3359_PRU.cmd file is specified as 0x1000 ?
According to datasheet its size is 2 times bigger (8K). The same size is specified in cmd file for hexpru.
[ - ]
Comment by texaneSeptember 23, 2015
Hi Sergej,

I guess this is an error ... Some files actually uses the whole size,
for instance:
https://github.com/deepakkarki/pruspeak/blob/master/src/pru-firmware/AM3359_PRU.cmd

Cheers,
[ - ]
Comment by Paulo SherringJanuary 3, 2016
Hi there! First of all, thanks for the tips and package!
I am trying to use your package but I am getting because of the soft float you used to build libprussdrv.a(prussdrv.o). I am using VFP and getting an error when run build.sh for pruss_c example.
How could I rebuild the binaries?
Thanks again!
[ - ]
Comment by Paulo SherringJanuary 3, 2016
So, I follow the advices in a few post up here: went to ./am335x_pru_package/pru_sw/app_loader/interface/ and ran 'make install'. Running 'make' only gave me no luck. I had to define also DESTDIR variable, used to deploy the files. Then, copied the deployed files to ./lib and ./include.
And voilà. I am going to deploy to board now and see if everything went ok.
Thanks!
[ - ]
Comment by RagnorokMarch 1, 2016
The PRU C Compiler includes a 'PRU Hex Utility' that does the conversion to data.bin & text.bin, *at* address 0x0, for you. Instructions here:

https://e2e.ti.com/support/development_tools/code_composer_studio/f/81/t/403440

Or search for "enable PRU Hex Utility".

This allows uio_pruss to be used out of the box with CCSv6; just drop the files on the BeagleBone and run them.

Great write-up!
[ - ]
Comment by EmikeSeptember 25, 2019

Great post! Thank you so much.

I was wondering if someone can help me though...

I'm trying to get only the PRU-C compiler and i already visited the link you gave, and the compiler looks like it is doing its job but, i was wondering if i can get the latest no BETA version of it, so i've visited the C6000_Code_Generation_Tools_v8.3.1 page.

But after installation i can't find the /bin/clpru and the official pru-software-support-package looks like it depends on it or that is what i see in the Makefile of the Building Blocks.


#pru-software-support-package/examples/am335x/PRU_RPMsg_Echo_Interrupt0/Makefile

$(GEN_DIR)/%.object: %.c
    @mkdir -p $(GEN_DIR)
    @echo ''
    @echo 'Building file: $<'
    @echo 'Invoking: PRU Compiler'
    $(PRU_CGT)/bin/clpru --include_path=$(PRU_CGT)/include $(INCLUDE) $(CFLAGS) -fe $@ $<

Does anyone knows where i can find the latest PRU-C compiler?

Does anyone know if the name of the PRU-C bin has changed? 

Thanks,

To post reply to a comment, click on the 'reply' button attached to each comment. To post a new comment (not a reply to a comment) check out the 'Write a Comment' tab at the top of the comments.

Please login (on the right) if you already have an account on this platform.

Otherwise, please use this form to register (free) an join one of the largest online community for Electrical/Embedded/DSP/FPGA/ML engineers: