Skip navigation
1 2 Previous Next


23 Posts authored by: shabaz Top Member

I just saw this:


It's a 14-channel 100Msps logic analyzer using the BeagleBone Black and no additional hardware - it makes use of the on-chip dual programmable real-time units (PRUs).

Apparently it has been used to capture sustained >100MByte sized data streams : ) And also for I2S audio data capture : ) It would be ideal for digital audio testing!

Highly impressive stuff.


The BBB has evolved into the universal test tool that we always suspected it could become.

Multifunction instrument based on BeagleBone Black


BBB - PRU C compiler

Posted by shabaz Top Member Apr 30, 2014

Nice bit of information at this TI URL:

(My underlining below):


PRU Development

The Programmable Real-time Unit (PRU) is a low-latency microcontroller sub-system comprised of two or more 32-bit RISC processors, local instruction and data RAM, local peripherals and an interrupt controller. The PRU is efficient at handing events that have tight real-time constraints. The PRU is also known as the Industrial Communications Sub-System since it is used to enable industrial protocols such as EtherCAT®, EtherNet/IP™, PROFINET, PROFIBUS, POWERLINK, SERCOS III, and others. Each 32-bit processor runs at 200MHz, enabling 5ns instruction cycle. Local peripherals within the PRU sub-system include UART, eCAP, MII_RT, MDIO and IEP. The PRU’s fast input and output pins enable detection and reaction to I/O events within two PRU cycles.

Code Composer Studio provides a C compiler enabling users to add differentiation to their products.


(Downloading now! )




This post briefly documents a BeagleBone Black (BBB) based music box. If you’ve ever wanted a Sonos system but (like me) felt they were a little expensive, then it is worth considering using a compact Linux platform like the BBB for creating something slightly similar. I feel the sound quality is not leagues different (better nor worse) than some more expensive commercial offerings.


It was a quick, fun project and costs about £100 including the cases and the BBB.

The idea for this project was simple - a compact box that connects to the home network and allows the ability to send it music to play (or it can play music stored on-board or on a server). The documentation provides just an overview because the circuits are already documented, and every implementation could be slightly different depending on end user needs, speaker enclosure, etc.

Here is the rear view:



Shown below is a video of it in action. The sound was recorded from the camera in-built mic so is not representative of actual sound quality. For actual sound quality, refer to the MP3 recording here, which was captured by connecting the headphone output (not line output) directly to an ADC and captured by the PC.



The main bits and pieces are the speaker box, the BBB and a DAC/amplifier.

Although a BBB and home-built DAC/amplifier was used, a Raspberry-Pi and Wolfson audio card could be used too, for a similar price.

The home-built DAC and amplifier is easy to assemble; it uses medium-sized SMD components that are hand-solderable, and gives results similar to a Meridian DAC which uses the same chip (a Texas Instruments ic). Full circuits and information are at these two locations: part 2 has the schematic, and part 1 has some more technical detail.

There are plenty of other DACs available including pre-built ones. A search for “I2S DAC” will reveal ones that should be suitable (I have not tried them) – this ebay example is just over £10. (Note that you may require a logic inverter, see the comments sections in the links earlier).


The speaker is a Tivoli Audio speaker. It is possible to get these in new condition for about £15-20 frequently on ebay, in various color options. Any speaker enclosure would have been fine. The official Tivoli webshop sells new speakers (slightly different model) from £39 upwards.


Design and Implementation

The DAC board was mounted inside the speaker, and the BBB was mounted outside. This allows access to all the BBB ports while making the minimal amount of holes in the Tivoli speaker (Speakers are sealed for good audio reasons).

It won't replace main home music systems but that was not the intention, nor is it stereo (that capability is easy to achieve by adding a second speaker connector, but I didn't require it). This is more a bedroom or home study one-box sound system.


Step 1: Fit BBB inside a case

The first step was to get the BBB into its own case. I connected a push-switch to safely power on/off the platform. I also wired up a DB9 connector to interface to the DAC.


I used L-shaped single-in-line header pins to solder up the connections and heatshrink at the DB9 connector end. The switch and LED were wired up to the power switch pin on the BBB and to the 3.3V supply (via a 100 ohm resistor) respectively. The push-switch is wired to the P9 header, pin P9_9 and to ground (pin P9_1). The LED 3.3V supply can be taken from P9_3.


The photo below shows the LiPo battery fitted. I used a paper sticker on the underside of it, to insulate it further. The BBB doesn’t run hot, but the battery could have a spacer between the PCB and itself if desired.


Here is the finished result, powered up. It can be safely powered down by pressing the button again (this feature is by default in the current Debian image).


The other side of the case provides access to the USB port, and a small USB WiFi adapter was fitted. I have not got round to finding a software driver for it yet, so for now I just used Ethernet.


Step 2: Speaker modifications

The next step was to put the BBB aside and work on the speaker and DAC. The speaker was opened up, and the wadding was removed and stored in a plastic bag to prevent dust and drilled fragments of plastic getting on it. The speaker cable was chopped and discarded, and the grommet removed.


The DAC board was fitted with L-brackets and the speaker rear cover was marked up for drilling the holes to secure it, and for the headphone and line jack outputs (3mm holes for the screws, and 6mm holes for the jacks).


The photo below shows the finished result.  The jacks are rather recessed. This is actually no problem for some headphones (e.g. a pair of low-end AKG I own) but others will have problems. I plan to drill to a recess with a larger drill bit to 7mm and it will cover both of my sets of headphones. Note that you want to make the holes as small as practical.


After wiring up the DAC to the speaker, the wadding was placed back in position and the cover was closed up again as shown below. Then the DB9 matching connector was soldered (wires protected with heatshrink). I didn’t bother with a cover for it.


After testing, the hole needs to be sealed (perhaps with epoxy resin glue).

Finally, the BBB was attached to the speaker (rubber feet and adhesive foam pads can be used).


Step 3: Try it out!

This step was the easiest.

Plug in the power supply, power up and install the audio player software:

sudo apt-get install mplayer

Then, try to play a music file (either from local storage or from network storage):

/usr/bin/mplayer -ao alsa -volume 10 “songname.mp3"


Summary/Next Steps

A quick and simple sound system was created. With a pre-built DAC and amplifier, the hardware implementation can be extremely easy.

There are plenty of software options for creating a library of songs and providing an interface for the user to select something to play. I have not tried them. For now I will just use SSH to select music. Eventually the hope is to create a simple browser based app that will allow one to upload MP3 songs from a PC or mobile phone for instant playback. A wake-up alert in the morning with a random song, or the news, will be a good option too (enabled via browser on mobile phone).

The Logic Supply BB100 case has be available for a while (also in black), I purchased one recently while buying other gear, these were my thoughts on it

(pictures were from a cameraphone so apologies for the quality - better images at the Logic Supply website of course).



If you need your BeagleBone Black boxed up, there are worse ways. I thought it was very well made and quite flexible. The cover can be mounted at three heights, to accomodate capes (the gaps can then be used for wires and ribbon cables for example. I will probably fit the Olimex 1400mAH LiPo inside it too as shown here.


The case is steel (not aluminium) and in my opinion is extremely accurately cut and shaped. The case has sub-millimeter accuracy. The base and shell are less than a millimeter thick, yet extremely tough because of the choice of material.


All connectors are spot-on centered into their holes and the tiny narrow microSD card slot doesn't scrape or touch the card at all.


The board is held in place with four screws on permanently fitted metal stand-offs. The finished result is about the size of a pack of playing cards.



The exterior finish is a matt type, slightly roughened surface so not gloss shiny/smooth. I think the finish is great.

Initially I wasn't a fan of the D-Sub connector punch-out (I don't like using this connector for serial connections although it is a standard) but I now think it is a great idea, since it can serve as the I/O for 8 pins or more if a serial port is not desired. On the other side there is a circular punch-out ideal for coax shaped connectors or for a switch for example (approx 6.5mm dia hole measured with a ruler). These punch-outs mean that for many use-cases one may not need to ever drill any holes in the case.

Very narrow slots allow for all LEDs on the board to be visible.



Lots of spare screws are supplied in two sizes; the flush ultra-tiny ones shown in the photo earlier, or slightly larger pan-head. By only fitting two screws, the lid can become hinged.

The rear has punch-outs for providing screwed attachment to another surface, or thin vertical slots can be used for fitting to a metal chassis. Really nice engineering everywhere on this case.

Four thin rubber feet are supplied for optional fitting.

The case is not cheap but metal cases usually do cost more, and so this case is fairly good value for money especially if you want a case you can use as part of a demonstration for example.

Postal cost is quite low in Europe for this case shipped from Netherlands, so that helps too.


As a summary, the case is very nice and practical, and I think it is worth the cost.

(BBB - Building a DAC part 1 can be found here).

Part 3 implements a complete design in an enclosure for a Sonos-like solution.


The BeagleBone Black (BBB) has a digital audio interface and this was explored slightly in an earlier post.

The findings from that prototype were used to construct up a DAC board and it is described here. The aim was to have a relatively simple, easy-to-assemble board designed for portable use (headphone or small speakers) but with at least iPod-level performance. The circuit is described here and the complete schematic is attached to the post. The entire circuit connects to the BBB using 6 pins and needs no separate power supply. This is a recording using just the microphone from the camera - actual audio quality is much better.


