Turnkey PRU deskclock application for BBB

I’m making available for image download a sample (clock) application with these features:

  • turnkey – after initial EULA agreement step, the application launches on boot
    • there is NO WARRANTY on ANY part of this project
  • uses both PRU and the ARM processor
    • not only one, but two ring buffers enabling fast data transfer (1.2MB/sec)
    • connected by /dev/mem
    • this app in no way needs this fast transfer, but your app might
  • Needs ILI9341 SPI (4wire) connection … PRU0 implements minimal SPI protocol:
    .asg “pru0outP9_31_hi”, RESET_HI
    .asg “pru0outP9_31_low”, RESET_LOW
    .asg “pru0outP9_27_hi”, DC_DATA
    .asg “pru0outP9_27_low”, DC_COMMAND
    .asg “pru0outP9_28_hi”, SS_HI
    .asg “pru0outP9_28_low”, SS_LOW
    .asg “pru0outP9_29_hi”, MOSI_HI
    .asg “pru0outP9_29_low”, MOSI_LOW
    .asg “pru0outP9_25_hi”, CLOCK_HI
    .asg “pru0outP9_25_low”, CLOCK_LOW
  • my wrapper for PRUdebug included and preconfigured
    • no djb configuration pain
    • easy to use with this app
  • video showing clock display during PRU stress test (1.2MB / sec)
  • image file NOT a flasher – run without EMMC modification
  • custom scheduler controls launch
    • ntp sync (clock app) … configured for Ubuntu pool
    • wait for remoteproc file system to be created
    • pin configuration
    • PRU initialization
    • application initialization
    • when using ring buffers, it is important that the processors are started in the correct order
  • application independent abstractions for pin manipulation … see pru.h
    .asg “.t1”, pru0P9_29
    .asg “CLR pruout, :pruout::pru0P9_29:”, pru0outP9_29_low
    .asg “SET pruout, :pruout::pru0P9_29:”, pru0outP9_29_hi
    .asg “CLR pruin, :pruin::pru0P9_29:”, pru0inP9_29_low
    .asg “SET pruin, :pruin::pru0P9_29:”, pru0inP9_29_hi
  • image file distribution has benefits similar to VM’s
    • dogtag – BeagleBoard.org Debian Image 2018-10-07
    • system code already loaded and configured
      • Perl
      • cr.yp.to
      • ncat
  • ILI9341 device orientation is landscape
    • if your display is upside down, the ‘flip_horizontal’ step can be adjusted
    • if device pins are on the left of the display, ‘flip_horizontal’ is a no op
  • video of earlier implementation:
  • Most of work done on PRU(s)
    • barely measurable ARM utilization
    • clock app generates and average of 650 bytes / second
    • PRU stress test utilizes ARM process @ 40% (performance freq 1Ghz)
      • 60MB input file executes in 50 seconds (1.2MB/sec)

use as you wish, in good health

1 Like

missing from initial post:
gomer@mercury:~/Downloads$ cksum clock.img.gz
1533175342 1047110484 clock.img.gz

wow… what an oversight!

user: debian
password: ILI9341

user: root
password: ILI9341

message of the day on debian login has instructions for EULA agreement, basically – sudo touch /root/Iaggree…

good luck

Hey Gomer,

This project sounds like a great way for a beginner to get some exposure to PRU programming. I am thinking about giving it a look-see. Does your image come with the source code?


this is as intended, as long as you are not too particular about (not using) remoteproc (eww).

all source code included, including the warts, but not the history.

all parts of the project can be rebuilt from source with matching cksums on executables.

image would PROBABLY need at least a 16GB microSD card if using etcher to create it due to this issue: eMMC to bootable SD

good luck

Hi Gomer,

Any chance we can get a higher res image of the internals? I am hoping to see how you connected the ILI9341 to the BBB.

Is it just the 4 SPI wires, BBB +3.3V to ILI9341 VCC and BBB Gnd to ILI9341 Gnd?


image? you mean picture? The pic provided from Amazon review is misleading, don’t use that. It was an earlier implementation.

