Coding for the Beaglebone PRU in C
So, I've recently decided to get my head around the killer feature of the BeagleBone family - the two Programmable Realtime Units that sit alongside the ARM Cortex A8 core that you'll normally find running Linux. These PRUs are what really set the BeagleBone apart from other SBCs like the Raspberry Pi. To be honest, if you just need to run Linux on something small then the Pi may be a better choice - quad core 1.2Ghz A53 vs the BB's single core 1GHz A8. For anything that requires accurate and predictable timing though, an OS is not your friend. Anyway, enough about the PRU itself - I'm guessing that if you're here then you know what it is. Let's look at coding for it.
There is a fair bit of information on the PRU out there. A lot of it is good, but a lot of it is now a bit outdated. Things have moved on and it seems things have improved. For instance earlier guides concentrated on assembler because that was the only way back then. Now we have a PRU C compiler for a desktop IDE. Some guides talk about using UIO for interfacing, but that's now been deprecated in favour of remoteproc.
What I'll cover
I'm hoping to show you the quick and easy route to compile a simple C project in TI's Code Composer Studio and deploy and run it on the BB. I won't be doing anything tricky - just toggling a pin. What we hope to get is a nice clean square wave unaffected by whatever the A8 core is doing. I'll point you in the direction of some more complex examples but I'll leave that up to you.
Setting up your BeagleBone
Black or Green and probably other colours too. This is all done from the command line, starting with the latest Debian image on a microSD card. (I have the 2018-10-07 build Debian 9.5. My BB came with a 2016 build installed on the eMMC.)
Update your OS
This is optional but, why not. The following commands got things fully up to date.
sudo /opt/scripts/tools/update_kernel.sh sudo apt update sudo apt upgrade sudo apt dist-upgrade
Enable FTP so you can transfer your code across
sudo apt install vsftpd sudo nano /etc/vsftpd.conf [uncomment the line "write_enabled=YES"] sudo /etc/init.d/vsftpd start
I also freed up some pins that conflict with the ones that the PRU uses. I did this by editing /boot/uEnv.txt and uncommented the lines "disable_uboot_overlay_video=1" and similar for audio and wireless which I don't intend to use. Sensible, but not really needed for this example.
Setting up your PC
In this guide I'll be compiling C code on my desktop using Code Composer Studio. I'm using Windows, but it should be the same for CCS on Linux. If you want to compile code on the BeagleBone itself then Mick Molloy's excellent Exploring BeagleBone book has this covered. Make sure it's the 2nd edition if you want to use remoteproc rather than UIO.
Download and install CCS. Make sure that you select the Sitara option as that's what we're targeting. Note that if you're adding Sitara to and existing CCS installation, you will need to make sure you have exactly the same version of the installer otherwise you'll be forced to do a new installation. Once it's installed, go to the App Center and add in the PRU compiler.
Install PRU software support package
This code is the essential stuff. It's not an installation as such, but a Git repository you'll need to clone or download. If you're going to clone it then pick a suitable folder (it will be referenced as include paths) and do:
git clone git://git.ti.com/pru-software-support-package/pru-software-support-package.git
Alternatively you can download it from here.
This support package contains the header files you need and also some nice examples in the example/am335x folder. I suggest you pick an example (such as PRU_gpioToggle) to start from. The critical part is that the include and include/am335x folders have some essential stuff.
So, here is our blinky project. The things to take note of are:
- our main C file It's not doing much - just toggling a bit in the PRU output register R30.
- resource_table_empty.h I haven't dug into what this file is for (yet) but it does seem to be needed.
- other referenced header files in the PRU support package.
You can of course build your project from scratch. I did, following this TI PRU Training. However, this assumes that you'll be deploying and debugging with an XDS-110 emulator - which I'll hopefully be doing soon! Note that it also leaves out resource_table_empty.h even though I found it was required. Some very useful current info in there though.
Build and deploy
Get your code on the BeagleBone
If all goes to plan, you should be able to build in CCS by clicking the hammer icon. The fruits of your labour will be a single .out file in the Debug folder. You need to copy this file to your BeagleBone - probably via FTP - so that it can find its final resting place of the PRU. I won't go into details of copying a file over here.
Enable the PRU output
Each pin on the BB has multiple modes. In the case of our simple blinky, we're expecting pin 27 on the P9 header to be used for PRU output. From the PRU's point of view this is PRU0, register R30 bit 5, but to the BeagleBone it's P9_27. You will find all these pin mappings here. To enable it, you will need to execute the following:
config-pin P9_27 pruout
Copy your firmware to the PRU
Your out file needs go be copied to a special firmware folder to be accessible.
sudo -i cp /home/debian/pru_blinky.out /lib/firmware/pru_blinky
Then we need to deploy it into PRU0 - confusingly referred to a remoteproc1. (PRU1 is remoteproc2. remoteproc0 is to do with the Cortex M3 co-processor.)
cd /sys/class/remoteproc/remoteproc1 echo 'pru_blinky' > firmware
Are you ready? It's taken us a while to get here but to finally run your cross-compiled C code in the PRU all you need is:
echo 'start' > state
See that big fat nothing that happened? That lack of an error message? That means your code is running! And look - we have a nice clean 1kHz square wave on the output pin. Hooray for square waves! My wife doesn't understand why I'm excited about this, but I'm sure you do.
Well, now that we have code running, it's time to do something more interesting. The examples you find in the PRU software support package are a good starting point for something more complex. It show things like communication between the PRUs and the main processor, interrupts, DMA, hardware UART, etc.
If you're ready to not just run your PRU code but step through it and debug it in CCS, you can do that too.