Using GPIO pins and scratchpad of the PRU with C

Hi,

I am building an application based on the PRU_Hardware_UART example of the “Programmable Real-time Unit (PRU) Software Support Package release 4.0” from TI. And I am using the TI C compiler v2.1.2. The UART works great.

I am able to use the GPIO pins by declaring “volatile register uint32_t __R30;” in my C source code. Then I can simply set the value of the variable “__R30” and the register value and the output pins reflect this value. This seems a bit like magic to me, how does the compiler know that __R30 is supposed to be the GPIO register? There doesn’t seem to be macro expansion or similar going on.

Is there a similar declaration I can use for the scratchpad registers and then access them from PRU0 as well as PRU1?

Thanks a lot,

Lucas

There is a manual for the C compiler and the assembler:

http://processors.wiki.ti.com/index.php/PRU-ICSS

The links are on the right side of the page.

Some of the PRU hardware specific registers are accessed via a large union in a header file. It uses structs with “bit fields” so you can easily access individual bits in the register.
Look for a header file called pru_cfg.h. But specifically to your question, I’m still trying to figure out how the PRU input and output registers R30 and R31 are done in C, as I
don’t see those called out in the header file (in information overload at this point!).

Regarding the scratchpad, I believe it can’t be accessed via C. However, you can embed assembler codes into C source code.
If you go here:

https://training.ti.com/sitara-processors-building-blocks-for-pru-development-summary

Download the firmware development slides and look at page 8.

Regards,
Greg

Ah, thank you. These are excellent resources. I think I found the answer to my first question in the PRU Optimizing C/C++ Compiler v2.1 User Guide:

Section: 5.7.2 Global Register Variables

The C/C++ compiler extends the C language by adding a special convention to the register storage class specifier to allow the allocation of global registers. This special global declaration has the form: register type regid The regid parameter can be __R30 and __R31. The identifiers _ _R30 and _ _R31 are each bound to their corresponding register R30 and R31, respectively. These are control registers and should always be declared as volatile.

I am still a bit uncertain about the scratch pad. I have a value stored in a C variable, but how could I copy that value into inline assembler - so that I can write it to the scratch pad?

On Tue, 9 Feb 2016 02:56:49 -0800 (PST), lucas
<lucas.gerads@gmail.com> declaimed the
following:

  Take into account that I've not done any such low-level programming,
and am just masticating various documents...

I am able to use the GPIO pins by declaring "volatile register uint32_t
__R30;" in my C source code. Then I can simply set the value of the
variable "__R30" and the register value and the output pins reflect this
value. This seems a bit like magic to me, how does the compiler know that
__R30 is supposed to be the GPIO register? There doesn't seem to be macro
expansion or similar going on.

  I would presume that the __R30 notation is directly handled as a
hardware PRU register; no translation/macro needed. It is not a stack/heap
allocated variable that could move around between compilations

http://processors.wiki.ti.com/index.php/Programmable_Realtime_Unit#General_Purpose_Outputs_.28R30.29

Is there a similar declaration I can use for the scratchpad registers and
then access them from PRU0 as well as PRU1?

  Closest mention to Scratchpad (at that site) is

http://processors.wiki.ti.com/index.php/Programmable_Realtime_Unit#PRU_Constant_Table_Block_Index_Register_.280x0020.29

from which I'd interpret that Scratchpad is not a bank of processor
registers, but rather "external" RAM; likely accessed via a pointer.

OK, I see they extended the C language for R30 and R31!

I haven’t found any good examples were C and assembler are mixed. I have seen statements which say there are multiple ways to accomplish it.
It looks like the simplest is to inject assembler code directly into the C code. See page 76. There is also a section on “Intrinsics” on page 89. I think that might be what you are looking for.

Greg, thanks a bunch. It seems like page 89 of the user guide does the trick! I am not yet sure how to debug both PRUs at the same time, but I can write to the scratch pad from one PRU and read it back.

example code:

void testScratchPad(){
static unsigned int test = 0;
test++;
unsigned int* testPtr = &test;
__xout(10, // Scratch pad bank 0
0, // base register 0
0, // remapping false
testPtr // object
);
unsigned int test2;
unsigned int* test2Ptr = &test2;
__xin(10, 0, 0, test2Ptr); // value is now in test2
}

So maybe this works :slight_smile: