Skip navigation

BBB - Audio notes

Posted by shabaz Top Member May 28, 2013

EDIT: See here for details on how to build a DAC:  BBB - Building a DAC


The BBB, unlike the RPi, does not have an in-built analog audio output*. However, there is a USB port for a soundcard, and a HDMI interface. The nice thing about the latter is what it derives the audio from; a hardware I2S interface inside the AM3359, which sends data out to an NXP TDA19988 for conversion to HDMI. So, the possibility exists to obtain I2S directly, theoretically at up to 24bit/192kHz (128fs clock).


Just to confirm audio worked, I tried USB audio first quickly. Plugging in the nearest USB audio sound card works with the Beaglebone Black - I tried an old Creative SB1100. The whole thing was powered just from the USB connector on a laptop for this, and it worked, but probably an external power supply should be used.


There are some software bugs however, because the sound was lower volume in one ear, like a software mixer issue. Hopefully that will be ironed out in a release sometime (the BBB is only a few weeks old currently). Apart from the lower volume issue, the audio quality was extremely good.


This is the procedure to get audio  playing:


ls -ald /dev/dsp* (you will see /dev/dsp listed)

Plug in the sound card and repeat. Now you will see /dev/dsp1 also listed.


Get the sound card name:


aplay -L


in my case, I saw:





Play an MP3 file:

ffmpeg -i test.mp3  -f alsa "default:CARD=Go" -re -vol 20 (where vol is 0-256; 0=silent)


top revealed about 14% CPU consumption on the particular MP3 file that was being played.


I tried to play the same audio file but directing to HDMI:

ffmpeg -i test2.mp3  -f alsa "default:CARD=Black" -re -vol 20


It did work, but the current software build has known HDMI audio issues and it was noticeable - it didn't sound great always. Not noise, but some other digital effect.


There is not much information on NXP's site for the IC that provides the HDMI interface (TDA19988), however the BBB reference manual (SRM) specifies that  I2S is used to it, clocked at 24.576MHz. I don't have an external DAC, but I was curious if it was truly I2S format as currently configured for the TDA19988. The I2S interface comes out to header P9:


BBB Description    Header pin          Description

SPI1_CS0            P9_28               Bitstream

SPI1_D0             P9_29               Left/Right clock

SPI1_SCLK           P9_31               Bit clock


The actual data is on the pin CS0, not D0.


Looking on a scope, it is clear that the 24.576MHz clock runs always, and the other two pins are low. When there is sound to play, the Left/Right clock begins to toggle (at 32 bits) and then after a short while the bitstream occurs. I couldn't determine which side the padding was for 16/24 bit audio, but these things are configurable on DACs anyway. I noticed the bit change occurs on rising edges of the bitclock, so they are read in on the falling edge of the bitclock.

So, in summary, it is configured as an I2S interface, and it would be rather easy to connect up a decent external DAC if desired (e.g. car audio applications).

I don't know enough about Linux audio, but it would be nice to even send high quality FLAC file content (e.g. from attached storage) after non-lossy conversion into an audio stream directly through the I2S interface.


* Although there is no analog output, there is the possibility to toggle pins (at up to 200MHz) for cheap audio, either as PWM, or with multiple pins and summing. It's very cheap just to use I2S  however, since some DAC ICs cost less than $1.


BBB - Connecting up an LCD

Posted by shabaz Top Member May 27, 2013

Now that the BBB is becoming useful, it would be good to have some libraries of code and schematics to interwork it to a few popular sized displays. The BBB has a built-in LCD interface, i.e. a parallel high speed bus that can directly write to TFT displays. The LCD interface is connected to a TDA19988 chip on-board, which provides a HDMI output. The LCD interface is also brought out to header P8 so it is also possible to direct the output to an LCD. It would need some driver experience.


Another more simple approach is to use a serial interface, in which case the output will not reflect the Linux desktop.


This was rather easy, now that we know how to use the PRU to send high speed data (at least for GPIO1 currently). I just used a random color LCD and it worked fine.

The vendor electronics_lee on e-bay is selling lots of serial mode LCD displays (for less than $7 including free postage) of the type used in normal mobile phones (i.e. non-smartphones). The nice thing is that they can be run at a very high speed, so that video is possible if desired. It uses Sitronix ST7735 as the driver.


Currently the PRU code is used to initialize the display, set it all to a single color (green in this example) and then write the character 'L' to the center of the screen just as a test.

The entire screen is written in just tens of millisec, and it would be possible to speed it up further (I didn't read the datasheet closely for the timing specs). It would be good to get the PRU to populate the display based on RAM filled by software running on top of Linux, but I ran out of time to work on that (it should be simple to do).



The PRU code is attached if anyone wants to improve on it, to create a decent LCD library. For the Linux side for now, I just used the example code that comes with the PRU assembler.


The LCD is rather small (128x160 pixels, 34mm x 46mm in size, about 3mm thick) unfortunately, but good enough to display status information or a simple graph.


The LCD has only 14 pins, of which a couple are not used, and the GND pins are connected together already (the two VCC pins do need to be connected). The LED was connected to the 3.3V supply via a 100 ohm resistor, and the whole thing was powered from the BBB 3.3v supply.



The LCD looks like this unsoldered. Notice the small white strip, which is adhesive tape. This is used to stick it to the PCB to keep it in position while soldering (and then the display is folded over, so that the soldered flex is underneath the display).



The flex cable on the LCD has pins spaced 0.8mm apart, which was a perfect fit using one row of pins on a TQFP breakout board (it would be nice to make some custom PCBs for this display).


The photo above shows it soldered to the breakout board. It can be done with a normal soldering iron and normal solder, but if you have solder paste it makes it even easier. A really extremely tiny amount of the paste is spread in a line over the pads on the PCB, the LCD flex is stuck down with the adhesive tape in the photo earlier, and then a soldering iron is just stroked on top (outward, in the direction of the pads) to allow the paste to melt. There are small holes in the flex pads, so the solder will go through, so you can clearly see that it soldered correctly.


Viewing direction: I never understand how the clock system is used to specify the viewing direction on TFT displays, but basically the view appears best in landscape on this LCD, not in portrait. In portrait the screen goes bright/dim depending on if I look at it from above/below. In landscape it is much better. The backlight LEDs are on the edge closest to the flex cable.


This was the connections to the BBB, in order to use the attached PRU code:


LCD pin          Description          BBB header pin          Control reg Address

2,3                  GND,LEDK              P9 pin 1                   

6                    RESET                 P8 pin 26               0x44e1087c

7                    RS                    P8 pin 12               0x44e10830

8                    SDA                   P8 pin 16               0x44e10838

9                    SCL                   P8 pin 15               0x44e1083c

10, 11               VCC,VCC               P9 pin 3

12                   CS                    P8 pin 11               0x44e10834

LCD pin 4 (LED Anode) is connected to VCC via 100 ohm resistor.


The PRU code uses lots of macros, because the CALL and RET functions are emulated, and I don't think they can be nested (not really a major issue since there is lots of memory space for PRU code). I could be wrong.


Before you run the PRU code, make sure that the pins are set to  GPIO mode outputs in the device tree. For now I just did it in the .dtb file, but really it should be done in the .dtbo fragment. The configuration pairs are listed here (i.e. the least significant byte of the control register addresses in the list above, all set to 0x07 which is mode 7 GPIO output):

<0x30 0x7 0x34 0x7 0x38 0x7 0x3c 0x7 0x7c 0x7>


In the current code there is some junk instructions between lines 420-437 that are not needed, but I didn't get a chance to retest with them removed, so I left them in for now.

For the .hp file, just use any existing .hp file from the demos that come with the PRU assembler.


BBB - HDMI and mouse

Posted by shabaz Top Member May 23, 2013

Out of curiosity I tried plugging in a HDMI cable (£2.29 from e-bay with free postage) into an out-of-the-box BBB (I didn't upgrade the image first) and it seemed to work fine with a several-year old TV. Audio didn't work, but I understand that is a problem with the image.


Setting expectations

The BBB has a USB port and HDMI, so the thought may occur by some to be usable as a media PC or general purpose computer for the home. I wouldn't advise that (probably better to buy something dedicated, like Apple TV  - I have not tried that, or any low-cost Intel based PC for web browsing or media use, or for media PC possibly RPI since it supports full HD today - I've no idea of the performance of it, I've not tried it for such a use-case).

Also, as expected, the performance of the BBB, while high, is not a suitable replacement for a general web browsing device, even for young children. It could be useful for kiosk apps or learning or teaching/training with the HDMI and kb/mouse in classes but I'm only guessing.

I wouldn't advise HDMI and kb/mouse for development either; the fastest way remains to develop on a PC (running Windows or Linux for example) and transfer files across via SFTP for compilation and execution on the BBB via SSH. Most app development does not require export of the display, but if something was needed,  X or VNC could be used (or an open source version of Remote Desktop - which seems to run faster than VNC for me). The built-in text graphical text editor seemed to work fine, and speed was reasonable for these types of apps and general window manipulation for the short period of time I tried it.


What could it be used for?

There could be low-cost commercial digital media player (e.g. signage) types of applications, kiosk etc as mentioned before, or the possibility to view a GUI  before implementing on an LCD. The BBB resolution with the current image is 1280x1024, which as it stands would suit industrial LCD panels, but it scaled well with a sharp image on a normal television (see photos below) to suit signage applications too.


USB mouse

Again out of curiosity more than anything else, connecting a wireless logitech mouse to the board seemed to work fine (scroll, forward/back buttons worked too). I don't have a keyboard but apparently they share the same receiver so it is possible to have both the keyboard and mouse using the same USB port. I've no reason to assume it wouldn't work with the keyboard too. I found I didn't need any hub nor external 5V PSU to get the mouse and HDMI to work, but probably for a real use a 5V PSU to the BBB would be advisable.




Example photos

Using mouse cut-and-paste I tried youtube. Some videos worked. There is clearly much frame drop but it is to be expected - Clearly Chrome or plugins are not using NEON: It would be more useful to try any media player software that was accelerated but I've not yet looked to see what exists.




GIMP was already installed as was this image in some folder:


This post is just to list some example initial things to do with the BBB, to prepare it for development. Others may have different suggestions to suit various working methods. The official getting started page is here.

Powering up the board for the first time

(Instructions here are Windows based, but the official page has instructions for Linux and MAC too; For Linux, no drivers are needed but they suggest using this script):

  1. Plug in the USB, let it boot up. Some drivers will not install (CDC Serial and RNDIS)
  2. Download BONE_D64.exe for Win 7 64-bit and run it. It will prompt a few times. Now all drivers will be installed.
  3. In a Windows command prompt, ipconfig /all will reveal a "Linux USB Ethernet/RNDIS Gadget" interface has been created on the PC with IP address; the BBB IP address will be
  4. It is now possible to use a web browser to navigate to


Using a serial cable

The J1 row of pins on the BBB allows connection to a PC for serial comms (115200 baud by default).

This is a small hardware mod to use a powered USB-serial adapter:

Solder a red wire from J1 pin 2 to P9 pin 4

The communications pins and direction of data is:

Beagleboard J1 pin 4 <---------------PC
Beagleboard J1 pin 5---------------->PC

J1 pin 1 is 0V.


Information on various serial cables is here. Connecting up a FTDI TTL-232RG-VIP-WE cable (these colors were different to the ones on that page):

Pin on J1    Color

1            Black

2            Red

4            Orange

5            Yellow


Plug in the FTDI cable into the PC. (On Window 7 64-bit; the driver will install automatically after a while - no need to download any driver.

Check the port number in Device Manager).

Start up serial terminal software on your PC, set to 115200 baud, no DTR/DSR/RTS/CTS/XON/XOFF
Power up board and observe it booting up; after around 10 sec it will be at the login prompt
Login as root (there is no password)


Updating the software

The getting started page has this detail and it works well. It requires a microSD card and a way to program it from a PC (e.g. a small SD to MicroSD adapter if your PC has an SD card slot). It takes almost exactly 45 minutes for the flash to be programmed on the board.


Setting the date

Check the date by typing date
Set the date, e.g. date -s "May 21 22:49 UTC 2013" (you may wish view )


Using SSH

From the PC, it may be possible to SSH to (username is root, no password)

If it is not possible on a new board (like my board) then this was the fix:

  1. Connect via the USB-Serial adapter
  2. /etc/init.d/dropbear stop (dropbear is the name of the SSH server software)
  3. cd /etc/dropbear/
  4. There will be a file in this folder
  5. rm dropbear_rsa_host_key
  6. /etc/init.d/dropbear start
  7. The dropbear_rsa_host_key will be recreated, and this time will be a few hundred bytes in size
  8. Now the SSH should work


Powering down the board

At the shell prompt, issue shutdown now to power down the board; otherwise you risk file system corruption.

There is a power button on the board, that  could issue this for an automatic shutdown if someone writes the code (the button is described in  the BBB SRM doc that can be found here).


Some shell and vi changes

To have a better shell:


vi /etc/passwd


edit the first line (the root user line) to say /bin/bash instead of /bin/sh

Then, issue a reboot command.



For me, the vi on the BBB behaved slightly different, but enough to make it uncomfortable for long use. I made these changes to suit personal tastes:

Make tabs equal to 2 columns instead of 8:

  1. Go to /usr/share/vim and edit the vimrc file there
  2. At the end of the file, add a new line with this content (including the colon):


:set ts=2


Disable the incsearch if you want traditional vi search behaviour (Otherwise, get used to pressing enter after a search):

Search for incsearch, and comment it out with a speech-mark at the beginning (i.e. " )

Disable the autoindent:

Search for autoindent and comment it out and comment out the else line above it too

Also, search for filetype plugin indent on and comment that line out too.


Setting the console width:


stty cols 100


Mounting file systems

Unusually the busybox version of mount is needed. Basically, this command worked:


cd mnt

mkdir shared

chmod 777 shared

busybox mount -o port=2049,nolock,proto=tcp -t nfs /mnt/shared


(where /volume1/shared is configured on your storage server and is the address of it). The -o part is necessary to get it to work.

(Disclaimer - this is some experimentation, so the information here may not be the best way of doing things.

Also, please read the comments below, which have recent information as people discover things)

17th March 2013 - Anything old is now in purple. Notes have been updated to reflect recent builds.


What is it?

The BeagleBone Black's TI chip (XAM3359AZCZ revision 2) contains the main processor (ARM) along with a number of other modules (see this diagram from the AM335x datasheet).


  Although the ARM Cortex-A8 processor portion of the chip is powerful, the nature of Linux means that real-time control of high-speed external hardware may often still not be easily possible. The TI chip improves the situation by providing two additional CPUs (known as PRU-ICSS or PRUSSv2, I’ll call it PRU for short) on the same silicon. It means that separate software can be run on them, to offload hardware interfacing and processing of low-level protocols.


The chip has been likened to having arduino-type capability on the same chip, but actually the additional CPUs run at a far higher speed (200MHz) which in many cases means that external logic devices, CPLDs or FPGAs may not be necessary.

  Generally, having to program more than one processor is inconvenient and means that a protocol is needed between the processors. This is greatly simplified on the TI chip, because (1) the code for the PRUs can be downloaded from the main processor, and (2) shared memory can be used for communication.

Where would it be useful?

For low-speed comms, conventional I2C or similar protocols can be used, and there is no need to use a PRU. For high-speed comms the PRU may be extremely useful because it can service the hardware with no interruptions due to Linux context switching, and no overhead is experienced by the main ARM processor. Here are some examples that should be feasible; basically quite a few possibilities.

  • interfacing to a fast ADC (e.g. analog capture),
  • CCD or a CMOS camera
  • LED or LCD display
  • analog video generation (video encoder)
  • custom PWM or other custom or non-standard protocols
  • motor control with feedback

  As far as I can tell, it is even possible to clock in parallel data from an external clock.


How to use it?

Currently, it is not straightforward, but certainly not difficult. The main difficulty is finding complete examples on the web. The information here has been gleaned from a lot of web searching and experimenting.

These are the main steps:

  1. Get the PRU system enabled on the BBB board
  2. Get the PRU assembler installed on the BBB (code for the PRUs is written in assembler currently, until someone creates a C compiler for it)
  3. Write the code. PRU applications are in two halves which can communicate with each other through memory addressing:

          (a) The assembler code that is assembled into a .bin machine file to run on the PRU, and

          (b) Some C code that will run on the main processor, i.e. on top of Linux. This C code is responsible for downloading the assembled code in the PRU

   4. configure the Linux device tree to enable any pins for input/output

   5. Run the program

What is the assembler code like?

It’s not bad. It’s easier than some common assembler languages like for PIC or other 8-bit processors because there are a large amount of registers (all 32-bit), the instructions are orthogonal and bit and byte referencing for manipulations is extremely good. There are not many commands, I’ve only used a few so far out of 45 approx, and that suits me fine (usually I don’t want to invest a lot of time learning assembler for an awkward processor – this is not the case and the PRU instructions seem easy to use).


Is it worth the effort?

I think it is, because it becomes possible to control hardware at high speed (say 50MHz). Each instruction takes 5nsec to execute on the PRUs (200MHz clock, each instruction takes 1 cycle) and no varying latency due to the Linux kernel.


What are the difficult bits?

Mainly, it is the device tree related stuff. Hopefully this can change or become simplified in the future. On a typical microcontroller, inputs/outputs are set using particular registers that reside in part of the memory map of a device. With the current software running on the BBB, the user is prevented from directly modifying such hardware registers from within conventional C code as far as I can tell. With the current method, a ‘device tree’ is used; it is a text file that is compacted into a binary file which is read when the system is booted. The file tells the system which pins are inputs/outputs. Device tree modifications are also used to enable the PRU system.

What is the device tree?

See a number of posts (e.g. post 109) here, Selsinork has created some useful examples of it, such as using it to switch off an LED which flashes by default on the BBB.

  The device tree resides in the /boot folder on the BBB, and it is a binary file that is not understandable (example snippet below). It has a .dtb or a .dtbo filename:


There is a program on the BBB called dtc that can be used to convert to a text readable form or vice-versa. Here is a snippet of what the text form looks like (usually a .dts suffix):



Working with the device tree means converting the existing binary .dtb file at /boot into a text source .dts file, making some changes and then converting back into the binary format, and then rebooting the BBB for the changes to take effect.

Here is the procedure to convert the binary file into a text file:

cd /boot
cp am335x-boneblack.dtb am335x-boneblack.dtb_orig
dtc -I dtb -O dts am335x-boneblack.dtb > am335x-boneblack.dts_orig

After any modifications have been made (maybe copy the file first so that you have a backup), it can be converted back into binary form using:

dtc -I dts -O dtb am335x-boneblack.dts_pru > am335x-boneblack.dtb_pru
cp am335x-boneblack.dtb_pru am335x-boneblack.dtb

These commands will be used for a couple of the steps below.

Step 0: Get the BBB ready in general for any development

Although it is possible to compile up code on an x86 Linux server, the BBB is fast enough that there is no need to cross-compile. Usually I tend to write the code on a Windows or Linux machine, and then use SFTP to transfer the files across to the BBB and compile there. But, sometimes vi still gets used on the BBB. The Angstrom Linux has a few defaults that may not suit everyone. I’ll place them in a separate post – some people may not want to do them, or may have better suggestions. By the way I used bash shell for everything, not the default sh. Just in case that makes a difference to environment variables setting.


Anyway, it is advisable to upgrade the software to the latest. This requires a 4GB minimum microSD card that can be programmed from a PC.

Step 1: Get the PRU system enabled on the BBB board

The information in color here is now historic. Today it is possible to enable the PRU using a "dts fragment file" also known as ".dtbo" method. So, skip the colored bit.

By default, lsmod reveals that uio_pruss is not installed, so you have to type the following to install this module:

modprobe uio_pruss

The device tree needs updating to enable the PRUs. Once you have got a text version of am335x-boneblack.dtb (using the method described earlier under "What is the device tree?") then edit it and make the following changes:

Search for pruss@4a300000 and then under it change

status = "disabled";


status = "okay";

(note: the correct procedure is not to do the above in the .dtb file but rather in a .dtbo fragment file as explained in the comments below, but there is currently a bug that makes PRU enablement unreliable via the .dtbo) - Note 2 - the bug appears fixed in recent images, so no need to do this in the .dtb file. Just do it in the .dtbo file instead. However, just make the led0 changes here, to disable the flashing.

While you are at it, make Selsinork’s LED change to disable the flashing USR0 LED (the LED on the far end of the board). It is extremely useful to disable it so that you can try to control it from the PRU as an experiment. This is what needs to be done:

The LEDs are controlled by this part:

gpio-leds {

compatible = "gpio-leds";

pinctrl-names = "default";

pinctrl-0 = <0x3>;

led0 {

                                label = "beaglebone:green:usr0";

                                gpios = <0x5 0x15 0x0>;

                                linux,default-trigger = "heartbeat";

                                default-state = "off";


led1 {..etc



So, we can change led0 (aka USER0 aka USR0) by changing the line from:

linux,default-trigger = "heartbeat";


linux,default-trigger = "none";


Ignore the colored bit, it is no longer necessary.

There is one more change for now, but I’ll explain it later. For now, you may wish to make this change too, to run some example code later. If you don’t make the change now, no problem; the device tree can always be updated again at a later date and then the board rebooted.

Search for a line that says

pinctrl-single,pins = <0x54 0x7 0x58 0x17 0x5c 0x7 0x60 0x17>;


and change it to:

pinctrl-single,pins = <0x030 0x06 0x54 0x7 0x58 0x17 0x5c 0x7 0x60 0x17>;

Note: Don't do the pinctrl  modification in recent releases. Just use the .dtbo file method because it works. The information above will be deleted soon, because it does not apply to recent releases.


Save the file, and then convert into the .dtb file as mentioned earlier, and then the board can be rebooted. Now the annoying flashing LED has stopped flashing and can be used for our debug purposes.

Read Step 4 now, to see how to create the fragment file. The ordering is a little back-to-front because in the past, the .dtbo method did not work to enable the PRU. Today it works.

Step 2: Get the PRU assembler installed on the BBB

This is straightforward. Find the file from the Internet and save it onto the BBB and unzip to a folder.

Type the following:



go to pru_sw/app_loader/interface and type:



then go to pru_sw/utils

mv pasm pasm_linuxintel

cd pasm_source

source ./linux_build

Go to pru_sw/example_apps

make clean




The steps above will have created the assembler, and also some demo programs. As mentioned earlier, PRU applications are in two halves;

     (a) the hand-written assembler code that got assembled into code (a .bin file) to run on the PRU of course, and

     (b) some C code that will run on the main processor.


The latter is responsible for two things:

  1. Uploading the assembled binary file into the PRU, and
  2. interacting with the PRU to pass/fetch information.

The source code for (b) resides in the example_apps/xxx folder, and when compiled it creates a .o file in the obj folder which we can link with libprussdrv.a to create our executable.

The assembler code for (a) resides in the same example_apps/xxx folder as a .p and a .hp file but when assembled, the .bin file sits in example_apps/bin

The commands earlier will have created the .bin file for (a), and the .o file for (b).

The .o file can be linked into an executable using (say):

cd example_apps/PRU_memAccess_DDR_PRUsharedRAM/obj

gcc PRU_memAccess_DDR_PRUsharedRAM.o -L../../../app_loader/lib -lprussdrv -lpthread –o mytest.out


With both the executable (mytest.out) and the .bin file in the same folder (You will have to move it manually), the executable can now be run:



This is the output:

INFO: Starting PRU_memAccess_DDR_PRUsharedRAM example.


        INFO: Initializing example.

        INFO: Executing example.

File ./PRU_memAccess_DDR_PRUsharedRAM.bin open passed

        INFO: Waiting for HALT command.

        INFO: PRU completed transfer.

Example executed succesfully.


The folders for the example are a bit messy. To make life easier you may as well copy the library and header files to system folders:

Go to pru_sw/app_loader/lib

cp libprussdrv.a /usr/lib/.

cd ../include

cp *.h /usr/include

cd pru_sw/utils

cp pasm /usr/bin


Now you could use a simple makefile to create your own code in any folder. That is what will be done in Step 3.

An explanation regarding the file suffixes: the .p means assembler source file, the .hp is like an include file but behaves exactly the same as the .p file so technically you could put everything into a single .p file if desired; the assembler is simple to use. No linker is required by the way.


Step 3a: Write the assembler code to run on the PRU

Here I just reused some of the example code (from the PRU_memAccess_DDR_PRUsharedRAM example in Step 2), and modified it so that it flashes the USR0 LED (the LED on the far end of the board).

Here is the entire .p file, I called it prucode.p:

// prucode.p

.origin 0

.entrypoint START

#include "prucode.hp"

#define GPIO1 0x4804c000


#define GPIO_SETDATAOUT 0x194


    // Enable OCP master port

    LBCO      r0, CONST_PRUCFG, 4, 4

    CLR     r0, r0, 4         // Clear SYSCFG[STANDBY_INIT] to enable OCP master port

    SBCO      r0, CONST_PRUCFG, 4, 4

    // Configure the programmable pointer register for PRU0 by setting c28_pointer[15:0]

    // field to 0x0120.  This will make C28 point to 0x00012000 (PRU shared RAM).

    MOV     r0, 0x00000120

    MOV       r1, CTPPR_0

    ST32      r0, r1

    // Configure the programmable pointer register for PRU0 by setting c31_pointer[15:0]

    // field to 0x0010.  This will make C31 point to 0x80001000 (DDR memory).

    MOV     r0, 0x00100000

    MOV       r1, CTPPR_1

    ST32      r0, r1

    //Load values from external DDR Memory into Registers R0/R1/R2

    LBCO      r0, CONST_DDR, 0, 12

    //Store values from read from the DDR memory into PRU shared RAM

    SBCO      r0, CONST_PRUSHAREDRAM, 0, 12

    // test GP output

    MOV r1, 10 // loop 10 times


    MOV r2, 1<<21


    SBBO r2, r3, 0, 4

    MOV r0, 0x00f00000


    SUB r0, r0, 1

    QBNE DEL1, r0, 0

    MOV R2, 1<<21


    SBBO r2, r3, 0, 4

    MOV r0, 0x00f00000


    SUB r0, r0, 1

    QBNE DEL2, r0, 0

    SUB r1, r1, 1

    QBNE LOOP, r1, 0

    // Send notification to Host for program completion

    MOV       r31.b0, PRU0_ARM_INTERRUPT+16

    // Halt the processor



As mentioned, this is derived from the example .p file. The only major difference is around where it says “// test GP output”. All the code before it is an example that shows memory access from the PRU and the ARM processor, as run earlier in Step 2. It is useful since it shows how to communicate between the processors.

The new code is intended to flash the USR0 LED ten times, and here is a description of what the assembler code is doing:

     R0: Used to store a large number for use as a delay

     R1: used to store 10 as a loop counter

     R2: This stores the value 1<<21 which is shorthand for bit 21 set, and all other bits clear. The USR0..3 LEDs are GPIO1_21..24 as can be seen in the schematic (see image below), so if we want to control USR0 then bit 21 gets manipulated


R3: This stores the address of the GPIO1 register which can be found in the am335x tech reference manual (4000 pages) and if you click on the blue text at that location, it goes to the chapter which shows the actual individual register addresses for GPIO1. The code uses this to set or clear the GPIO1 pin 21 in this example.




Some example assembler syntax:

     MOV r1, 10 – This moves 10 into register 1 (i.e. r1 <- 10)

     SBBO r2, r3, 0, 4 – SBBO stands for ‘store byte burst’ and this moves from registers to an address; in this case the contents of r2 into the address at r3. The zero means no offset, and the 4 means copy 4 bytes (each register is 32 bits).


You can see the code has a main outer LOOP1, and a couple of DEL1 and DEL2 loops.

The prucode.hp file is the same as the .hp file that is in the example folder (I just renamed to prucode.hp); it contains some definitions and some useful macros.

The .p and .hp code gets assembled into a single .bin file. I used a makefile for this, and didn’t assemble it until I had completed step 3b.


Step 3b: Write the C code to run on the ARM processor

The C code is nothing special. It is probably advisable to just re-use the example code. I reused the .c file from the PRU_memAccess_DDR_PRUsharedRAM example and just renamed it to mytest.c

The C code makes use of some library functions that initialize the PRU and download the .bin file into the PRU. It is fairly obvious what is occurring by inspecting the example code.

Step 3c: Create the .bin file for the PRU, and the ARM executable

I’m no Makefile expert but what worked for me is attached. You can just type ‘make’ and it will build the .bin file (prucode.bin) and the executable (mytest).

You can actually run the program now and it will work, without steps 4 and 5.


This will flash the end-most LED on the board 10 times.


Step 4: Configure the Linux device tree to enable any pins for input/output

Although the example worked, actually this is just because we used it to toggle a pin that was already configured for use as a GPIO output (USR0 LED). Ordinarily some work needs to be done with the device tree.

There is also another important point: Most pins on the TI chip can be used for multiple purposes, depending on how they are configured. It is known as Pin Multiplexing (pinmux) and it seems complex because there are so many modes (up to 7) that each pin can be used for.

There is a very useful table that Selsinork created. It is in post #5.

By inspecting this table, you can see which pins on the chip make it out to the headers on the BBB, and the names of the functions in each mode.

This is important to know, because although the PRU runs at a high speed (200MHz), it cannot control pins in the standard GPIO mode at such a high speed. The pins need to be set to a different mode so that the PRU can directly control them. Then, the PRU can control the pins at the high speed (5nsec, i.e. a single clock cycle). The direct mode is known as ‘PRU GPI’ or ‘PRU GPO’ mode (for input and output respectively).

So, in the step 3 above, the LED was controlled with the pin set in standard GPIO mode. If the delay in the .p assembler code was reduced, the LED could be made to flash at around 25MHz max (I checked with a scope). If you want to control at the fastest speed, the direct PRU mode is needed, and currently the only way I know to set this mode is via the device tree.

Once set, the pins can be controlled from the PRU by writing or reading from the special registers R30 (for writing) and R31 (for reading). This is easy to remember, since the 0 in 30 looks like an ‘O’, i.e. output, and the ‘1’ in 31 looks like ‘I’, i.e. Input. There are 16 pins available for input in the fast mode, and 15 for output.


You can see which pins can be used by looking at Selsinork’s table or by inspecting the schematic. For a test, I decided to toggle a pin on a header as a PRU GPO. I decided to use this pin shown on the schematic, since it is clear it can be configured as a PRU GPO because of the name (it has R30 in it, and is less than or equal to 15).


The quicker way is just to check the table. Hit ctrl-F and search for r30 for example. Then, by looking at column 1 you will see which header and pin the connection is available on. For the pin that I decided to use, PR1_PRU0_PRU_R30_14 is GPIO1-12 which goes to P8 pin 12. In the am3359 datasheet, this PRU pin is called GPMC_AD12 and it needs to be in mode 6 to become an output.



Going back to Step 3 briefly, I changed the last bit of the  .p assembler source code to:

    // test GP output

    MOV r1, 10000000 // loop 10,000,000 times


    SET r30.t14

    CLR r30.t14

    SUB r1, r1, 1

    QBNE LOOP, r1, 0

    SBBO r2, r4, 0, 4

    // Send notification to Host for program completion

    MOV       r31.b0, PRU0_ARM_INTERRUPT+16

    // Halt the processor



Basically the code now does not flash the LED, but instead pulses a pin quickly (needs an oscilloscope unless you wish to modify this code to insert a delay).

This line sets the pin:

SET r30.t14


and the following line clears the pin.

Issue a ‘make’ to rebuild the code.

Now, back to Step 4:

To set the pin to mode 6, I used a utility to help called available from TI’s website. Once installed, it looks like this:


If you double-click on the signal that you require, it turns green and then you can go to File->Save->SourceFile and it will save two files: mux.h and pinmux.h

In pinmux.h, you will be interested for searching for the text ‘pru’ and it will reveal this line:

MUX_VAL(CONTROL_PADCONF_GPMC_AD12, (IDIS | PD | MODE6 )) /* pr1_pru0_pru_r30[14] */\


So, now you know that to use this signal, you need to set a register to value IDIS | PD | MODE6 and that can be converted to a number using the information in mux.h:

#define MODE0 0

#define MODE1 1

#define MODE2 2

#define MODE3 3

#define MODE4 4

#define MODE5 5

#define MODE6 6

#define MODE7 7

#define IDIS (0 << 5)

#define IEN (1 << 5)

#define PD (0 << 3)

#define PU (2 << 3)

#define OFF (1 << 3)


With this information, it is clear that I need to set a register to 0x06. Table 9-10 in the 4000-page tech ref manual reveals the offset that represents the register.

I found this by just doing a text search in the doc for CONF_GPMC_AD12.


According to page 158 of the tech ref manual, the Control Module address begins at 0x44E10000, so ordinarily we need to add the 0x830 offset to it, to get 0x44E10830. However with the Device tree, according to this link when using the device tree the address to use is relative to the base address of the pin gpmc_ad0. That base address is 0x44e10800. So, the number that will be used in the device tree is 0x30.

Remember in Step 1 this change?

pinctrl-single,pins = <0x54 0x7 0x58 0x17 0x5c 0x7 0x60 0x17>;


was changed to:

pinctrl-single,pins = <0x030 0x06 0x54 0x7 0x58 0x17 0x5c 0x7 0x60 0x17>;


The purpose of this was to set the register to 0x06. You can see the register offset ox030, and the value 0x06.

This is not the correct way of doing things (since I’ve just tacked it into the LED section in the device tree), but it works.

The supposed correct way actually didn’t work for me, so I’m hoping someone can spot the issue. (note: It is explained in the comments below).

This is what I believe should have worked. It is based on snippets of information from various places on the web:

In the .dts file (same as before), the following additions are to be made in the appropriate sections (just search for something similar, and then insert these lines):

   cape@12 {

           part-number = "BB-BONE-PRU";

version@00A0 {

version = "00A0";

dtbo = "cape-bone-pru-00A0.dtbo";



     slot@102 {


compatible = "kernel-command-line", "runtime";

board-name = "Bone-Black-PRU";

             version = "00A0";

manufacturer = "na";

part-number = "BB-BONE-PRU";



Then convert to .dtb as before.

Create a device tree “fragment” file called BB-BONE-PRU-00A0.dts containing the following:

* pru dts file BB-BONE-PRU-00A0.dts

/ {
  compatible = "ti,beaglebone", "ti,beaglebone-black";

  /* identification */
  part-number = "BB-BONE-PRU";
  version = "00A0";

  exclusive-use =

  fragment@0 {
    target = <&am33xx_pinmux>;
    __overlay__ {
      mygpio: pinmux_mygpio{
        pinctrl-single,pins = <
          0x30 0x06

  fragment@1 {
    target = <&ocp>;
    __overlay__ {
      test_helper: helper {
        compatible = "bone-pinmux-helper";
        pinctrl-names = "default";
        pinctrl-0 = <&mygpio>;
        status = "okay";

  target = <&pruss>;
    __overlay__ {
      status = "okay";


Convert this file into a .dtbo file using:

dtc -@ -O dtb -o BB-BONE-PRU-00A0.dtbo BB-BONE-PRU-00A0.dts


and then place it at /lib/firmware (not /boot for this fragment).

Then reboot, and then type the following: Note: if the 'export SLOTS' line below doesn't work, try bone_capemgr.9 instead of bone_capemgr.8, or even easier, just use * instead of a number:

export PINS=/sys/kernel/debug/pinctrl/44e10800.pinmux/pins

export SLOTS=/sys/devices/bone_capemgr.8/slots

cd /lib/firmware

cat $SLOTS

0: 54:PF---

1: 55:PF---

2: 56:PF---

3: 57:PF---

4: ff:P-O-L Bone-LT-eMMC-2G,00A0,Texas Instrument,BB-BONE-EMMC-2G

5: ff:P-O-L Bone-Black-HDMI,00A0,Texas Instrument,BB-BONELT-HDMI

echo cape-bone-pru > $SLOTS

cat $SLOTS

0: 54:PF---

1: 55:PF---

2: 56:PF---

3: 57:PF---

4: ff:P-O-L Bone-LT-eMMC-2G,00A0,Texas Instrument,BB-BONE-EMMC-2G

5: ff:P-O-L Bone-Black-HDMI,00A0,Texas Instrument,BB-BONELT-HDMI

6: ff:P-O-L Override Board Name,00A0,Override Manuf,BB-BONE-PRU

Now if you try the commands in purple below, you will see correct value of 00000006!


Now you can see the slot entry, but the pin does not appear to be set to the right mode using this method : - (

I saw this using:

cat $PINS | grep 830

pin 12 (44e10830) 00000027 pinctrl-single


The ‘00000027’ value should become ‘00000006’ but it didn’t work for me. But if I do the quick hack method described earlier, then it is ok:

cat $PINS | grep 830

pin 12 (44e10830) 00000006 pinctrl-single



Any suggestions would be appreciated.

Step 5: Run the program

When you execute ./mytest it will toggle the pin 12 on header P8 rapidly, observable on a scope to be at a rate of 50MHz. So, success, but not using the ideal method in the device tree.

I have not tested inputs yet (it should be similar), or anything more advanced. (note: see the comments below for an example of how to read inputs in the GPIO mode)


Where to get more info?

There is lots of documentation in the file mentioned in step 2. This is extremely useful I found.

For the device tree, see post 2 here for some very useful links.

I also found lots of useful stuff here and here.

Also, very useful link: will allow you to very quickly see the pinmux value!! Highly Recommended.

Another note: When doing high speed GPI mode input, the pinmux value needs the "Input Enabled" box checked at the site.

I’ve put together a blog that shows how to debug a Linux application running on BeagleBone Black, using the free “Community Edition” of ARM’s DS-5 toolkit.  This uses DS-5 Debugger for debug, and Streamline performance analyzer to profile the entire running system, using the Open Source “Xaos” fractal renderer as an example Linux application:





I have been enjoying my Beagle Bone Black for a few days now, but have been ready to take the beagle for a walk off the officially supported hardware path.  My mission: could I get the unsupported Camera Cape working despite no official support (so don't bother the developers about support questions) and not all that much to work with?  Succintly, YES! 



Black Ops. Plan:  all that follows relates to an unsupported cape and my own attempts to get it working on the Beagle Bone Black.  Please note that this is one person's confirmation of success.  I will give you some details of the journey to get this working, but mostly provide enough detail to excite the community into their own investigation.  With some good sluething you too can get your camera board working on the Beagle Bone Black.




My plan was simple, check the web and see if I couldn't find an SD dump of a developer's hack and then dd that onto my own card.  Once I got a hold of a devloper's SD dump, flashed my microSD card, and got the Beagle to boot off of the card I then mounted the camera cape.  I would be more detailed, but at the time I wasn't really taking notes or thinking I could get this to work.  Anyway, the first boot with the the caped Beagle you have to be patient as it seems to take a bit longer to boot that normal.  One key to look for is the two lights on the camera cape to be illuminated solid... if you have this, then you are getting close to Beagle sight.  Another issue to be aware of is that sometimes the Beagle seems to hang.  I am unsure if it actually hanging at boot, but the symptoms are that two of the Beagle's LEDs are illuminated and none of the chaotic flashing that signals proper operation.  What you want is for all four of the Beagles LEDs to be going wild and the two LEDs on the camera cape to be solid.  If you get to this point you have done most of the difficult stuff...


Once the Beagle booted with the cape on I got to the developer's GUI login --recall I didn't make the installation-- with usernames and passwords I had no clue about.  For good reason root was not an option at the GUI login; however, my Linux experience compelled me to attempt to switch tty and attempt to login as root --hoping that there remained no password set on the root account.  Success! 


Once logged in as root, and having written down the username I wanted to become since I don't like to use Linux as root, I did a simple password change for that user and jumped back to the GUI login.



At this point I began to feel like I had the Beagle and Cape in my clutches; yet, all was not finished...




The above dmesg looked good to me and it might give a clue to how to get this [redacted?].


Since everything was seemingly working at this point I fired up cheese to test out the camera cape's talents viz. snapping pictures.  The screenshot above includes the dmesg covering the cape manager reportage and both the cheese and Gimp apps all running. 


On the initial running of cheese you will need to tweak the preferences.  For whatever reason the defaults in cheese have the camera set at an absurdly high resolution and with a very dark contrast.  This is the easiest fix in the entire mission!  Simply navigate your way to the preference menu in cheese and make the appropriate adjustments.


After a bit of tinkering with the preferences within chesse I could take pictures like the one below:




So I hope I have sparked your interest in trying to get unsupported hardware working on the Beagle Bone Black.  This is not a howto nor a guide, so please don't be upset that this is a provocation only.  If I can get this working, so can you!


Happy Hacking!


Installing Software

Connecting to the BeagleBone board is pretty easy, here’s the quick run down of how to do it:


1) Download and install the driver:


32 bit

64 bit


2) Download and install putty:





Now that you have all of the necessary software installed, you need to figure connect to the board. To do this, open device manager. I always forget where it is, so I think the easiest way to get to it is just to search for it:


Start -> Search Text Box : “Device Manager”


Once in the device manager, expand the “Ports (COM & LPT)” section.  This is where the BeagleBone will show up once it is plugged in.


Now plug in the BeagleBone. The “Ports (COM & LPT)” section should update and the BeagleBone board should show up there.  For me it was difficult figuring out which one it was, so I had to watch the list pretty closely.


The important part is what COM port it was assigned.  Once you know this open up PuTTY and:


Change the “Connection Type” to “Serial”

Set the “Serial Line” to COM<X> where <X> is the number that you found in the Device Manager.

Set the “Speed” to 115200

Click “Open”




I don’t know why, but mine comes up blank and I have to hit enter before it does anything.  Once I hit enter, it prompts me for a “beaglebone login”, which is “root”.




At this point you should be up and running with your BeagleBone.


Now that we are connected to the BeagleBone through the USB connection, we want to be able to connect to it through Ethernet.  To do this, we first need to figure out its IP Address, which can be obtained through the command:


Ifconfig -a




Then take the eth0 IP address and type that into Firefox or Chrome.  That should land you on a BeagleBoard 101 page.




Blink an LED

Create a circuit like the one shown here:




Now that we have the circuit built, we need to run a program that blinks the LED.  Fortunately, an example comes built in with the BeagleBone board.  To access it, fire up Cloud9, which is their built in Integrated Development Environment (IDE).  To do this, go to <IP_Address>:3000 in your browser:




Once you have the browser up, double click blinkled.js.  This is a simple program that blinks an LED.  To run the program, just click the green play button at the top, next to the word “debug”.


Setting up the BeagleBone is really easy.  In a couple of minutes, we went from opening up the box to running a program that blinks an LED.  Not bad at all.

From the Make: Blog,


Using the BeagleBone to Control a Powerful Upper Body Exoskeleton

Nick McGill is a senior Mechanical and Electrical Engineering student at the University of Pennsylvania.

"My senior design team at the University of Pennsylvania has developed a powered upper body exoskeleton for use in physical therapy and assistive mobility applications. We’ve named the suit Titan after the powerful deities of incredible strength and stamina in Greek mythology."


The exoskeleton in action:


Here's how the Beagle is involved:

Our exoskeleton runs off a master BeagleBone microcomputer running Ubuntu Linux. Thanks to Alexander Hiam, we’re running the entire system using PyBBIO, an open-source Python library for BeagleBone control. A control loop takes velocity input from the joystick on a hand-held controller and filtered absolute positioning from a rotary potentiometer (mounted at the end of the motor shaft) to compute motor PWM signals. The BeagleBone also controls the brake for the ratchet system — the rocker switch manipulates a servo motor to actuate the pawl.

More information is found on the website:




Thank you to everyone who entered our fun Beaglebone photo hunt competion which was running across Facebook, Twitter and Google+ pages last week.


We can now confirm that boris was hiding on the the following blogs:


In the Raspberry Pi group:

The energy harvesting Roadtest area:

Finally in the members area:


So we're very pleased to to announce the winners who were drawn at random from all who entered. Nate Chapman (USA), Julian Bourne (Spain) and Marc Nozell (USA); you guys will all be receiving a brand new Beaglebone Black from us shortly, so many congratulations!


Thanks once again to everyone who took part in the competition and remember if you didn't win this time, you can still order the amazing Beaglebone Black from element14 now.