The following sections in this guide will introduce you to device tree changes, firmware development, and the loading procedure so that you can get started developing on the PRUICSS on the phyCORE-AM57x Development Kit.

Requirements

  • Must have completed the Build the BSP guide. This requirement must be met in order to follow the instructions below to modify the kernel. 
  • PHYTEC Expansion Board (PCM-957) will be needed to wire up an LED circuit to the Expansion Connector pin 25C

What is PRUICSS? 

PRUICSS stands for Programmable Real-time Unit and Industrial Communication Subsystem. It's essentially a slave core complex that the host processors (these are the Cortex-A15s on the phyCORE-AM57x running Linux) can use to offload various tasks. For example, you can emulate more UARTs using the PRUs than the host processor has physically available. You could also implement more high speed and real-time communications protocols. The PRUICSS is a dual-core complex (PRU0 and PRU1) and since there are 2x PRUICSS on the standard phyCORE-AM57x SOM kit variant this means there are actually 4x PRUs available.

How is a PRU programmed? 

There are a couple of options going about this for development. You could hook up to the phyCORE-AM57x via JTAG and load code directly into the core's instruction RAM but this is outside the scope of this article. The method that will be explored in this guide will involve cross-compiling our PRU code on a Host development machine, transferring our executable to the phyCORE-AM57x which is already booted and running Linux, and then leveraging the remoteproc framework to load the code into the PRU from Linux.

Remoteproc is a kernel driver that allows the ARM host processor(s) to load firmware into slave cores such as the IPUs, DSPs, and PRUs. It provides a way to start these cores, stop these cores, and to configure resources that the cores might need during their execution (such as configuring interrupt controllers or setting up space in memory to pass messages between the cores).

Wiring Up an LED

You will need to populate an LED and a 100 Ohm resistor to the PCM-957 Expansion Board according to the schematic below. Do this with the PCM-957 Expansion Board disconnected from the phyCORE-AM57x development kit.


Configuring the Device Tree

The PRUICSS is disabled by default in the Linux BSP PD20.1.2 and a kernel modification will be required to both enable the PRUICSS and to configure a processor pin of the AM5728 SoC to operate as a PRU general-purpose output. For more information please see the AM57x Technical Reference Manual.

This guide assumes you have completed the BSP Development Guide and have successfully built the arago-core-tisdk-bundle build target. When building the BSP for the first time all the source repositories are pulled locally to the development machine. We will use these to modify the kernel before rebuilding it.

  • Once you have completed the steps outlined in the BSP Development, navigate to the local kernel repository: 

    Host (Ubuntu)

    cd $BUILDDIR/arago-tmp-external-arm-toolchain/work/am57xx_phycore_kit-linux-gnueabi/linux-phytec-ti/4.19.79+git_v4.19.79-phy3-r7a/git/
    CODE
  • Using your preferred Text Editor, modify arch/arm/boot/dts/am5728-phycore-kit-41300111i.dts by adding the following code excerpt to the end of the file. If this is not your SOM configuration then contact PHYTEC Support if you need help adapting these steps.

    Try the Vim Text Editor!

    Host (Ubuntu)

    vim arch/arm/boot/dts/am5728-phycore-kit-41300111i.dts
    CODE

    The Vim Text Editor begins in "Command Mode" and you must first hit the 'i' key in order to enter "Insert Mode". Using the arrow keys to navigate, make the necessary changes and then hit ESC to go back to "Command mode". Now enter ":wq" to write the file and quit.


    Pro Tip: Use the right click on your mouse to paste! This will only work if you are in "Insert Mode" first.

    arch/arm/boot/dts/am5728-phycore-kit-41300111i.dts

    # ADD ME TO THE END OF THE FILE
    &dra7_pmx_core {
            pru2_gp_pins: pru2_gp_pins {
                pinctrl-single,pins=<
                    DRA7XX_CORE_IOPAD(0x35D8, PIN_OUTPUT | MUX_MODE13)     /* (E11) vout1_vsync.pr2_pru1_gpo17 */
                >;
            };
    };
     
    &pruss_soc_bus1 {
        status="okay";
    };
     
    &pruss_soc_bus2 {
        status="okay";
    };
     
    &pruss2 {
        pinctrl-names="default";
        pinctrl-0=<&pru2_gp_pins>;
        status="okay";
    };
    CODE

    In this code, we are multiplexing a processor pin to operate in a general-purpose output mode and enabling both PRUICSS 1 and 2! The pin that is enabled in this code corresponds to the signal X_GPIO4_23 in the phyCORE-AM57x schematic and this is routed out to the pin 25C on the Carrier Board Expansion Connector. Please see the Schematics section of the Hardware Development page for more information. This pin was selected since it was not being used for any other existing subsystems on the phyCORE-AM57x development kit.

  • Once you have saved and closed the file arch/arm/boot/dts/am5728-phycore-kit-41300111i.dts we can then recompile the kernel. 

    You'll have to use the same terminal session from when you ran through the BSP Development in order to have your environment already sourced. 

    Host (Ubuntu)

    bitbake linux-phytec-ti -f -c compile && bitbake linux-phytec-ti
    CODE

    This will force the bitbake build system to recompile the kernel and redeploy it.

  • Now the newly generated device tree blob, $BUILDDIR/arago-tmp-external-arm-toolchain/deploy/images/am57xx-phycore-kit/am5728-phycore-kit-41300111i.dtb, will reflect the changes we made. Transfer this file to your bootable SD Card using the following commands (you will need your bootable SD Card connected to your Host Development Machine in order for this command to work):  

    Host (Ubuntu)

    sudo cp $BUILDDIR/arago-tmp-external-arm-toolchain/deploy/images/am57xx-phycore-kit/am5728-phycore-kit-41300111i.dtb /media/<user>/rootfs/boot/pru-blink.dtb && sync
    CODE

    Leave your SD Card connected to your Host Machine because you will need to transfer another file.