how could this description from earlier post be clearer? it is from the actual software (gpio_code.asm). Its’ purpose is to provide symbolic substitution specific to the app (MOSI_HI) to the symbolic substitution in pru.h (pru.h is application agnostic).

is it clearer if I instead specify:
P9_25 ---- sclk
P9_29 ----- mosi
P9_28 — SS/CS
P9_27 ---- DC
P9_31 ----- reset

I didn’t think that was necessary, but am happy to provide it…

If that wasn’t clear, it probably also wasn’t clear that enough of the SPI protocol has been coded into PRU0 to drive the ILI9341 device. (not claiming anything close to complete compliance with SPI). This is a roll your own exercise in SPI communication for one specific device (ILI9341). that is why I specify which pins do what.

If I haven’t answered your question, please restate. Can provide pic if that is what you meant.

good luck

Hi Gomer,

That is much clearer. Thank you very much. Wasn’t necessary but, makes is easier on the new user.

My main concern however, was how you did the power supply to the display. I see the BBB can supply up to 250mA on the 3.3V outputs on the P9 header. Did you plug the ILI9341 right into the header? something like:

P9_01 ---- GND
P9_03 — VCC

The ILI9341 datasheet shows that it draws 100uA in standby but, i don’t see what it draws in full on display mode. Just trying to avoid damaging my new hardware before I get to run your awesome clock!!!


This is correct. without a breadboard, you’ll probably want to use two 3.3 sources (P9_03 and P9_04), one for VCC and one for led.

you’ll get plenty of warning if display is underpowered, it will dim on and off. Just be sure to use a 5v supply on the barrel jack, don’t try to power it from the usb connection. (or you can try, just to see it fail)…

I hope that you didn’t pay too much ($15) for one of these… it is good value. I can attest that I tortured these devices for years with misconfigurations, and bad practices without any damage.

good luck

Hey gomer,

Your clock has been running, well like a clock!!!

As of right now, 47 days uptime. I love it. I haven’t looked at the code yet. It just keeps on ticking away on my desk.

I have been spending most of my beagle time learning about SPI. The only SPI example that I have gotten to work out of the box is yours. I have a question for you: In your experience, does the Linux SPI kernel driver actually work or is it best to just use the PRU to bit bang SPI?

Examples I have tried that failed to work:

  1. Configure SPI for BeagleBone AI-64 - Embedded Systems
  2. Raspberry_Pi_3_demos/8x8_click.py at master · MikroElektronika/Raspberry_Pi_3_demos · GitHub
  3. exploringBB/spi595.c at version2 · derekmolloy/exploringBB · GitHub

Molloy’s 74HC595 example almost works, it seems like the latch timing is drifting in and out of sync. Haven’t had any time to put it on a scope.

Thanks for any tips.

If any other users have had success with SPI on the BBAI-64 and can shed some light on the subject, I would be grateful for any advice or links to code that works.


Thanks for the feedback, I wondered if you followed through with it.

I would have used the kernel driver, if I knew how… I’m really not experienced at SPI, the ILI9341 display and XPT2046 (touch) are the only devices that I have worked with… One of the things that I don’t know, is how to use the kernel driver for the ILI9341 since it needs a DC (data/command) line and a RESET line. Neither of these two control lines are part of SPI (as I understand it). If you have a device like the touch (XPT2046), then maybe the kernel driver would work fine, but I’ve never done it.

As I see it, there is canonical SPI, and then there are devices that SAY they are SPI, but have these extra control lines that are not part of SPI. All that said, gomer could be wrong about anything.

Using the PRU is the fun of it. I see of no other reason to be a BBB fanboy than for these coprocessors. There are plenty of SBC that do linux better. The combination of the ARM and PRU allow for concrete implementations of advanced concepts (like ring buffers). I wish that the BBAI (I have two) and other more current beaglebones did PRU implementation as well as the BBB.

