PRU example: Hello World loaded by Code Composer Studio


Make a hello world program that can be loaded via JTAG to be run and debugged.

A hello world program has no useful purpose as an application program except for demonstrating that printf-like output is captured and made available within Code Composer Studio. This is an essential debug technique and that is the reason for this example.

The PRU does not have a direct output which can capture the output. Code Composer offers an alternative in the form of CIO (Console IO). Using CIO, a program can make a call to fputs("message", stdout) and Code Composer can grab the message and display it in a Console View within Code Composer.

This example will go through the steps needed to enable and make use of the CIO technique.


Start Code Composer in a new workspace.

Create a new CCS project

  • Change "Generic Arm7 Device" to AM62
  • Change from the "Cortex A[Arm]" tab to the "PRU" tab
  • Enter a name for the project. e.g. pru_hello
  • Change from "Empty Project (with main.c)" to "Empty Project".
  • Click Finish

Add source file

  • Add source file
    • In Project Explorer, select pru_hello project->right-mouse->Add Files...
    • Browse to directory in ti-processor-sdk:
    • Pick the main.c file. Copy Files to your workspace
  • Change CFGFG0 to cfgfg0_reg
    • The original code is not for the AM62x and the register name has changed.
  • We will not be toggling leds. This example is being used to demonstrate the useful "printf" debugging technique.
  • Adjust the cycles per second
    • Add/change the following lines:
       * main.c
      // CYCLES_PER_SECOND will be same as speed of the processor
      #define CYCLES_PER_SECOND (250000000)
      #define CYCLES_PER_MS (CYCLES_PER_SECOND/1000)
              __delay_cycles(500*CYCLES_PER_MS); // half-second delay

Add "printf" code

  • The usual printf() function has a large memory footprint and is too large for use on a PRU. Alternatives exist in the form of fputs().
  • Add the following code
    • Include files
      #include <stdio.h>
      #include <stdlib.h>
    • Initial hello world message.
          fputs ("Hello World from a PRU\r\n", stdout);
    • Periodic hello world message
          volatile uint32_t gpo;
          int counter = 0;
          while (1) {
              if ((counter % 10) == 0) {
                  char buff[20];
                  ltoa (counter/10, buff, 10);
                  fputs(buff, stdout);
                  fputs(": another hello from the PRU\r\n", stdout);
  • Complete program should look like this:
    #include <stdint.h>
    #include <pru_cfg.h>
    #include <stdio.h>
    #include <stdlib.h>
    volatile register uint32_t __R30;
     * main.c
    // CYCLES_PER_SECOND will be same as speed of the processor
    #define CYCLES_PER_SECOND (250000000)
    int main(void)
        volatile uint32_t gpo;
        int counter = 0;
        /* GPI Mode 0, GPO Mode 0 */
        CT_CFG.gpcfg0_reg = 0;
        /* Clear GPO pins */
        gpo = 0x0000;
        fputs ("Hello World from a PRU\r\n", stdout);
        while (1) {
            if ((counter % 10) == 0) {
                char buff[20];
                ltoa (counter/10, buff, 10);
                fputs(buff, stdout);
                fputs(": another hello from the PRU\r\n", stdout);
            gpo = __R30;
            gpo ^= 0xF;
            __R30 = gpo;
            __delay_cycles(500*CYCLES_PER_MS); // half-second delay

Fix Compiler Include Paths and Heap size

  • Include paths
    • In Project Explorer, select pru_hello project->right-mouse->Properties->PRU Compiler->Include Options
      • remove ${CCS_BASE_ROOT}/pru/include
        • Select entry. Click on the icon with the red x.
      • add ~/ti-processor-sdk-linux-am62xx-evm- using the add button and then browse to the directory
  • Heap size
    • The default heap is 256 bytes. If the heap is not large enough, the fputs() will just silently fail and you will not see any output in Code Composer.
      • You can turn off buffering using setvbuf() or you can make the heap larger.
    • In the project Properties->PRU Linker->Basic Options
      • Change the heapsize to 1024
      • Change the stack size to 1024
  • Click on Apply and Close

Add .cmd file

  • Project->Add Files...
    • Browse to
    • Select the AM62x_PRU0.cmd file, Copy to your workspace.
  • In general, a.cmd file for PRU0 will be different from a .cmd file for PRU1. For this simple example, the same .cmd file could be used on either PRU processor. For your own applications, you may wish to find an example close to yours for the appropriate PRU and use the .cmd file for that example as a starting point.

Build the program

  • Project->Build Project

Create a New target configuration file

  • This will need patches from CCS_am62x_target_configuration_fix
  • File->New->Target Configuration File
    • Use shared location. This will create a target configuration file in a common location that can be used in other examples even from other workspaces.
    • change name to am62x.ccxml
    • Finish
    • Change Connection to your type of emulator probe.
    • Pick AM62 as board or device
    • Use Advanced Tab to bypass the ARM/Linux processors. This avoids accidentally connecting to them or stopping them.
      • Select CortexA53_0, click the Bypass box
      • Select CortexA53_1, click the Bypass box
      • Select CortexA53_2, click the Bypass box
      • Select CortexA53_3, click the Bypass box
      • Note: bypassing the above processors helps to avoid accidents. You can also bypass other processors to help reduce clutter in the Debug View.
    • Click on Save

Create a Debug Configuration

  • Run->Debug Configurations...
    • Select Code Composer Studio - Device Debugging->right-mouse->New Configuration
      • Name. Change from New_configuration to same name as the Target Configuration: am62x.ccxml
      • Main tab
        • Select target configuration from File System...
        • Uncheck Use same console for CIO of all CPUs.
          • If the same console is used for all CPUs, each line may have a string identifying the processor producing the text. This can be annoying. Using separate views avoids this clutter. If you are only debugging one CPU, it doesn't really matter.
      • Target tab
        • Change Device to PRU_ICSS_PRU_0, enable CIO function
        • Change Device to PRU_ICSS_PRU_1, enable CIO function
      • Apply
      • Close

Start the target connection

  • Open the Target Configurations View
    • Window->Show View->Target Configurations
  • Select am62x.ccxml (drill into User Defined)
  • right-mouse->Launch Selected Configuration
    • switches to Debug Perspective (different set of views)
    • takes a while
  • In debug view
    • Select PRU_0, right-mouse->Connect Target
    • Run->Reset->CPU Reset
    • Run->Load->Load Program
      • Use Browse Project to select pru_hello.out
      • OK
    • Stopped at start of main()
    • Put breakpoint at start of while loop.
    • Run->Resume
    • Should see a console for am62x.ccxml:CIO with Hello World from a PRU message
    • Remove breakpoint
    • Run->Resume
    • Should see additional messages, about 1 every 5 seconds.
    • Terminate debug session


  • Created a project for PRU_0.
    • The .cmd file for PRU_1 would be slightly different but for this simple program is not important.
  • Started a target launch to get the list of processors available through the JTAG.
    • The Target configuration bypassed the ARM/Linux processors to avoid accidents and reduce clutter
  • Connected to the PRU_0 target
  • Reset the cpu. This must be done before loading the program.
  • Loaded the program.
  • Set a breakpoint and ran the program.
  • Saw output on the Console view in Code Composer
  • Removed the breakpoint, resumed the program and saw additional hello messages.

Go to top
Add picture from clipboard (Maximum size: 1 GB)