For a better quality, the audio from the prototype can be heard in this zipped mp3 file. This was directly recorded from the headphone output so that it is more representative of what the user will hear (the original track that was played through the DAC was downloaded from Amazon, for comparison purposes).



Detailed Description

This is the functionality on the board:


The DAC integrated circuit and headphone amplifier portion were left unchanged from the part 1 prototype although the DAC was replaced with TI’s PCM5102 which is pin-compatible with the earlier PCM5101A. The PCM5102 device is used in commercial DACs such as Meridian’s Explorer.

The remainder design is kept simple too. Three regulators are used to supply power to the DAC (can be reduced to one to save costs, or replace with the lower cost pin-compatible TC1015-3.3):


An optional speaker output was desired, and the selected device was LM4861 which can run from a single low voltage supply and offers over 1W of power. This is enough to provide loud volume for home use (in the video above, the single mono speaker was a couple of meters away and the audio was played at a volume setting of 15 on mplayer). The circuit uses two of these for stereo, although only one needs fitting for mono summed speaker output (the photo above shows only one populated). The LM4861 input is driven from the headphone output, not the line output, to keep line output and headphone outputs as distortion free as possible.


The speakers are muted using the LM4861 shutdown pin driven from the headphone socket built-in switch.


The board was tested with headphones, a small 4 ohm speaker and a larger home speaker. Sound was as expected, and there are no known issues although more testing needs to be done. The board runs cold unless driving a speaker, in which case the LM4861 which is intended to be run without heatsinking in normal temperatures, would perhaps benefit from a tiny heatsink such as this one. The BBB image that I used outputs 16-bit audio at 48ksample/sec (i.e. the sound is as good as a regular CD player), but the DAC will work at higher resolution and sample rates for those with recordings that would benefit from it. The board was tested on an older Angstrom image and a Debian image. There are discussions in the comments section in the earlier post describing current ongoing exercises to get drivers working for different settings.



The described circuit is low cost and provides hopefully nice performance. The complete schematic and parts list is attached.


There are many compact LCD and OLED displays available, but the documentation tends to be poor. This is just a quick post to record a working configuration (circuit and code) to get a compact OLED display working. A 160x128 OLED display was selected, model DD-160128FC-1A (Farnell code 1498857, also available from Newark). It is a very high quality display.


The display is an Organic LED (OLED) type. For interfacing a similar-sized LCD display, see here.

The code that was written is targetted for the BeagleBone Black (BBB) but can be very easily adapted for any platform. For the BBB, it uses an I/O library called iolib (see here for more details) intended for quickly prototyping a solution. The library code is already included in the zip file attached to this post.


The code is prototype level – ideally it would be rewritten to use faster interfaces (e.g. SPI, or PRU processor), but it runs fast enough for many use-cases - with the current code the display update rate is more than sufficient for text information and simple diagrams. Perhaps 30 updates per second are possible with the current code if the entire screen is not being refreshed.


The code has a few graphic commands but not much – it is an easy matter to use one of the many existing third party graphics libraries if anything beyond simple text/graphics is required.

The current code has just these capabilities:

  • Point plotting
  • Line plotting
  • Rectangles (filled, unfilled, bordered)
  • Scalable Text
  • Graphic image read from raw file into RAM
  • Graphic image display from RAM


Display Dimensions and Notes

The display has a Densitron code DD-160128FC-1A. The screen has the label “UG-6028GDEAF01” on the rear. A connector by Omron (Omron code XF2M35151A  Farnell code 1112561) should fit.

Shown below is a diagram from the datasheet. The screen is very thin (about 1.5mm). There is an in-built controller (Syncoam SEPS525) located in the hatched purple area. The display is organized such that memory address 0 is top-left (where the round blob is shown) like most displays. Personally I prefer to have the origin at bottom-left, so the code uses that reference point as (0,0) instead of top-left.



Example Images

These photos were taken in a brightly lit room. The screen appears bright, sharp and has a more rich/saturated quality than LCD displays:



This animated character is drawn at position (0,0), since co-ordinates are taken from bottom-left in the attached code:



An example menu. A circuit board could have buttons to the side:




Note - The photographs are more representative of what the display looks like in action. The image quality appears extremely bright and sharp when viewed in person – about the same as a mobile phone

The video clip here is only really useful to show the update speeds for the current code. The pulsing/flickering and horizontal banding visible in the video is not apparent in real life.

Click here for the video- having real trouble with it, it is from a camera I don't normally use and the quality is pretty bad - sorry. The final animation is actually quite smooth in real life.



There is an optional demo board available, but it is quite basic; it has no active components, it is almost just a breakout board. The demo board was intended to speed development up, but the datasheet slowed things right back down again - the datasheet from Densitron is poor and has many errors (they have taken absolutely no care to review it).

This is the required circuit to get the display working in a serial mode:



An appropriate connector shown here (Farnell code 1112561) should be compatible (35 way, 0.5mm pitch) but was not tested.


The display requires a low voltage supply (3.3V max) which matches what the BBB offers. A higher voltage (13V) supply is also required. I didn’t have any appropriate IC over the holiday period, so a Maxim MAX734 was used, with some resistors used to adjust the voltage to 13V. This is not recommended since it is outside the specification of the MAX734, but the circuit is shown below since it worked for the prototype. It is recommended to use a different circuit.


Once assembled, the circuit was connected to the BBB as indicated in the schematic. The 0V, +3.3V and +5V supply rails were powered directly from the BeagleBone, using the BBB header P9 pins 1, 3 and 5 respectively.



The code is attached to this post. It is written in C. Refer to the file ‘oled.c’ to see the functions available. The main function currently also resides in that file. It runs five demonstrations when executed.


To use it, create a folder off the home directory (/home/root in my case):

mkdir –p development/oled
cd development/oled

The path will now be /home/root/development/oled

Copy the files into this location, then type the following to compile the code:

make install

The demo can now be run by typing:




It would be worthwhile creating a board for this display, and using it for small projects with the BBB where a high quality image is needed. A good amount of information can be represented on this display. It is easy to use with the example C code library, but will require a 13V supply (a small circuit can be used to generate this from the BBB’s 5V supply rail).

For larger displays, the 4.3” and 7” BB-View displays are available.


The revision 1 code is attached below for reference, but is also available here so that changes can be tracked.

This was a quick (and interesting) project, to get the BBB prepared for programming programmable logic. If you’re interested in implementing programmable logic, then this is a useful first step so that you have a tool for programming the devices.


The solution here allows you to program Xilinx parts (CPLDs and FPGAs) at zero cost (assuming you have a BeagleBone).


It is browser-based and simple to use with drag-and-drop programming. Just drag your programming file from the desktop onto the beagle in the browser.. no menu or CLI at all. It was surprisingly fast, too. It takes just a few seconds to program a small CPLD. For a simple project using this programmer, see here.



How Does it Work?

Xilinx programmable logic chips (FPGAs and CPLDs) have a JTAG interface; the BBB runs some software that can take a programming file and send it over some I/O pins that are connected to the target device JTAG interface.


The code is easy to implement because Xilinx have done the hard work - they have code and a paper, and their existing code was adapted slightly. For the BBB I/O, the C library here was used and this made it a quick thing to get running.


For the web interface, Node.js is used (thanks to Drew for making me aware of it!), and some javascript code called dropzone found on the Internet is used to get the drag-and-drop functionality implemented. I had a little difficulty with MIME and UTF-8, and if anyone has a better solution than my quick hack, it would be appreciated. It needs some thorough testing still - I just tested with a small file, using FF, IE and Chrome.

Getting Ready for Programming

Creating the programmer described here, or using it, does not require the Xilinx development environment, but you do need to download it if you’re interested in programmable logic designs. Also, download it much in advance to requiring it because is quite large (multiple GBytes) so be prepared for a very long download. They also offer DVDs but they can take months to arrive, so really the only option is to download. The location to download is shown here.


Obtain a Development Board

You will also need a test board to play with; there are a few options. In the CPLD space, these options are worth considering:

  1. Purchase a blank board and parts (Gazunty Pi) at low cost – Intended for the RPi, but it would be fine with the programmer here. The Gazunty Pi uses a XC9500XL device
  2. Purchase a pre-built board (£15) from Farnell (Digilent board) or Newark that uses a XC2C64A device
  3. Build your own test board on prototyping board (will supply more detail later if there is interest) – I chose a XC2C64A device (UK Farnell link / US Newark link).


Photos of the three options are below. (Derek from Gazunty Pi, I hope you don’t mind me using your photo).







I went with options 2 and 3 because I’m familiar with that particular part. Despite it being surface-mount, it is large (0.8mm pitch pins) and easy to hand-solder with a normal iron. Also hardly any pins need wiring for test purposes so a SMD prototyping adapter board can be used rather than a custom PCB.

For the circuit diagram, you could follow the Digilent board circuit. The green bit in the photo above is a voltage regulator and you can see a few small capacitors were soldered directly on the prototyping adapter board.