There is nothing like a scope to see what is going on. SPI is a simple protocol, else it would not have gained the adoption that it has, BUT the devil is in the detail. For instance, the ILI9341 can be driven @20MHZ which is about as fast as the PRU can drive it, but the touch screen cannot (and never would need to) be driven that fast. It isn’t realistic to expect to develop any connection to a SPI device without detailed reading of the device spec sheet AND seeing it happen on a scope. This is whether you use a PRU OR use C. Molloy uses a scope in his descriptions, and he outlines how the timing has to be set in his C/C++ example (ADXL345). Using the kernel driver STILL needs a detailed knowledge of the device.

My C skills are meh at best, and I consider the instruction set of the PRU MUCH simpler than (expertly) using a C compiler. YMMV, it is just what gomer thinks.

I’m sure that the kernel driver is much more general on the specifics, and coded to work with lots of different SPI devices, while I implemented a subset of SPI specific to one device. This code that does SPI is on PRU0, and that is basically all that PRU0 does. Have a look, you might not find it difficult at all to follow.

good luck!

1 Like

I have never had an issue with SPI on the BBB
I did a project where I had 2 480x800x24 bit, LCD displays connected in parallel. Obviously both salve devices. Both displays showed the same thing. I think I was clocking them at 10MHz, the fastest clock they would support.
I was using SPI dev to write the data from a QT program which was generating the image. It was also for a clock, with the displays updating evéy minute. Maybe using the PRUs would have given a more seemless update to the display, but it worked well and was pretty easy to get going. Unless you were looking during the update you would notice the draw as most of the screen stayed the same.

1 Like

sounds interesting, do you remember manufacturer, model, etc … did they have any ‘extra’ connections like the one I described earlier?


Hi @gomer ,

Sorry I don’t have any info on the display. This was nearly 10 years ago, so I doubt you would still be able to get the displays in any case.

From what I remember, the lcd controller chip could either be driven directly by the lcd signals, or over spi.
The main interactive display was connected to the lcd signals on the BBB and if I remember correctly this also included an i2c connection for the capacitive touch screen. This was a large flexi-ribbon cable. Also on the module was a small flex-ribbon connection for spi. The spi displays were wired in parallel as they were never read. The lcd controller chip was unfortunately limited to about 2Mhz spi clock frequency.

IAW the discussion with @jkridner I am working on another image that will emphasize the ‘conduit’ subsection of this project at the expense of the example application that is emphasized in this post.

The intermediate stage for the ILI9341 conduit is very simple … everything is a rectangle, including one (1) individual pixel. 3 instructions define these rectangles in the format of a 32bit ‘word’:

  • 20rrggbb – the color palette for subsequent rectangles
  • 26ssseee – the start and end ‘columns’ of the rectangle (0-239)
  • 27ssseee – the start and end ‘pages’ of the rectangle (0-319)

sss <= eee, rr = red (0-255), gg = green (0-255), bb = blue (0-255). All values in hex obviously.

the column definition must precede the page definition for a given rectangle

those who have already implemented the existing image can get some of the features of the upcoming image by following these steps:

  • shut down the clock application
    • sudo svc -d /service/clock (svc is part of DJB cr.yp.to/daemontools … gratitude)
  • sudo su
  • echo ‘200F0F0F 260000A0 270000A0’ >> /var/local/pipeA
    • gray box should appear in corner of ILI9341 device
    • hardware geometry of device is portrait with pins on top:
      • coordinate 0,0 is leftmost column, uppermost page (row)
      • coordinate 239,319 is rightmost column, lowermost page
    • must be root due to permission restrictions of /var/local/pipeA
      • will be remedied with additional ‘ncat’ daemon in the upcoming image
        • will also permit the instructions to be read from the network
    • cat /home/debian/clock/stress.dat >> /var/local/pipeA
      • this is the stress test mentioned earlier for the clock app
    • restore clock application without rebooting
      • svc -u /service/clock

I hope that there will be some interested in building their own applications with text generators of their choice.

comments and questions welcome

wrong… I had not removed the flip_horizontal step which made everything upside down… s/top/bottom … with the pins lowermost, the rest is correct.

also … s/pipeA/pipeB/g … pipeA is input to flip_horizontal, pipeB is input to ILI9341 (c program) … the stress test will go 5x faster if redirected to pipeB rather than pipeA

the devil is in the detail