Writing the PRU Firmware

Now that we have successfully enabled the PRU cores available on the phyCORE-AM57x, and muxed a GPO for one of them, we can now write some firmware to run on the PRU core that toggles the LED.

What is firmware?

Firmware is low-level software that provides control over hardware systems. It's code that we are going to give to a PRU before we tell that PRU to "start". In order to begin developing firmware for the PRU cores, PHYTEC recommends first installing the PSDK. The PSDK is built automatically when building the arago-core-tisdk-bundle target and includes example applications that can serve as a starting point for your development. Since this guide requires a device tree modification and therefore assumes that you have completed the BSP Development, you should be able to find the PSDK already built in your local filesystem at $BUILDDIR/arago-tmp-external-arm-toolchain/deploy/images/am57xx-phycore-kit/processor-sdk-linux-bundle-am57xx-phycore-kit.tar.xz

Setup the PSDK

  • Install these common dependencies to your Host development machine: 

    Host (Ubuntu)

    sudo apt-get update
    sudo apt-get install build-essential autoconf automake bison flex libssl-dev bc u-boot-tools
    CODE
  • Create a directory to install the PSDK. This guide will use ~/AM5-PSDK but you can change this to something (just make sure you have permissions in that location). 

    Host (Ubuntu)

    mkdir ~/AM5-PSDK
    CODE
  • Unpack the PSDK: 

    Host (Ubuntu)

    tar -Jxf processor-sdk-linux-bundle-am57xx-phycore-kit.tar.xz -C ~/AM5-PSDK
    cd ~/AM5-PSDK
    export AM5-PSDK=`pwd`
    CODE
  • Run the PSDK installer: 

    Host (Ubuntu)

    ./sdk-install.sh
    CODE

