Skip to content
Friedemann Stoffregen edited this page Aug 7, 2018 · 2 revisions

PRU (programmable real-time unit)

General Info

The BeagleBone has two PRUs which can be run seperated from the CPUs. Each PRU is capable of using

Using the PRU

Installing the Compiler

Just download the PRU Code Generation Tools and install them by executing the downloaded .sh-file.

If you want to use our bundled generation tools, use the following commands to set up the toolchain:

echo "export PRU_CGT=/usr/share/ti/cgt-pru" >> /~/.bashrc
export PRU_CGT=/usr/share/ti/cgt-pru
cp -r ./pru/demos/pru-software-support-package/include $PRU_CGT/includeSupportPackage
cp ./pru/demos/pru-software-support-package/lib/rpmsg_lib.lib $PRU_CGT/lib

Compiling the Firmware

To compile the firmware, just run this command:

cd pru/src
make all

This will compile the firmwares for both PRUs, copy them to the correct destination (/lib/firmware) and (re)start the firmware.

(Re)Starting the firmware

If you want to start the firmware, the firmware shall be stopped beforehand:

rmmod pru_rproc -f

Now you can start the firmware by running:

modprobe pru_rproc

Communicate with Linux process

The ADCManager-process and the PRU-firmware are communicating via a RPMsg. An detailed explanation how it works can be found here.

PRU - ADC communication via SPI

The ADC "ADC5592" has an SPI-Interface for communication. Therefor, the SPI-protocoll had to be implemented.

Communicate via SPI

The implementation of the SPI-Communication can be found in the file pru/src/pru1adc.c:

short sendSPICommand(char command) {
    short data = 0x00;          //  Initialize data.
    for (int i = 7; i >= 0; i--) {
        int bit = (command & (1 << i)) >> i;

        if (bit) {
            __R30 = __R30 | (bit << 12);
        } else {
            __R30 = __R30 & 0xEFFF;
        }

        __delay_cycles(PULSEWIDTH);
        CLK_LOW;
        __delay_cycles(PULSEWIDTH); //  Delay to allow settling.
        CLK_HIGH;
        __delay_cycles(PULSEWIDTH);
        __delay_cycles(PULSEWIDTH);
        __delay_cycles(PULSEWIDTH);
        data = data << 1;           // Shift left; insert 0 at lsb.
        if (__R31 & (1 << 8)) //  Probe MISO data from ADC.
            data = data | 1;
        else
            data = data & 0xFFFE;
    }
    return data;
}

Within the for-loop, every bit of the to-be-transmitted character is send seperately.

The most interesting part might be this line: __R30 = __R30 | (bit << 12);. The variable __R30represents a register of output pins. The bit is shifted by 12 because the we use the pin P8.21 as the SPI-MOSI pin, which is configured via the Overlay as pr1_pru1_pru_r30_12 (see also).

Within the for-loop, we also read the the value from the __R31register. __R31 represents a register of input pins. We use P8.27 as SPI-MISO. It is configured as pr1_pru1_pru_r31_8and therefor the bit to read is the 8th bit of __R31.

Initializing / Configuring the ADC

The ADC is initialized using the function initADC():

void initADC() {
    sendWord(0x7D, 0xAC); // Reset Chip (Table 44) or: sendWord(0x05, 0xAC); //
    sendWord(0x5A, 0x00); // Internal reference always on (Table 42)
    sendWord(0x18, 0x20); // set ADC input to 2xV_ref (5V) (Table 18)
    sendWord(0x20, 0x0C); // configure port 2, 3 as ADC
}

The referenced tables can be found in the ADC Datasheets.

Reading ADC-Values

After the PRU received the command to start reading the values from the ADCManager, the PRU collects 16 values for each ADC-Channel, calculates its mean-value and sends the result back to the ADCManager.

Hint: The lines for adc0, adc1, adc4 and adc5 are commented out, because they are currently not used. Uncomment them if needed!