Regardless of option you choose, it is worthwhile buying a small oscillator too for reasons to be explained later, and soldering it on somewhere. You can see it on the underside here, soldered upside down. I chose 32MHz - just gone out of stock! But any value in that ballpark will be fine, e.g. a 20MHz oscillator.



In the FPGA space there are several options too. Perhaps the lowest cost (but good value) board is the Papilio One from Seeed Studio ($38). However a CPLD is a better choice to start off with.



How to use the Programmer

There are just four signals and 0V that need connecting from the BBB to the Xilinx device. They are indicated in the diagram here (used the Digilent board as an example).


Once you have the BBB powered up, type

node index.js

This will start up the web server, and then you can browse to:


Then just drag the desired file onto the dog, and it will program the board within seconds. It doesn’t give any indicaton of completion today :-) I might get round to implementing that but, after programming, the target device will immediately begin execution so you can see that the programming is complete. There is no need for a power-cycle either; to reprogram the device, just drag another file onto the beagle. If you wish to use a command line option, the syntax is:

./xprog_app my_programming_file.xsvf


The photo shows a typical use scenario - there are six wires between the CPLD board and the BBB (TMS, TDI, TDO, TCK, GND) and also VCC so that the CPLD board is being powered from the BBB. The BBB is plugged into a DC supply and into the network so that it has an IP address, and a web browser can allow you to drag the file to be programmed into it.



Compiling the Software