Modifying the Example Application PRU_Halt

  • Now that the PSDK is installed, you have access to some PRU firmware examples and the toolchain to build them. Let's open up the AM572x PRU demo, PRU_Halt, and modify it to toggle our GPO. 

    Host (Ubuntu)

    vim example-applications/pru-icss-5.6.0/examples/am572x/PRU_Halt/main.c
    CODE

    Let's take a moment to look at some things in the PRU_Halt demo before we make changes.

    • Every PRU project has to incorporate a resource table, even if it is empty. This specifies the system resources that the PRUs will need during their program execution and might include things such as interrupt mappings and shared memory buffers for passing messages with the Cortex running Linux. These shared memory buffers are similarly defined for the Cortex-A15s in the Linux Device Tree and will have to match in order for these resources to be used properly. 
    • Note that the PRU_Halt project just suspends the core that runs it, as its name suggests. This is more or less the perfect clean slate project to begin writing firmware.

    The PRU_Halt demo is an especially great starting point for our blink example since we don't need any fancy messaging schemes. Other than loading the PRU core with the instructions needed for blinking our LED, and starting/stopping, there won't be any Interprocessor communication going on.

  • Modify the main.c file to reflect the following: 

    The Vim Text Editor begins in "Command Mode" and you must first hit the 'i' key in order to enter "Insert Mode". Using the arrow keys to navigate, make the necessary changes and then hit ESC to go back to "Command mode". Now enter ":wq" to write the file and quit.


    Pro Tip: Use the right click on your mouse to paste! This will only work if you are in "Insert Mode" first.

    example-applications/pru-icss-5.6.0/examples/am572x/PRU_Halt/main.c

    #include <stdint.h>
    #include "resource_table_empty.h"
    
    //+++++++++Blink Code+++++++++++++++
    #include <pru_cfg.h>
    volatile register uint32_t __R30;
    
    int main(void)
    {
            //  __halt();
    
    //+++++++++Blink Code+++++++++++++++
            volatile uint32_t gpo;
    
            /* GPO Mode Direct Output */
            CT_CFG.GPCFG1_bit.PRU1_GPO_MODE = 0;
    
            /* Clear SYSCFG[STANDBY_INIT] to enable OCP master port */
            CT_CFG.SYSCFG_bit.STANDBY_INIT = 0;
    
            /* No-idle Mode*/
            CT_CFG.SYSCFG_bit.IDLE_MODE = 2;
    
            /* No-standby Mode */
            CT_CFG.SYSCFG_bit.STANDBY_MODE = 1;
    
            /* Divisor Value 1  */
            CT_CFG.GPCFG1_bit.PRU1_GPO_DIV0 = 0;
            CT_CFG.GPCFG1_bit.PRU1_GPO_DIV1 = 0;
    
            /* GP Mux Sel Reset */
            CT_CFG.GPCFG1_bit.PR1_PRU1_GP_MUX_SEL = 0;
    
            gpo = (1 << 17);
    
            /* Toggle Outputs */
            while (1) {
                    __R30 ^= gpo;
                    __delay_cycles(100000000);
            }
    }
    CODE

    The register __R30 determines the states of the output pins for a given PRU (__R31 is similarly used to read the input states). We are just toggling the bit that corresponds with prX_pruX_gpo17. In order for this code to actually toggle pr2_pru1_gpo17 we will have to ensure that this firmware is loaded to the correct PRU core. 

  • Once you've saved and closed the file, clean and re-build all the PRU demos with the following commands: 

    Host (Ubuntu)

    make pru-icss_clean
    make pru-icss
    CODE
  • If no mistakes were made you should have generated an executable at $AM5-PSDK/example-applications/pru-icss-5.6.0/examples/am572x/PRU_Halt/gen/PRU_Halt.out and we will need to copy this to the bootable SD Card. PRU firmware has to be located in /lib/firmware inorder for the remoteproc driver to find it properly.

    Host (Ubuntu)

    sudo cp $AM5-PSDK/example-applications/pru-icss-5.6.0/examples/am572x/PRU_Halt/gen/PRU_Halt.out /media/<user>/rootfs/lib/firmware/pru-blink.out && sync 
    CODE

    Check out the guide Copying Files to the Device for more options on transferring files to and from the target hardware during development. This guide just uses the bootable SD Card to accomplish this and while this is a proven method, it is slow and cumbersome. Setting up an NFS Server is highly recommend for long term development but this is not required.

Running the Firmware

  • Safely eject the SD Card from your Host Development Machine.
  • Connect both the bootable SD Card and the PCM-957 Expansion Board to the phyCORE-AM57x development kit.
  • Power on the kit and interrupt the boot process by pressing a key when prompted to stop in the U-Boot console.
  • Enter the following commands to manually specify our new device tree as the one to be used when bringing up the kernel: 

    Target (U-Boot)

    setenv override_board 1
    setenv findfdt 'setenv fdtfile pru-blink.dtb'
    saveenv
    boot
    CODE
  • Once booted into Linux, let's take a moment to check out the PRU cores: 

    Target (Linux)

    cat /sys/kernel/debug/remoteproc/remoteproc*/name
    cat /sys/kernel/debug/remoteproc/remoteproc7/name
    cat /sys/class//remoteproc/remoteproc7/state
    CODE

    We have four PRU cores available to us. Since the signal we chose to bring out, pr2_pru1_gpo17, is a general-purpose output for the PRUICSS2 PRU1, we will have to make sure we load our firmware into the correct core. PRUICSS2 PRU1 corresponds with 4b2b8000.pru.

  • Load the PRU with the firmware and signal it to start: 

    Host (Ubuntu)

    echo 'pru-blink.out' > /sys/class/remoteproc/remoteproc7/firmware
    echo 'start' > /sys/class/remoteproc/remoteproc7/state
    CODE

    Assuming the circuit, the device tree and firmware were setup correctly, AND the firmware was loaded to the correct PRU (PRUICSS2 PRU1) then the LED should be blinking!