Author Topic: Beaglebone PRU coding  (Read 5439 times)

Offline charleskerr

  • Jr. Member
  • **
  • Join Date: Jun 2013
  • Location: Oak Hill, VA
  • Posts: 87
  • Kudos: 0
Beaglebone PRU coding
« on: June 09, 2014, 05:50:45 PM »
David,
  Didn't know if you ever looked, but I finally got around to coding the two programmable real time units on the Beaglebone.

As some may be aware, besides being a 1GHz ARM, with a host of I/O modules, it also has embedded in the silicon, two 200Mhz programmable real-time units (that most instructions take 1 cycle to execute). This was to allow one to code any needed I/O they needed.  The PRUs memory can be accessed by the ARM, and the PRUs even at a 12KByte shared memory between them.

Needless to say, finally go around to coding on the PRUs.  I got my WS2812, and a few other formats easily coded, with the ARM as my front end for any ethernet, or other type interfaces.  One isn't limited to SPI clocks, etc.  A tad more then the PI, but something you may want to look at it. 

I like it because I can get rid of dongles and pixel controllers (i use pixel splitters that are like a high pass pixel filter for the 2812)and just put out two streams of 2812 format (up to about 400 pixels per stream at 25ms).

Just though you may want to look at it as another option.
One is never too old to learn

Offline CaptainMurdoch

  • Administrator
  • *****
  • Join Date: Sep 2013
  • Location: Washington
  • Posts: 9,856
  • Kudos: 214
Re: Beaglebone PRU coding
« Reply #1 on: June 09, 2014, 09:00:15 PM »
We do want to look at having a FPP build for the BBB.  I actually ran FPP on a PogoPlug this past Christmas since I only had one Pi at the time and I was playing around with using that for Asterisk.  I can see us distributing at least a Pi and BBB image in the future.  In the FPP v0.3.0 release that should be out any day now, we are supporting one string of WS2801 pixels directly attached to the Pi and I'd like to add in support for other chips on the BBB as you describe once we get around to it.  I haven't picked up a BBB yet, but want to sometime this year so I can play around with it.
-
Chris

Offline charleskerr

  • Jr. Member
  • **
  • Join Date: Jun 2013
  • Location: Oak Hill, VA
  • Posts: 87
  • Kudos: 0
Re: Beaglebone PRU coding
« Reply #2 on: June 09, 2014, 09:04:47 PM »
Well, they aren't comparable if you plan on using the PRU on the BBB (as the PI doesn't have them). 
You can use the other peripherals  (SPI, I2C, etc) just like the PI.  But if you want realtime control (for instance, high speed bit banging of a special protocol without interruption) you will have to have a special BBB build.

Offline CaptainMurdoch

  • Administrator
  • *****
  • Join Date: Sep 2013
  • Location: Washington
  • Posts: 9,856
  • Kudos: 214
Re: Beaglebone PRU coding
« Reply #3 on: June 09, 2014, 09:08:06 PM »
Well, they aren't comparable if you plan on using the PRU on the BBB (as the PI doesn't have them). 
You can use the other peripherals  (SPI, I2C, etc) just like the PI.  But if you want realtime control (for instance, high speed bit banging of a special protocol without interruption) you will have to have a special BBB build.

We would have a special image for the BBB, with it's own compiled fpp* binaries of course.  The code would have compile-time options to indicate whether it was running on a Pi or BBB and the UI would know this as well so it could present the valid channel output options to the user, just as we auto-detect USB serial ports now and don't allow users to add a USB channel output if there are no USB serial devices present.

Offline charleskerr

  • Jr. Member
  • **
  • Join Date: Jun 2013
  • Location: Oak Hill, VA
  • Posts: 87
  • Kudos: 0
Re: Beaglebone PRU coding
« Reply #4 on: June 20, 2014, 02:47:25 PM »
This is some example PRU code that will generate a DMX or WS2812 output on one of the headers.  It can be loaded in either PRU (or both, and have two independent streams).

Just wrote the PRU memory buffer from the ARM, and set the ready flag and it will output.  Just a quick hack I did for testing purposes.  Since y'all are looking at the BBB and possible PRU, it may or may not be of help.
Enjoy.

Code: [Select]
.setcallreg r29.w0
.origin 0
.entrypoint START

#define AM33XX

// Refer to this mapping in the file - \prussdrv\include\pruss_intc_mapping.h
#define PRU0_PRU1_INTERRUPT     17
#define PRU1_PRU0_INTERRUPT     18
#define PRU0_ARM_INTERRUPT      19
#define PRU1_ARM_INTERRUPT      20
#define ARM_PRU0_INTERRUPT      21
#define ARM_PRU1_INTERRUPT      22

#define CONST_PRUDRAM   C24
#define CONST_SHAREDRAM C28
#define CONST_L3RAM     C30
#define CONST_DDR       C31

// Address for the Constant table Programmable Pointer Register 0(CTPPR_0)
#define CTBIR_0         0x22020
// Address for the Constant table Programmable Pointer Register 0(CTPPR_0)
#define CTBIR_1         0x22024

// Address for the Constant table Programmable Pointer Register 0(CTPPR_0)
#define CTPPR_0         0x22028
// Address for the Constant table Programmable Pointer Register 1(CTPPR_1)
#define CTPPR_1         0x2202C


// Registers we use for our code
#define SCRATCH0 r2
#define LOW_RATE r3
#define OUTPUT_COUNT r5
#define BAUD_DURATION r6
#define SLEEP_TIMER r7
#define DATA_READY r8
#define SLEEP_SCRATCH r14
#define OUTPUT_TYPE r9
#define INDEX_REG r10
#define BYTE_VALUE r11
#define PIXEL_TYPE r12
#define REG_OUTPUT r13


// Index we use
#include "MemOffset.h"

.macro SLEEPUS
.mparam us,inst,lab
    MOV SLEEP_TIMER, (us*100)-1-inst
lab:
    SUB SLEEP_TIMER, SLEEP_TIMER, 1
    QBNE lab, SLEEP_TIMER, 0
.endm

.macro SLEEPUSREG
.mparam us,inst,lab
MOV SLEEP_TIMER, us
lab:
    SUB SLEEP_TIMER, SLEEP_TIMER, 1
    QBNE lab, SLEEP_TIMER, 0
.endm

.macro SENDBIT
.mparam reg,bit,lab,lab2,lab3
        QBBC lab, BYTE_VALUE,bit
        SET r30, REG_OUTPUT
        QBA lab2
lab:
CLR r30,REG_OUTPUT

lab2:
SLEEPUSREG BAUD_DURATION,1,lab3
.endm

.macro SENDPBIT
.mparam reg,bit,lab,lab2,lab3,lab4
        QBBC lab, BYTE_VALUE,bit
        mov BAUD_DURATION,70
        mov LOW_RATE,60
        QBA lab2
lab:
        mov BAUD_DURATION, 35
        mov LOW_RATE,80
lab2:
        SET r30,REG_OUTPUT
        SLEEPUSREG BAUD_DURATION,1,lab3
        CLR R30,REG_OUTPUT
        SLEEPUSREG LOW_RATE,1,lab4
.endm

START:
//      Setup our memory
LBCO    r0, C4, 4, 4
CLR     r0, r0, 4         // Clear SYSCFG[STANDBY_INIT] to enable OCP master port
SBCO    r0, C4, 4, 4


// Get our fixed values
LBCO REG_OUTPUT, CONST_PRUDRAM, OUTPUT_BIT_REG,4
    LBCO OUTPUT_COUNT, CONST_PRUDRAM, OUTPUT_COUNT_INDEX, 4

    LBCO PIXEL_TYPE, CONST_PRUDRAM,OUTPUT_TYPE_INDEX,4
QBEQ DMXOUT, PIXEL_TYPE, DMX_OUTPUT
QBEQ SSDOUT, PIXEL_TYPE, SSD_OUTPUT
QBEQ WS2812OUT, PIXEL_TYPE, WS2812_OUTPUT
JMP START // None of the types we support, keep looking

DMXOUT:
MOV BAUD_DURATION, 400
JMP UARTOUT
SSDOUT:
MOV BAUD_DURATION, 100
UARTOUT:
// Set our output high
SET r30, REG_OUTPUT
// Move our offset for our data ready flag
UWAIT:
SLEEPUS 400,1,UWAITRDY
    LBCO DATA_READY, CONST_PRUDRAM, DATA_READY_INDEX, 4
QBEQ UWAIT, DATA_READY, 0     // If the flag is zero, loop

// It wasn't zero, we need to clear the flag
MOV DATA_READY,0       
SBCO DATA_READY, CONST_PRUDRAM, DATA_READY_INDEX, 4
// Flag is now cleared, we have to actually get our data
// First, send a break and 0


    CLR r30, REG_OUTPUT
    SLEEPUS 92,1,BREAK_LOW
    SET r30, REG_OUTPUT
    SLEEPUS 12,1,BREAK_HIGH
       
    MOV BYTE_VALUE,0
    CALL SNDBYTE
MOV SCRATCH0,OUTPUT_COUNT
MOV INDEX_REG,DATA_INDEX
DLOOP:
LBCO BYTE_VALUE, CONST_PRUDRAM, INDEX_REG,1
CALL SNDBYTE
ADD INDEX_REG,INDEX_REG,1
SUB SCRATCH0, SCRATCH0, 1
QBNE DLOOP, SCRATCH0, 0

    JMP UWAIT
   
WS2812OUT:
    CLR r30, REG_OUTPUT
   
PIXEL:
SLEEPUS 400,1,PWAITRDY
    LBCO DATA_READY, CONST_PRUDRAM, DATA_READY_INDEX, 4
QBEQ PIXEL, DATA_READY, 0     // If the flag is zero, loop
// It wasn't zero, we need to clear the flag
MOV DATA_READY,0       
SBCO DATA_READY, CONST_PRUDRAM, DATA_READY_INDEX, 4

MOV SCRATCH0,OUTPUT_COUNT
MOV INDEX_REG, DATA_INDEX-3
PLOOP:
ADD INDEX_REG, INDEX_REG, 3
LBCO BYTE_VALUE, CONST_PRUDRAM, INDEX_REG,3
SENDPBIT BYTE_VALUE,15,PBIT15,PBIT15SLEEP,PBIT15_SLEEP,PBIT_15_SLEEP
SENDPBIT BYTE_VALUE,14,PBIT14,PBIT14SLEEP,PBIT14_SLEEP,PBIT_14_SLEEP
SENDPBIT BYTE_VALUE,13,PBIT13,PBIT13SLEEP,PBIT13_SLEEP,PBIT_13_SLEEP
SENDPBIT BYTE_VALUE,12,PBIT12,PBIT12SLEEP,PBIT12_SLEEP,PBIT_12_SLEEP
SENDPBIT BYTE_VALUE,11,PBIT11,PBIT11SLEEP,PBIT11_SLEEP,PBIT_11_SLEEP
SENDPBIT BYTE_VALUE,10,PBIT10,PBIT10SLEEP,PBIT10_SLEEP,PBIT_10_SLEEP
SENDPBIT BYTE_VALUE,9,PBIT9,PBIT9SLEEP,PBIT9_SLEEP,PBIT_9_SLEEP
SENDPBIT BYTE_VALUE,8,PBIT8,PBIT8SLEEP,PBIT8_SLEEP,PBIT_8_SLEEP
SENDPBIT BYTE_VALUE,7,PBIT7,PBIT7SLEEP,PBIT7_SLEEP,PBIT_7_SLEEP
SENDPBIT BYTE_VALUE,6,PBIT6,PBIT6SLEEP,PBIT6_SLEEP,PBIT_6_SLEEP
SENDPBIT BYTE_VALUE,5,PBIT5,PBIT5SLEEP,PBIT5_SLEEP,PBIT_5_SLEEP
SENDPBIT BYTE_VALUE,4,PBIT4,PBIT4SLEEP,PBIT4_SLEEP,PBIT_4_SLEEP
SENDPBIT BYTE_VALUE,3,PBIT3,PBIT3SLEEP,PBIT3_SLEEP,PBIT_3_SLEEP
SENDPBIT BYTE_VALUE,2,PBIT2,PBIT2SLEEP,PBIT2_SLEEP,PBIT_2_SLEEP
SENDPBIT BYTE_VALUE,1,PBIT1,PBIT1SLEEP,PBIT1_SLEEP,PBIT_1_SLEEP
SENDPBIT BYTE_VALUE,0,PBIT0,PBIT0SLEEP,PBIT0_SLEEP,PBIT_0_SLEEP
SENDPBIT BYTE_VALUE,23,PBIT23,PBIT23SLEEP,PBIT23_SLEEP,PBIT_23_SLEEP
SENDPBIT BYTE_VALUE,22,PBIT22,PBIT22SLEEP,PBIT22_SLEEP,PBIT_22_SLEEP
SENDPBIT BYTE_VALUE,21,PBIT21,PBIT21SLEEP,PBIT21_SLEEP,PBIT_21_SLEEP
SENDPBIT BYTE_VALUE,20,PBIT20,PBIT20SLEEP,PBIT20_SLEEP,PBIT_20_SLEEP
SENDPBIT BYTE_VALUE,19,PBIT19,PBIT19SLEEP,PBIT19_SLEEP,PBIT_19_SLEEP
SENDPBIT BYTE_VALUE,18,PBIT18,PBIT18SLEEP,PBIT18_SLEEP,PBIT_18_SLEEP
SENDPBIT BYTE_VALUE,17,PBIT17,PBIT17SLEEP,PBIT17_SLEEP,PBIT_17_SLEEP
SENDPBIT BYTE_VALUE,16,PBIT16,PBIT16SLEEP,PBIT16_SLEEP,PBIT_16_SLEEP
SUB SCRATCH0, SCRATCH0, 1
QBNE PLOOP, SCRATCH0, 0

    //SLEEPUS 50,1,PIXEL_RESET
    JMP PIXEL

       
SNDBYTE:

    CLR r30, REG_OUTPUT
    SLEEPUSREG BAUD_DURATION,1,START_LOW
SENDBIT BYTE_VALUE,0,BIT0,BIT0SLEEP,BIT0_SLEEP
SENDBIT BYTE_VALUE,1,BIT1,BIT1SLEEP,BIT1_SLEEP
SENDBIT BYTE_VALUE,2,BIT2,BIT2SLEEP,BIT2_SLEEP
SENDBIT BYTE_VALUE,3,BIT3,BIT3SLEEP,BIT3_SLEEP
SENDBIT BYTE_VALUE,4,BIT4,BIT4SLEEP,BIT4_SLEEP
SENDBIT BYTE_VALUE,5,BIT5,BIT5SLEEP,BIT5_SLEEP
SENDBIT BYTE_VALUE,6,BIT6,BIT6SLEEP,BIT6_SLEEP
SENDBIT BYTE_VALUE,7,BIT7,BIT7SLEEP,BIT7_SLEEP
SET r30, REG_OUTPUT
SLEEPUSREG BAUD_DURATION,1,STOP1_HIGH
SLEEPUSREG BAUD_DURATION,1,STOP2_HIGH

    RET
       
       
       

EXIT:
        MOV R31.b0, PRU0_ARM_INTERRUPT+16
        HALT

Offline CaptainMurdoch

  • Administrator
  • *****
  • Join Date: Sep 2013
  • Location: Washington
  • Posts: 9,856
  • Kudos: 214
Re: Beaglebone PRU coding
« Reply #5 on: June 20, 2014, 03:38:59 PM »
Thanks, I bookmarked it for later reference.

Offline charleskerr

  • Jr. Member
  • **
  • Join Date: Jun 2013
  • Location: Oak Hill, VA
  • Posts: 87
  • Kudos: 0
Re: Beaglebone PRU coding
« Reply #6 on: June 21, 2014, 07:17:03 AM »
For those looking at the Beaglebone Black, I suggest you check out the audio cape.  The schematic is freely available, so if you want to build your own cape (and add other electoncs like a few buffers to connect light strings to).

Anyway, the audio cape is very easy to get up and running.  Unfortunately, it starts to raise the price of the BBB, given the recent price increase for RecC of the BBB anyway.

55 dollars for the BBB and 29 for the cape.  On the other hand, I find the functionality and potential far greater then the PI, so for me worth the price.  But I like to develop on it.  For just show purposes, and using pixel controllers instead of having the BBB generate the ws2812, PI is probably more economical at 35.

 

Back to top