For convenience, create a folder on the BBB off the home directory (e.g. call it development, and inside it another folder called xprog and unzip the code inside there. Install the GPIO library from here. To compile the code, type

make clean

(If you make any code changes, type make clean first - there is a bug in the makefile).

Then, plug in the wires to the CPLD board and run the code as described above.

The code is still fresh so there may be bugs. If you spot any, please let me know! It has been tested on a single CPLD so far.

(Code now attached).

(Note: The BBB supports all programming languages - this post is for those who wish/need to use C, but it's not always an ideal language - it is strongly recommended to investigate the in-built, web-browser based 'Cloud9' developement environment and Bonescript).

Note 2: The library is well worth considering for C code projects, because it is very easy to use. The text below describes it in detail, but to summarise: All that is needed is to include the header file, and then do iolib_init(), and then set directions for ports using iolib_setdir specifying the physical header and pin number on the BBB, and then using pin_high() or pin_low() functions to set pins high or low, and using is_high() and is_low() to check the levels for input pins. Call iolib_free() at the end of your code.

Note 3: vegetableavenger has taken the original code and extended it to a more complete library, and also created some very good demos to do things like control 7-segment LED displays and ultrasonic range sensors. After you have read this post and comments to get an understanding how to use the library, it is suggested to go to Meng-Lun's resource here to download the code and any demos that you are interested in. All are documented with graphic diagrams.



There are Python I/O libraries for the BBB, however I had not seen a C library – I may have missed it. Not everyone uses Python! And I’ve been mainly using the PRU. So, I spent a few hours creating a basic library.


It allows you to program in C and control simple I/O, up to around 2MHz speed. (This is quite slow I/O, but it is very simple to use because it hides all the detail. If you need extremely high speed I/O, the BBB can operate I/O pins to 200MHz using the in-built dual PRU processors by the way).


The main benefit of this library is that it is very easy to use, and the 2MHz speed can be acceptable for many use-cases.


Here is how to use it:

  1. Type make clean followed by make all to build the library
  2. Copy the libiofunc.a into /usr/lib
  3. Copy the iolib.h into /usr/include
  4. Write your C program, as shown in the example below; it will use functions iolib_init(), iolib_setdir(), pin_high(), pin_low(), is_high(), is_low() and iolib_free()
  5. Compile using: gcc -c main.c -o main.o followed by gcc main.o –liofunc –o main_app
  6. Execute your program as usual using ./main_app


Here are some snippets of an example C program. A full example is in the attached zip file.

(Note: the zip file is left below and will eventually be removed, however vegetableavenger now has a repository for the latest code at this location).

First, in the C file, include iolib.h:

#include <iolib.h>

In the main() function, initialise the library:


Then, tell the library which pins you want as inputs or outputs. Here, header P8 pin 12 is set as an output:

iolib_setdir(8, 12, DIR_OUT);

Set the pin high or low using the pin_high or pin_low functions:


If you need a short delay (0-999 milliseconds), use this function shown here. For longer delays, use sleep():


For inputs, you can check if a pin is high or low using is_high or is_low functions. This example checks header P8 pin 11 (assuming it was set as an input):

if (is_high(8,11))

At the end of the program:



It is not a sophisticated library (it does not perform' pinmux' which is used to manage the vast multi-function capabilities of each pin through mode changes) but it should be good enough for simple control of hardware. With the appropriate circuitry it is fine for controlling relays, LEDs and handling switch inputs. The absense of this mode changing capability means that not all pins will work, so please test the pin before you use it (some example code supplied that will let you choose any pin and the direction (input or output), and then it will toggle it so that you can test it with an LED, and will print the state so you can test it as an input using a switch). When I get a chance, I will test each pin to confirm if the default state is in the correct mode for GPIO or not and write a list. But for now, please test the pin you wish to use (and use the comments section to help others by reporting which pins are suitable without requiring any pinmux performed).

Example circuit and code to demonstrate the functions

The example code can be compiled using:

gcc test_app.c –liofunc –o test_app

When run, it will blink an LED at a slow or fast rate. The rate depends on a switch input being pressed or not.

Here is the circuit layout. The BBB offers 0V and 3.3V pins on the header, and these were used to connect the LED and switch:


The code is quite short and easy to follow:

#include <stdio.h>
#include <stdlib.h>
#include "iolib.h"

    int del;
    iolib_setdir(8,11, DIR_IN);
    iolib_setdir(8,12, DIR_OUT);

        if (is_high(8,11))
            del=100; // fast speed
        if (is_low(8,11))
            del=500; // slow speed





Here is what the circuit looks like:



The source code is supplied if you wish to make changes (there may be bugs, so please check each pin with an LED or a switch before you use it, and let me know of any errors).

Note that the library will try to return an error code if it believes an incorrect pin is being used (not all pins are available).

So, you can do:

If (iolib_setdir(8,11, DIR_IN) != 0)


To test a pin, compile up the attached program file testio.c and run it. It will prompt you for the desired pin to test, and will then perform the LED toggling or text output indication of high/low for the pin as mentioned earlier.

The graphic template is attached for documenting any projects.


vegetableavenger also has another example that implements a digital temperature sensor at this location where the latest copy of the library can be downloaded. See the Demo_ADT7301 folder there. See the Demo_LED folder for the example illustrated above.


A few pins confirmed to be in GPIO mode by default without requiring any mode changes. I have not tried many pins.

Header P8:

Pins 11, 12, 15, 16

Edit: nikorun2 has tested further pins on P8, see comments below:

Header P8:

Pins 3, 4, 5, 6, 11, 12, 15, 16, 20, 21, 22, 23, 24, 25, 26

Note: There are many types of motors (and also sub-classes) – this post is about the most commonly encountered motor (as in electric toothbrushes, mobile phone vibrating motors), also known as a permanent magnet brushed or DC commutator motor – just referred to as a DC motor below.



This post is to document some experiments in driving DC motors using the BBB. The end result was a simple, low-cost circuit that it is hoped can perform well for many robotic applications for the BBB. While it can operate with many typical small DC motors, it is easiest to use with some higher-performance motors that are expensive new, but are often available as surplus or used motors from ebay.


Some tests were done to investigate the performance, and the videos below show some of the tests in action. The results were measured and are recorded further below. The exercise required a mini test set up, it was quickly made from not-great construction skills,  balsa and PVA glue and sprayed with acrylic primer to soak into the wood and hopefully make it a bit tougher. It is described in detail further below.


In this video, pay close attention at the green label attached to the motor shaft and the LCD display below. For now, bear in mind that the motor is actually running 16 times the speed (it is geared down 16:1) and is under a load.

What problem do we not want in the design?

If you’ve tried to use PWM with a H-bridge (and no feedback) to attempt to control the speed of a DC motor then you will have noticed that although it works well when the motor is driving nothing apart from its spindle, in a real scenario the speed is not in your control; where the motor is driving a load the behaviour changes and the speed is reduced; it may even stall. As an example: you’ve just created a mobile robot, and it relies on the PWM mechanism just mentioned. It may run fine on a perfect surface, but as soon as it encounters an incline - or a rug - , the behavior is unpredictable because it’s motion (speed, and hence position [maybe totally stalled]) has been affected by the load that it is experiencing, and often this is not possible to predict. If it is relying on timing and speed (i.e. dead reckoning) to figure out where it is, then the result will now be very inaccurate. Also, the motor may now be suffering from operating outside of its specification if the motor has slowed or stalled.

What is the PWM signal doing?

Motors turn at a speed dependant on voltage, and the PWM signal is essentially supplying a certain (average) voltage to the motor dependant on the PWM duty cycle. PWM is not necessarily the best way to drive a motor, but it is convenient in a digital world.

How about Stepper Motors?

The effect mentioned above makes it difficult to use such a motor system when you want to do accurate things in robotics, and so stepper motors sometimes get chosen.

However, a stepper motor while the best and appropriate choice for some scenarios isn’t always the right option. They are less efficient (a problem for battery powered and small, lightweight designs) and they cannot be run at such a high speed (in the low range of a few thousand RPM with acceleration) – however they are designed for high positional accuracy, and also provide far higher torque for a given size than a DC motor. With DC motors gearing is often needed to obtain a useful torque and a useful speed. Ungeared the speed of DC motors can run well beyond 10,000 RPM.

How can the problem be solved?


As an example scenario - the Mars rovers did not use stepper motors for their wheels; they used DC motors.

It is clear that the voltage (or PWM duty cycle) needs to be adjustable and this can be achieved with an automatic feedback mechanism (also known as closed loop control). Feedback can come from different methods.

Adding feedback provides the capability to adjust the PWM drive depending on real conditions that the motor is experiencing. If the motor is slowing due to load, then the error (difference between the desired speed and the actual speed) can be used to increase the PWM on-time in order to increase the motor speed.

So, a closed loop motor controller needs to be pursued.

The plan of attack

The normal method is to manage the entire control using a  DSP. However for this experiment a combination of analog, digital and software methods were used. It comes at the expense of additional hardware and the usual inflexibility of hardware versus a software implementation when it comes to making adjustments or implementing more advanced algorithms. This is especially true with control applications like motors. So, while this method may be of less practical use nowadays for commercial projects, it serves two purposes

(a)    It still gives good performance for custom, one-off designs for home use

(b)    It is useful to show the fundamentals of the behaviour, in the analog domain to compare with a software implementation

The latter purpose serves as a good learning exercise, since control theory isn’t the easiest thing in the world without practical examples.

How does it work?

A typical H-bridge circuit was used (consisting of four MOSFETs). There are a lot of bad circuits for this particular topic on the Internet..


The actual circuit used is shown further below.

The motor is a conventional brushed DC motor, but it has a number of high-performance features (however any motor could have been used – but not with the same results). This type of motor can be obtained used from ebay; for a new motor, the cost is high but for good reason: the technical features allow the motor to rotate more smoothly than conventional lower-cost DC motors and have a higher power for a given size and rotate faster and run cooler. When you consider that similar motors made it to Mars then the cost doesn’t seem so bad. These motors are an attractive choice in addition for the fact that they can be purchased with built-in gearing and encoder which greatly simplifies projects.


Regardless of motor choice, it is possible to use an external encoder. There are different types of encoders and as a digression there are some high-resolution ones made by Avago.

These encoders are nice because they can be fitted onto the end of any shaft in a system, it doesn’t need to be the motor shaft. These encoders are overkill and not advised for this particular task (but they would be absolutely great for – say – home telescope control), and a far lower cost method is to use this IC and a small magnet. I’ve not had a chance to try it, so I’d be interested to hear if anyone else has.

The exact number of pulses per revolution does not matter, but you don’t want it too high, because it makes it harder to generate an error signal with the low cost circuit as will be seen later.


Typically PWM is generated by a microcontroller but in this case an analog circuit was used, for a voltage controlled PWM setting. The feedback signal is generated by creating (using the rotary encoder) pulses of a fixed width, each time an encoder transition occurs. The fixed width pulses occur more rapidly when the speed is increased. They are converted to an analog signal using a classic op-amp circuit known as an integrator and this signal is used to adjust the voltage controlled PWM level.



The entire system mentioned above can run without a processor (except for setting direction and the PWM voltage), with the analog circuitry described above and digital logic. It was decided to feed the fixed pulse signal into the BBB, so that it could count the pulses; this allows a second control loop of course; in my case the pulses were used to measure the rotation or distance travelled so that the motor could decelerate or stop under program control when it reaches a certain position. The BBB is ideal because the pulses are fairly narrow and frequent. The BBB's PRU capability can easily capture them without skipping, and there was no need to use an interrupt input.


You might be wondering (and so was I) if it can have anywhere near the accuracy or repeatability of a stepper motor because there is no control of individual windings in the motor, so it may overshoot. Or, the gearing (which would nearly always be required with a DC motor) may cause play (backlash) and cause inaccuracy. So a test was needed. The theory was that accuracy (compared to a stepper motor) should be achievable but to find out how accurate, tests were required (described below).

The Implementation

Conveniently most of the circuit was implemented in just a few ICs. ON Semi’s MC33033 is a very low cost (and high performance - great value for money) motor controller intended for a different type of motor (three-phase brushless motors) but the datasheet shows that it can be used for DC motors in an open loop (i.e. no feedback) design. However the datasheet also shows a closed loop three-phase brushless design so it was decided to try to combine bits of the two circuits. The end result is that the single MC33033 IC is used for the entire motor control and for the op-amp integrator.


The IC also features a capability to protect the motor (for example if it experiences a very high load) by monitoring the current and reducing the PWM width accordingly.

The rotary encoder output is converted to a fixed width pulse train using a dedicated low-cost IC (MC33039). The PWM setting voltage is achieved using a TI dual 10-bit DAC (the second channel is not used but could be utilised for a second motor or some other purpose). Clearly the BBB could have generated a PWM train to use as a DAC, but the DAC simplifies the software.


A more detailed explanation of the control loop, error signal and results will be added at a later date to this post – I wanted to get the bulk of the information out while it was still fresh in my head.


In quick results, for my test-bed, the speed under a certain load (described further below) and compared with a reduced load was very similar at about 4700RPM (not measured very accurately at the moment – to be updated later).


The actual H-bridge was based on external MOSFETs for flexibility in future. Note that you may find you need the usual external diodes across the MOSFETs (the internal one is not well spec’d for some MOSFETs). The inductor is not essential but is useful if your motor has a low inductance, to help smooth the ripple current.



The entire circuit is quite small and fits on a 3.5x5cm PCB. All parts (although surface-mount) are hand solderable with a normal soldering iron.


Test Bed and Results

In quick tests, the performance is nice; it is possible to adjust the speed with far greater control than H-Bridge circuits driven by PWM with no feedback, and the motor can be driven very slowly or fast and in all cases the motor can overcome a load. The way it was tested is described here.


The problem was that it is hard to create a fixed load; friction against the motor shaft could have been used, but the concern was that it would be varying, or become very unrepeatable. So, it was decided to try a ‘tug of war’ type of test, where another motor would be connected to the motor under test. The ‘fighting’ motor (not a technical term!) would try to turn the other way (i.e. to try to turn the motor under test to rotate in the opposite direction), by applying an adjustable voltage to it. A low enough voltage was applied so that the motor was just on the threshold of rotating in the opposite direction (about 0.9V in this case – called the ‘fighting’ voltage in the test results for now). I was worried about damaging the motor, so I didn’t do this test for long. However, the current consumption was fairly low (about 26mA) so it was a semi-calculated risk.

A side view of the test bed can be seen here:


To couple the motors, clear plastic tubing (actually heatshrink but it was not shrunk) was coated on the inside with PVA glue and then placed over the gears on the two motors. This was so that the join could be slightly flexible if the motors were not perfectly aligned, and so that the tube could be easily removed afterwards (and the glue scraped off) without damaging the gears.


The motors were mounted in the balsa wood blocks and were wrapped in tape and epoxied in position. The epoxy and tape can be removed, so it is not permanent.


The holes at the top of the blocks were going to originally have nylon screws to hold the motors in place but the motors were easier to align with glue.

The actual rotation (versus the programmed desired rotation amount) was measured using a FRDM-KL46Z board (even though the BBB could have done it of course).


The KL46Z makes an excellent low-cost ($15) test tool for this purpose; it is described in detail here. It has a built-in LCD for displaying data:


Two main categories of test will be done – measuring distance and measuring speed. Currently only a couple of distance related tests have been completed. More results will be published later as they are done.

Test 1 – Short distance at a slow speed

The motor under test was programmed to rotate for one revolution (360 degrees), at a slow speed. The actual rotation (in degrees) was measured.

This is a video of the test (results are detailed further below):

Test 2 – Long distance at a fast speed

The motor under test was set to rotate at its highest speed and to turn 10 revolutions (3600 degrees). The actual rotation (in degrees) was measured. The video is shown at the top of this post (in the introduction).

Motor Details

The motor had a rotary encoder that generated 12 cycles per motor revolution; this results in 12*4 = 48 quadrature pulses per revolution. The motor was geared down by a ratio of 16:1, so the number of pulses per revolution (360 degrees) is 48*16 = 768 pulses. As mentioned, the FRDM board was used to count pulses and display them on the LCD.


Each test was run five times, and the results are listed below.



This is really just some of the tests that really ought to be done, but the initial results are promising. The system is very low cost (with e-bay motors for home use) and allows the BBB to accurately control movement.

Given the very compact size of the motors (the ones used for the tests were 10mm diameter), the closed loop DC motor method is a good alternative to stepper motors or the ‘continuous rotation’ modified servos for some scenarios.


Additional tests will be run and documented soon (while the test-bed still exists).

Code Details

The test code and schematic are attached. The test code is just programmed to rotate 10 revolutions when run and then exit.

The code currently uses the following connections on the BBB, but you may wish to select better ones (I just used these because I was already using them for a different project); these ones clash with HDMI which would then need to be disabled. You need pins which can be configured for PRU GPO and GPI (i.e. using R30 and R31) as shown here. I used PRU1 in my example.


To compile the code, type

make clean

followed by


Copy the BB-BONE-MOTOR-00A0.dtbo file that will be generated into /lib/firmware

Then, type

source ./ 

followed by


This was an interesting exercise to try to get simple camera capability for the BeagleBone Black directly (without USB) for some low-resolution imaging ideal for some machine vision use-cases, robotics and movement detection. The lower resolution means there is less data to process, and the opportunity to connect multiple cameras  (e.g. for stereo vision).

Here is an example image taken with the BBB.


This image was 160x120 pixels, and has been slightly corrected - although still quite washed out - and resized to 640x480 using bilinear scaling on a desktop but which could be done by the BBB – see here.

This is the actual unaltered image from the camera – the software saves it in .png format:


So, (as expected) the quality is not great (and probably not even well focussed – I didn’t check), but adequate for some use-cases. In the photo, Bert is about 55cm away from the camera, the top of his hair is 18cm from the floor and the furthest end of the blue block is 45cm away from the camera. Also, the image is flipped left-to-right currently; this is an easy fix of course. Note that some work will need to be done to make this a usable camera system.

How does it work?

There is not much to the implementation – it is a low-cost camera module (OV9655) - £9.58 from ebay (or £2.56 or less with no PCB), connected up to a buffer and then connected to the BBB. In other words, in much the same procedure as for the ADC here. The same buffer board was used.

This is a photo of the entire layout:


This is a close-up of the camera board (oriented with the connector at the top gave an image the correct way up (but with left-right flipped as mentioned earlier):


As you can see in the photo, some slight modifications need to be done – these are detailed further below. Note that the camera is the same one that is available on the STM32F4DIS-CAM module which is more expensive, but which won’t need the modifications.

Some buffering is needed as mentioned earlier and this is achieved with a 74LVC244A device and MC74VHC1GT50 (see the ADC post for information).

The diagram here shows the overall system:


On startup, the application initializes the camera (using I2C) and then starts off the PRU software.

The PRU code is very similar to the ADC example in that it sits and waits for a command, and then it captures data from the camera and dumps to shared RAM, ready for the Linux hosted application (called cam_app in the diagram) to pick up. There is a slight complication here, in that there is not much RAM available; there is just 12kbyte shared between the PRU and the ARM core. This means that it’s not possible to transfer the entire image in one go; I had to grab the image in 4 portions. The cam_app code sends a number between 0 and 3 to select the desired portion of image. To fix this requires a driver to change the RAM allocation.

The code dumps the data into a cairo buffer, and writes a file in png format. Although it works, the code (attached) is extremely untidy  and is just a quick prototype.

Hardware details

As mentioned, a low cost camera module was used. It requires some decoupling capacitors, otherwise expect it not to work at all. Even with decoupling, the camera only just worked with the extreme wiring in the photo earlier (time to make a PCB).

The STM32F4DIS-CAM documentation was used as a reference. The cheap ebay board was missing 1nF capacitors. The two photos here show where they need to be soldered (0603 sized capacitors).

The rear of the camera board requires two 1nF capacitors, where the yellow outlines are shown in the photo here. This is an unmodified board photo. The 1nF capacitors are just piggy-backed on top of the existing capacitors.


Below is a photo of the front of the camera board (unmodified board photo). Another 1nF capacitor is required at the yellow outline again piggy-backed.

At the red outline (i.e. across the two pins of the header), a 10nF and 1uF capacitor were both piggy-backed. Something higher than 1uF will be preferable.


At the blue circle in the diagram above, a 32MHz clock needs to be fed in; a 3.3V oscillator in a 7x5mm package worked fine. It can be seen glued upside-down in one of the photos earlier.

Buffers are needed for all the data lines (there are 8, marked D2..9), and preferably for the VSYNC, HREF and PCLK pins too. The table here shows the wiring from the BBB point of view, and how it is assigned to the camera (through the buffers). All pins are inputs apart from the buffer enabling pin. HDMI is disabled.


There was a lot of high-frequency noise on the VSYNC line. I tried to reduce it with a resistor in series, but I didn’t measure it in any detail to have much effect. I don’t know if it is related to the PCB layout and (likely!) the wiring. After a while, I gave up trying to resolve it on such a poorly constructed layout (a PCB is required), so the solution for this particular layout was to perform some de-glitching in software which worked well.

The longer term plan is to connect up at least two of these cameras to the BBB for additional flexibility, such as stereo vision capability. It would be easy to do, since the buffers have an enable pin.

Camera Protocol

The camera is capable of 1Mpixel imaging but for now, I set the camera to the very low resolution QQVGA (160x120 pixels) mode which is still useful for some applications, and to reduce the need for a driver to allocate more RAM.

Once the camera has been configured by the I2C-like interface for QQVGA mode, PCLK runs at 2MHZ continuously. This I2C library was used.

The camera configuration is stored in camctrl.c, and is just an array of data (register and data pairs) that is not annotated. However it can be decoded using the camera datasheet.

The video is comprised of frames, and each frame contains 120 lines. Each line contains 160 pixels.

Each pixel is in RGB 565 format, which means that 16 bits (two bytes) are used per pixel. So to summarize each line contains 160*2 bytes (320 bytes) and two bytes are sent, one after the other, per pixel.

In order to capture images, it is important to understand how the camera signals the start and end of frame, and the format of data for each line within a frame. The detail is described here.

Start of frame

The start of each frame begins with VSYNC going low. The diagram here shows VSYNC going low, and then after about 2.8msec the first line of data appears (i.e. when HREF goes low).

The diagram shows all the interesting signals; PCLK, VSYNC, and HREF. Only some of the data signals (D7,8,9) are shown. Note that signals D2..D9 will be used for the eight bits (D0 and D1 are not used in all modes).


Line format

The diagram here shows the data per line. At 2MHz the PCLK period is of course 0.5usec. Once HREF goes low, the line data is read. 320 bytes are read as mentioned earlier, per line of 160 pixels. Each burst of line data is 160usec long (i.e. 320bytes x 0.5usec) followed by 640usec delay until the next line.


The diagram below shows a zoomed-in view of the beginning of each line. It can be seen that each byte needs to be read on the rising edge of PCLK.


End of frame

The diagram below shows the last few lines before end of the frame. It can be seen that after the last line in a frame (i.e. 120th line) there is approximately a 990usec delay until VSYNC goes high to indicate that the frame is complete.


Not shown on the diagram above, VSYNC will stay high for about 800usec and then go low for the next start of frame indication.


Building and Running the Software

The code can be built by issuing make clean followed by make (if you make a change to the C source, type make clean first, becuase my makefile is broken - I have to fix it someday!). (Note - make sure the i2c library has been compiled and installed first). This will build three things; the cam_app software, the PRU code and a .dtbo file which is used to configure the pins. Copy the built .dtbo file into the /lib/firmware folder.

HDMI will need to be disabled (or, modify the code to use different pins available to PRU#0 - the code currently uses PRU#1). HDMI disablement is mentioned on the ADC page.

To run the code, first type source which will execute some commands to configure the pins using the .dtbo file.

Then, just type ./cam_app

The code will capture an image and dump to a file called img.png

Next Steps

It would be great to integrate the camera and buffer into a single module so that multiple cameras could be connected up to the BBB (and perhaps also a serializer for wiring convenience and distance). Or, a board with two cameras spaced eye-distance apart for 3D vision processing.

Note April 2017: There are different revisions of the BeagleBone Black since this post was written in 2013, and without testing them all, it is the user's decision whether to try this solution or not. The revision changes are listed here and a possible option for at least some revision boards is shown in the photo here but I've not investigated this. The newer BeagleBone Blue already has a battery connection, so that is another option.


This posting is about implementing a rechargeable battery system for the BeagleBone Black. It is simple, safe and very low cost (less than 6 Euro).




First, some brief information about the power circuitry on the BBB.


The BBB has a built-in power management IC (PMIC) based on the TI TPS65217C device. This device contains multiple switch-mode regulators and LDO regulators to provide all voltage levels needed for the entire board. It handles wake-up using a push-button fitted on the BBB. Automatic power-down via the button requires some software to be implemented (to do the equivalent of 'shutdown now' from the command line). When the button is pressed, an interrupt is generated and the microprocessor is supposed to query the PMIC (via I2C) to learn that the button was pressed, and kick off the shutdown sequence. In the event of a failure here, the power can be switched off by holding the button down for 8 seconds.

The IC also contains built-in battery charging capability.

Apart from the USB requirement of 5V, there is no need to run the BBB from 5V; it can happily run from a lower supply. This means that a single 3.7V cell could be used to power the entire board. No need to step-up to 5V or to run dual cells and step-down to 5V, both of which could have been inefficient.

Why is this useful?

It makes it an excellent platform for outdoor/portable use.

For indoor use a battery is useful because it serves as a backup supply in case the main power (from a mains powered supply or from USB) gets disconnected. It could prevent filesystem corruption. If the main supply gets disconnected, the battery immediately takes over. In fact, I permanently leave the battery connected even when I'm running from the mains supply, in case I forget to safely shutdown the board.

What battery can be used?

Any small Lithium Ion (Li-Ion) or Lithium Polymer (Li-Po) single cell can be used, preferably as long as it has a built-in protection circuit. If it doesn't have an in-built circuit, it is highly advisable that one with a built-in thermistor is used. A cell in the range 700mAH to around 2AH is advisable. The one that I used in the photo above is from Olimex part code BATTERY-LIPO1400mAh. It should last around 3.5 hours (EDIT: Now been measured, it lasts 2 hours 50 minutes - see notes below, and comments below) on a full charge (not measured) and should fully charge in around 2 hours. This particular battery is just the right size to fit in between the two rows of headers and is flush so that a cape can still be plugged on top. So, the entire thing can fit inside any enclosure.

You will also need a connector (see next section) and one resistor.

Construction detail

The BBB has four holes that are suitable for connecting up the battery. They are detailed in the BBB system reference manual (SRM):


This is what they look like:


The Olimex Li-Po has a built-in protection circuit, so I soldered a 10k resistor to TS and GND to simulate the thermistor. (EDIT: You may or may not wish to do this, please study Li-Po and use your own judgement - see comments below) It is desirable to use a connector for the Li-Po.

The LiPo connector was convenient to solder to pins TP6 and TP8, and then  a zero-ohm link between TP5 and TP6 on the underside.

Here is how it was done step-by-step (there are just two steps):

1. Solder the 10k resistor, and a zero-ohm link (both are achieved on the underside of the board) as shown here in the yellow box. These are simple 0603 resistors; I used a 1% tolerance resistor, but 5% should be fine.


2. Solder in the connector.

This is straightforward, but complicated slightly by the fact that the connector has 2mm pin spacing, but the board has 0.1" spacing. It means that the pins on the connector need to be splayed or bent into the correct spacing. The connectors are available in vertical mount or right-angle (RA) mount. If you use a vertical mount connector, there may not be enough space to splay the pins. Instead, I used a right-angle connector and bent the pins into a vertical orientation, and then I had space to bend the pins and still have the connector flush with the board as shown here. You can see another view of the connector from the first photo.


I'm fairly sure that the desired connector is JST 'PH' series.


That's it; plugging in the battery, the board worked instantly. Note that the Li-Po charge method is usually to have a constant current supplied to the battery until it reaches a certain, very precise voltage. After that the charger switches to a constant-voltage mode. For the Li-Po battery that I used, the charger needs to be set to 4.2V, but the BBB by default sets it to 4.1V (It can be set to 4.2V via I2C control but today it doesn't). I'm not sure what the impact of this is (beyond storing less charge), but I believe it is safe. I have been using it daily for three months and the battery is always cool to touch.

Controlling the PMIC

The TPS65217C PMIC is very programmable; it has dozens of configuration settings specifically for charging and it has safety timer capability. The PMIC is configured upon startup via I2C. There are three I2C busses on the BBB, and one is dedicated to on-board peripherals. Control of the PMIC is not normally possibly by the user; it requires driver code or possibly there is access by the device tree infrastructure. Checking the .dts file in /boot did not reveal how to control the battery charger functionality. There are two current Google Summer of Code (GSoC) projects that touch on PMIC:

1. IIO, ADC, PMIC, LCD debug/patchwork (summary page, blog page) - Zubair Lutfullah

2. MINIX I2C drivers (summary page, blog page) - Thomas Cort

Hopefully the guys working on the projects (Zubair and Thomas) can offer some advice on how to set the level to 4.2V. Zubair's project also includes how to use the in-built ADC inside the AM3359 to monitor voltages.


There really should be some more detail including measurements to show how long the battery lasts and to observe the charging status (via I2C reads). Unfortunately I didn't have time to collect this information. But I've been using it for three months regularly and it functions well.

EDIT: The following simple test was conducted using the Olimex battery referred to above.

1. Power up the BBB using the DC power supply and let it charge the battery while powering the BBB

2. After about 4-5 hours, the DC supply was disconnected, and a script was run on the BBB to log the current date/time to a file, every minute. The script would sleep in-between. The Ethernet connection was left up, and the BBB was left alone until the battery died, and then the log file was examined.


while true; do
date >> log.txt
sleep 60


The result was that the log file showed that the BBB ran for 2 hours 30 minutes before it died. After this, the test was repeated. The second time, it ran for 2 hours 50 minutes. The discrepancy may be because this battery has never been fully charged followed by such a long discharge, and so perhaps it is related to that. No test has been run with the Ethernet disconnected, but the BBB should run for longer in that case of course.

In a third test, the battery again ran for  2 hours 50 minutes (to within 1 minute). Again, this was with the Ethernet interface up.

This was a fun yet initially challenging experiment, to find a convenient way to read in data at a reasonably high speed on a BeagleBone Black. This photo shows the results from a mobile, showing a couple of sampled waveforms (100kHz and 1MHz sinewaves in this case).


This was another capture of the same signals on a PC (this is an older picture with a x10 probe so the amplitude is a little low in the photo - it should fill the screen).


What does it do?

In its current state, it grabs analog data from an ADC, and dumps it into memory on the BBB, ready to be displayed or further processed. It could be used for gathering analog information from sensors, CCDs or other data acquisition use-cases. To be reasonably useful, the desire was for it to support 20Mbytes/sec of data or more. It does achieve this, but it is for further study to find higher speed methods.

How does it work?

A few different ways were considered. The initial approach was using an FTDI device (USB interface). However the method described here just feeds data directly into the on-chip 200MHz PRU that is part of the Beaglebone’s AM3359 chip. Other methods are possible too.

It was also desired to have an external clock, so that the data could be sampled at a determinable jitter, so that it could be useful for frequency analysis, or maybe Software Defined Radio (SDR).                                                            

The overall approach that was taken is outlined here.                                                                                                                                                                                   


The analog signal was amplified and fed into a high-speed ADC (A parallel bus ADC is needed in order to achieve high throughput).

A pre-built amp+ADC board was used from KNJN (note: in my opinion it is not a good choice, because it is closed source; there are no circuit diagrams for it so it is hard to modify it, the datasheet is sparse and also it is expensive; better to construct one up manually).

A linux application (called adc_app in the diagram) was used to kick off the PRU code which reads in data and dumps to shared memory. Once complete, the adc_app stores it in a .csv format file.

I wanted to try out Node.js ever since a recent blog post, so some very basic code is used to create a HTTP server.  The real-time comms between the browser and web server is achieved using Socket.IO which is a way of passing arbitrary data.

A photo of the overall system:


A bit more detail:


The underside was more untidy!



ADC Detail

As mentioned, a ready-built amplifier and ADC board was used. The on-board oscillator was disabled, so that an external one could be fed in. I needed a clock of 20MHz or less, but I only had a 32MHz oscillator at hand and didn't want to wait (and the local Maplin store doesn’t sell any 3.3V-compatible logic to divide by two!) and I’m not entirely sure how long the shared memory write takes, and I did experience lost samples with the 32MHz oscillator. I plan on trying frequencies in the range 14MHz-20MHz to find the upper limit for missing no samples; for further study!

Note that some ADCs will have specific requirements related to the clock and duty cycle.

The ADC on this particular board was ADC08200 but an ADC08100 or ADC08060 could have been used at lower cost).


These were extremely important for two reasons. One reason is that the pins to the BBB that I wished to use need to be isolated during power-up, because they are used for selecting the boot method. If there was any unusual level on the pins upon power-up then the BBB will not boot from the eMMC. So, a tri-state buffer is needed.

The other reason is that there is a fair bit of capacitance and it is highly likely that the ADC may not be able to directly drive the pins at high speed. I actually came across this problem while trying to connect a camera to the BBB. I struggled for days without realising that the camera could not support the load. So, the buffers are likely to be essential for most designs using the pins that were selected. I used a 74LVC244A device as a buffer.

Note that the clock also needs a buffer, unless significant jitter is acceptable. No tri-state is required here, so I used a MC74VHC1GT50.

PRU code

The PRU code uses shared memory for communication. I designated a single byte of shared memory to be used for commands. When run, the PRU sits in a loop waiting for the command to instruct it to begin the data capture.  PRU GPI mode is used which allows inputs to be read at the processor speed of 200MHz with no varying latency. Just a few instructions are needed to populate the data into shared memory. No attempt was made to pack the data, and 32-bits are used to store the 8-bit sample. This is not such a bad idea, because in future the ADC could be swapped out to a (say) 10-bit ADC with no code change on the PRU.

There are two PRUs in the AM3359. There are a total of 12 PRU GPI capable pins available that are connected to PRU 1 which are brought out to port 8 on the BBB. So, this means that realistically 10 or 11-bit is about the limit for high-speed parallel ADCs connected in this manner. Still, at (say) 16MHz clock, this would equate to 20Mbytes/sec of data for a 10-bit ADC.

EDIT: See comments section - on PRU0, all 16 pins are in theory available).

The pins used are shared with the HDMI interface; it proved necessary to disable the HDMI interface by recompiling the device tree file in the /boot folder (EDIT: See Brian's comment below for a better method to disable HDMI). Since I wished to display the data using a web browser, I have no issue with losing the HDMI.

Once the data has been captured (2000 samples in this example), the command byte is acknowledged, so that the Linux hosted application can know that the PRU has completed. The PRU now sits and waits for a new instruction from the Linux hosted application.

These were the pins used. They were used as D[0..7], CLK and a *EN signal for controlling the octal tri-state buffer.


Linux hosted application

The adc_app program is very simple (C code); it downloads the assembled code into PRU1 and executes it. The resultant data in shared memory is dumped to a text file and then the program exits.

Node.js application

The Node.js application creates a HTTP server (no need for apache!) and a Socket.IO connection. This sits and waits for a connection from any web browser. Once it receives a connection, it will send a handshake and then wait for a ‘capture’ command from the web browser. It then calls the adc_app program. Once complete, it opens the file of captured data and transmits it over the Socket.IO connection line-by-line. This is very inefficient, but it is proof-of-concept code that could really be optimised.

Web Page

The web page served up contains some small bits of code to handle the Socket.IO connection and send a ‘capture’ request when a button is clicked and to display the received data with a canvas element and pixel manipulation.


In conclusion, it is possible to read analog data with low jitter at fairly high speeds without any external FIFO or logic (beyond a simple buffer IC), while continuing to run Linux applications such as a web server. It is also nice that a web-based UI can be rapidly created using Node.js.


Note: It is still for further study how long captures can be sustained and read off by the Linux application without any data loss. If it can be sustained, then it could be useful for SDR applications just about, although a higher speed (and better ADC) would be preferable.


Note2: The waveforms used to test out the system were generated by the same BBB using a low-cost ‘direct digital synthesis’ (DDS) board. That’s a subject for a later date.


Using the code

Disable the HDMI as mentioned in the comments.

You may need to install Socket.IO. Type this to install it:

npm install


Create a development folder and then the attached code can be unzipped to (say) /home/root/development/adc.


make clean
cp BB-BONE-HSADC-00A0.dtbo /lib/firmware/
node index.js

Then, navigate to http://xx.xx.xx.xx:8081/index.html


If you want to make subsequent changes, there is a bug in the makefile, and you will need to issue 'make clean' before typing 'make' whenever any change is made in the C code.

If you just want to reassemble the PRU code, type 'make pru' (no need for 'make clean').

These were rendered from the mfg bundle, and may be useful for documenting any changes/wiring as people start to customize their boards.








Introduction - why would you want to extend I/O over USB?

The Beaglebone Black's PRU allows very high speed I/O capabilities with guaranteed timing while Linux applications continue to run. As useful as this is, occasionally there may be a need to use FTDI's USB-interfacing UART/FIFO ICs to extend capabilities further. There are a number of benefits to this:


* It increases the number of I/O pins available

* It increases the number of serial interfaces

* Provides interfacing to traditional peripherals that require *CS, *RD, *WR signals and an 8-bit data bus

* High speed parallel data transfer (60MHz) in a FIFO mode

* Portability so that applications can run on any device with a USB port


In theory the notes here should work just fine for other processor boards too, e.g. RPI, but clearly having a good USB capability (and the processing power to handle high-speed parallel data transfer is important - and the BBB is the ideal platform).

Some example applications could also be listed, but it's clear the possibilities are vast. Another benefit is that it is possible to easily enable a USB interface on custom hardware, by simply adding a FTDI chip to the project. It's only fair to mention that there are alternative, possibly lower cost methods too. People have successfully shoe-horned small USB stacks into small PIC and AVR microcontrollers that do not possess a native USB interface. Atmel offer ATmega devices that already contain USB capability, at very little cost.

Other manufacturers like Silabs, Exar and Cypress produce devices with similar capabilities to FTDI devices too.

Is it easy?

It turned out to be surprisingly easy - almost no soldering if a pre-built board is used, and very little coding. For creating a custom board (e.g. with your own peripherals on it), FTDI devices don't need a lot of additional circuitry.

There are quite a few similar-sounding part codes, but the FT2232H (PDF datasheet) has been on the interest list for quite a while - working with the BBB provided the opportunity to finally experiment with it. For clarity, it is the FT2232H range, available in a QFP package as part code FT2232HL-R.


Connecting up the FT2232H to the BBB

Like most of FTDI's chips, it doesn't take a lot of circuitry to assemble, however in this case I just used a pre-built board available from Seeed Studio for a quick prototyping exercise.


Connecting this to a BBB is trivial - just plug in the USB connector and it will power up from the 5V offered by the BBB's USB host port. For experimentation, I tried the so-called bitbang mode, which provides 16 pins of I/O in two banks of 8. Of more interest will be the FIFO modes for high-speed data transfer at up to 60MHz.


When plugged in, lsusb reveals the following:

root@beaglebone:~# lsusb
Bus 001 Device 003: ID 0403:6010 Future Technology Devices International, Ltd FT2232C Dual USB-UART/FIFO IC
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Bus 002 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub


Note the 0403:6010 - this is the vendor and product ID respectively, in hex (needed later). The board doesn't come with any connector, so SIL headers need to be soldered. The reverse of the board shows the pin naming, and the circuit diagram is here.


The bitbang mode is brought out to the ADBUS[7..0] and BDBUS[7..0] pins. For input testing, I just pulled various pins high and low (i.e. to 3.3V and 0V) through a 1k resistor (in case a pin was accidentally still an output) and for output testing a multimeter was used (an LED and resistor would be fine too).

Software introduction

Generally, hi speed I/O may require kernel drivers; in the case of the FT2232H this is no different, but it is already part of Linux images. Some code and libraries are required as part of the application. This is explained in the diagram below.


The application software will be the area of interest, where the data is received and transmitted and any processing with the end data is handled. To connect to the kernel driver, a couple of libraries of code need to be linked in to the application code; these are libftdi (open source library for many FTDI ICs) and libusbx which provides a consistent API regardless of if the OS is Linux or Windows.

Building the software

This was quite simple; three downloads are required:

libftdi (download here) - I used version 1-1.0

libconfuse (download here) - version 2.7 - this is used for parsing text files for configuration purposes

libusbx (download link) - version 1.0.16

Create a folder off your home directory (e.g. called 'development') and create a folder called usb inside it.

The three downloads were extracted in the usb folder.

Installing libconfuse 2.7:

make install

(installs in /usr/local/include,lib and share)


For libusbx 1.0.16:

./configure --disable-udev
make install

(installs in /usr/local/libusb-1.0 and /usr/local/lib)


For libftdi 1-1.0, the makefiles are intended to be built with cmake, which I didn't have installed (and is a little unfamiliar to me) - however it is possible to build the code from the command line easily, there are not a lot of commands.

In the folder where libftdi was extracted, traverse to the 'src' folder. Then copy to ftdi_versio_i.h and replace the variables marked with '@' with a custom value. In other words, modify the following lines so that this is how they appear, and then save the file.


const char FTDI_VERSION_STRING[] = "1-1.0";
const char FTDI_SNAPSHOT_VERSION[] = "0";

In the same src folder, compile like this:

gcc -c ftdi.c -I/usr/local/include/libusb-1.0
gcc -c ftdi_stream.c -I/usr/local/include/libusb-1.0
ar rs libftdi.a ftdi.o ftdi_stream.o
cp libftdi.a /usr/local/lib/.
cp ftdi.h /usr/local/include/.

Now the code in ftdi_eeprom can be compiled (path is development/usb/libftdi1-1.0/ftdi_eeprom). It requires a file ftdi_eeprom_version.h to be created in a similar manner as before.


Type these commands to compile it:

gcc main.c -I/usr/local/include/libusb-1.0  -I/usr/local/include -I. -L/usr/local/lib -lftdi -lusb-1.0 -lconfuse -o ftdi_eeprom
cp ftdi_eeprom /usr/bin

Then example code files can be compiled as shown here for instance (path is development/usb/libftdi1-1.0/examples):

gcc simple.c -I/usr/local/include/libusb-1.0  -I/usr/local/include -L/usr/local/lib -lftdi -lusb-1.0 -o ftdi_simple
cp ftdi_simple /usr/bin

There is an another example program in the same folder, called bitbang_ft2232.c but it needs a small change; replace where it says 0x6001 (product ID) with 0x6010 in two places, and then compile:

gcc bitbang_ft2232.c -I/usr/local/include/libusb-1.0  -I/usr/local/include -L/usr/local/lib -lftdi -lusb-1.0 -o bitbang

When the bitbang program is run, it will just slowly toggle some pins (bits 0 and 1) on the two ports.

As an experiment, the code was modified to toggle pins with no delay for thousands of times; a speed of about 20,000 writes per second is possible, allowing for 10kHz square-waves (this was not measured on a scope, so it is just a guideline). Bitbanging in this manner will not have real-time accuracy like the PRU. (The FIFO mode that the FT2232H is capable of will be far better than bitbanging too, but needs to still be tested. However, bitbanging is still suitable for some purposes). Note: See comments section below. Accuracy is extremely poor with the bitbang way; an alternative method using buffers is available on the FTDI and that method should be investigated.

A quick program was created to test inputs in bitbanging mode too, and it reads input values at a similar speed. The program is attached (very untidy for now - it's late in the evening! but it works). The program reads the AD[7..0] pins repeatedly, and displays the 8-bit value in hex on the screen. Run it, and it will display lots of 0xff on the screen (the inputs appear to float high) and pulling low (1k resistor to 0V) on any of the input pins will make the text change.

To compile the code:

gcc bbtest.c -I/usr/local/include/libusb-1.0  -I/usr/local/include -L/usr/local/lib -lftdi -lusb-1.0 -o bbtest


Summary / Next Steps

To a large extent the PRU capability has rendered this almost redundant, but it's good to know that it is easy to interface high-speed data in several ways with the BBB now. The FTDI device is easy to use because a ready-built board is available, but equally it is easy to include the IC on a PCB where a USB interface is not currently available. Experimenting with the FIFO modes will be interesting.


Part 2: FIFO mode

A "synchronous FIFO" mode is available on the FT2232H, which is supposed to allow far higher rate I/O. In order to enable this, an EEPROM needs to be programmed. There is a ftdi_eeprom program that was compiled earlier (see above), however it did not work. The alternative is to just download a Windows executable called FT_PROG and use that.

Download FT_PROG from here  (PDF help file is here).

Run FT_PROG, click on the magnifying glass icon ("scan and parse") to read the board EEPROM. It will display as lots of FFFF, since it is a blank part.


On the left side device tree, expand to FT EEPROM->Hardware Specific->Port A->Hardware, and change the property from RS232 UART to 245 FIFO, which is needed for the FIFO modes to function. Repeat for Port B.

Then, go to File->Save as Template (e.g. my245fifotemplate.xml).

Select the Device:0 on the device tree, right click, and select 'Program device'. It should be virtually instantaneous, and the Device Output will show some new values instead of FFFF.

You could confirm all is well by restarting the FT_PROG application and clicking the scan icon again, and viewing the EEPROM contents.


Once this is done, unplug the FT2232H from the Windows maching and plug it back into the BBB. There is code in the examples folder called stream_test.c, and it is compiled in a similar manner as the other examples:

gcc stream_test.c -I/usr/local/include/libusb-1.0  -I/usr/local/include -L/usr/local/lib -lftdi -lusb-1.0 -o ftdi_stream_test
cp ftdi_stream_test /usr/bin

The program can be run by typing:

ftdi_stream_test -n dump.bin

It will capture data at a very high speed and dump to a file (unformatted raw bytes), whenever the *WR pin (pin 27 on the FT2232H-R chip, or P3_17 (ACBUS3) on the ready-built board is pulled low.

The '-n' suppresses error messages when bytes are skipped.

It appears that bytes are guaranteed to skip, and I'm guessing this is because there is a delay writing to the filesystem. With a very short *WR pulse (of the order of tens of nsec) the number of bytes written to file appear to be close to the expected value (assuming that the FT2232H is trying to capture at 60MHz). At any longer pulse, bytes are skipped. For further investigation!


BBB - Building a DAC

Posted by shabaz Top Member Jul 6, 2013

Part 2 to this post, which implements the prototype, can be found by clicking here.


Part 3 implements a complete design in an enclosure for a Sonos-like solution.


See Creating an Internet Radio for a complete project by the EAGLE team including board layouts



The BBB has an on-board I2S interface, which makes interfacing an external DAC easy. The I2S interface is connected from the AM3359 processor to the HDMI chip (TDA19988) but it is not required for HDMI to be used in order to make use of the I2S interface. The I2S interface is brought out to some pins on port P9 (see here for details). It was encouraging that Technoshaman and Donald Miller had some success with the interface, so I wanted to try it out and I got some time today.


Since the interface is capable of 24-bit/192kHz audio, it was worthwhile picking a nice DAC. A good but not over-the-top device seemed to be the Texas Instrument's PCM5101 which is nice because it has reasonable specs and also provides a built-in charge pump so that it can function from a single supply. A headphone amp was connected, and this was ON Semi's NCP2811A. The combination of PCM5101 (actually my prototype used PCM5101A which can also function from 1.8V, but this was not needed)  and NCP2811A was chosen so that the entire circuit could operate from the BBB supply if desired, even if it was from a Li-Ion battery that was powering the BBB, and for low noise and distortion. The only problem is that the PCM5101 has quite a high output (clearly a good thing!) but the audio amp minimum recommended gain is 1 and it cannot meet the required output voltage, and it means that it will distort at high volume. So, at a lower volume (and lower SNR) it will be fine, and I prefer this particular amp because of the very low distortion. The ON semi datasheet was sparse though.


This is the DAC prototype:


This is the whole thing connected up:


This is the rear of the board - a bit messier! It was built on a SMD to DIP adapter board with some copper tape for supply rails:


This is the audio amp - not a lot to it, since it is so integrated.



I made a recording, but excuse the quality. The audio is from a small 64 ohm speaker picked up by a simple camera in-built microphone so it sounds bad, but connecting to headphones is a different story - it sounds as good as an ipod (although this is subjective - I don't have a way to measure). Another thing I still need to check is that originally I thought the data was read on the falling edge of the bitclock on the BBB, but I2S specifies the opposite. Maybe I made a mistake in my initial observations (I have not had a chance to re-check), or maybe it changed in a build. But the circuit as shown here works for me.


This is running on an not-recent Angstrom downloaded build (maybe a few weeks old image), and I still hear some very slight audio issues - it sounds like perhaps a break for a few tens of milliseconds occasionally, only if you're listening closely. I really hope it is resolved in a build soon (or maybe it is due to ffmpeg - perhaps avconv gives better results).

EDIT: I've since been using mplayer (command line is mplayer -ao alsa -volume 4 AmyWinehouse-BackToBlack.mp3  and either I'm not noticing any audio issues or they have disappeared). I've concluded it sounds at least as capable as my old ipod touch, maybe better).


I played audio using the command line:

ffmpeg -i AmyWinehouse-YouKnowImNoGood.mp3 -f alsa "default:CARD=Black" -re -vol 150

and it reported the stream as:

Stream #0.0: Audio: pcm_s16le, 44100 Hz, stereo, s16, 1411 kb/s




This is the circuit. All the 3.3V supplies were connected together for the prototype (I wouldn't do that for real, although it sounded very good in my limited tests). The amplifier V+ can be connected to 3.3V or the 5V supply (or the Li-Ion battery directly).

Note 16th Jan 2014: See the comments section below for more detail; the SCK pin on the PCM5101A was disconnected from 0V and instead connected to the BBB P9 pin 25. This will provide the lowest jitter by disabling the DAC's internal PLL. A sample capture of the audio quality (captured from the headphone output of the NCP2811A, just to give an approximate idea of what it sounds like from headphones) is attached to the post below, in the zip file More info on it in the comments section below.




I've also tried a FLAC file, but I'm hitting some limitation with ffmpeg it seems, and it picks a 16-bit format when it ought to be 24-bit. Meanwhile, avconv I couldn't get to work for MP3 or FLAC (it reported 'av_interleaved_write_frame(): Resource temporarily unavailable'). If anyone knows, any tips on how to play FLAC at 24-bit would be gratefully appreciated.



root@beaglebone:~# ffmpeg -i Taxman_2009_Digital_Remaster.flac -f alsa "default:CARD=Black" -re -vol 5

ffmpeg version v0.8.4, Copyright (c) 2000-2012 the Libav developers

  built on May 20 2013 13:00:42 with gcc 4.7.3 20130205 (prerelease)

This program is not developed anymore and is only provided for compatibility. Use avconv instead (see Changelog for the list of incompatible changes).

[flac @ 0x2da80] max_analyze_duration reached

Input #0, flac, from 'Taxman_2009_Digital_Remaster.flac':


    ORIGREFERENCE   : 6C05C9F79EE74052A7991B9669B98533

    ORIGDATE        : 2009:09:14

    ORIGTIME        : 11:57:01

    TIMEREFERENCE   : 5292000

    CODINGHISTORY   : A=PCM,F=44100,W=24,M=stereo,T=SADiE5


    TITLE           : Taxman

    track           : 1

    ARTIST          : The Beatles

    ALBUM           : Revolver (24 BIT Remastered)

    DATE            : 2009

  Duration: 00:02:37.85, bitrate: 1892 kb/s

    Stream #0.0: Audio: flac, 44100 Hz, 2 channels, s32

Incompatible sample format 's32' for codec 'pcm_s16le', auto-selecting format 's16'

Output #0, alsa, to 'default:CARD=Black':


    ORIGREFERENCE   : 6C05C9F79EE74052A7991B9669B98533

    ORIGDATE        : 2009:09:14

    ORIGTIME        : 11:57:01

    TIMEREFERENCE   : 5292000

    CODINGHISTORY   : A=PCM,F=44100,W=24,M=stereo,T=SADiE5


    TITLE           : Taxman

    track           : 1

    ARTIST          : The Beatles

    ALBUM           : Revolver (24 BIT Remastered)

    DATE            : 2009

    encoder         : Lavf53.21.0

    Stream #0.0: Audio: pcm_s16le, 44100 Hz, 2 channels, s16, 1411 kb/s

Stream mapping:

  Stream #0.0 -> #0.0