PRU_ICSS vs PRU_ICSSG wrt GPIO and bi-directional communications

I have an extremely time-sensitive application that is perfect for a PRU…communicating on a memory bus. However it requires bi-directional communication. And it was my understanding when I researched this years ago with the PRU_ICSS that to do this correctly, each pin would have to be doubled…one for input, one for output. And because GPOs can’t be “disconnected”, an external device would be required to sever the GPO pin from the actual bus during times when the PRU isn’t transmitting on the bus.

The TI TXS0108E 8-Bit Bi-directional, Level-Shifting, Voltage Translator seemed perfect for this task since it can both level-shift between a 3.3v (BB) and 5v (the actual bus) domain as well as connect/sever the two via an enable-pin.
txs0108e

The downside is this takes up double the number of pins necessary to communicate on the bus. And given this bus is a parallel bus, there’s 8 lines that require bi-directional behavior (a number of other control lines also need to be monitored, but don’t require bi-directional control). Fortunately there’s enough pins on the BB headers to accommodate this. But this limits the other peripherals that can also be used since so many pins are consumed.

When I started reviewing the BBAI-64 and realized it has the upgraded PRU_ICSSG, I decided to educate myself on the differences. Document searches led to TI training videos…one suggests that when a PRU is configured for GPO output, it now has the ability to put the GPO into bi-directional mode and control the direction via the PRU’s DIGIO_DATA_OUT_EN register.
Youtube>Programmable real-time unit for gigabit industrial communication subsystem: cores, I/O & peripherals
The link should jump you right to ~3:30 (mm:ss) where this topic is discussed.

Is my interpretation correct that when using a PRU_ICSSG, GPIO pins intended for bi-directional COMs no longer need to consume 2 pins, and instead each GPO mapped to the PRU can be changed from output to input, on the fly, depending on whether the PRU intends to transmit or receive?

That certainly seems like what they are saying. But I thought maybe I better ask the question just to make sure there isn’t more to the story and possibly get some references to where this is discussed, in more detail, in documentation.

More importantly, has anybody actually done something similar to this with a PRU_ICSSG and thus can affirm that this is, indeed, the case that GPOs can now be bi-directional?

1 Like

Yes, PRU_ICSSG (as well as PRU_ICSS) can provide floating (bi-directional) GPIO by switching the DIGIO_DATA_OUT_EN register. This register is in GPIO-SS and doesn’t work on fast (direct) PRU-GPIO. The line has to get controlled by the GPIO-SS (via L3 bus), which means a latency of at least 3 cycles (depending on the L3 bus load).

Find an example in github.com/dtjf/libpruw1 project, where a bidirectional line is used for one-wire communication.

Regards

Good to know.

And I’m surprised to hear that what you are describing is a feature of PRU_ICSS. The video on PRU_ICSSG was presenting it as though it was new functionality for the G version. Maybe that was just my wrongful interpretation of the video presentation?

So here are my followup questions:

-When you fiddle with the DIGIO_DATA_OUT_EN, can you select specifically which GPOs you want to float (i.e. leaving other GPOs active and driving their pins)?

Knowing that this register is in the GPIO_SS should help me to find more info about it in documentation. I was thinking it was a register of the PRUs.

Also good to know there’s that potential 3 cycle latency. For my purposes, 3 cycles is probably OK since the protocol does have “settling time” built into the timings when the direction of lines changes. But if that’s a minimum, I’d need to experiment with how loaded the L3 tends to get. I do expect to make relatively good use of the mailbox subsystem to pass Tx/Rx data-messages between the PRUs and the Processors. That traffic, I’m assuming would also be traversing the L3, and while it won’t be excessive, it will be present and thus adds some non-determinism to the system that will have to be tested for.

-The use of bi-directional leads me to assume that when GPOs are put into a floating state and are driven high/low by external means (i.e. other devices on the bus), the PRUs can READ the GPO pins for current state as though they are GPIs?

If the answer is YES to both of these, then I think this is something I can make use of to optimize my pin consumption. Unfortunately it doesn’t eliminate the need for the TXS0108E to perform level-shifting of the line voltages. But it might mean I don’t need to manage its Enable pin…another GPO I can reclaim.

I didn’t watch the video.

A floating line needs writing/reading registers in a GPIO-SS. This can be done by each cpu on the L3 bus (PRU, ARM, DSP, …).

Each GPIO-SS controls 32 lines. There’s one bit [0-31] for each line in the related read/write/data-out registers. So yes, some lines can float while others stay unchanged. You should take care that all lines are at the same GPIO-SS [0-3] (in order to control the paralel interface by a single register operation).

The rpmsg concept is not designed for real-time applications. Using UIO driver instead will speed up your development by making the timing in your application more predictable/reliable.

Regards

Meanwhile I watched the video. Here’s what I seem to understand:

Each PRU has fast GPIO lines (1 cycle latency) controlled by R30/R31.

In addition both PRUs can use the DIGIO block in the IEP module (constant 2 cycles latency). This block contains 8 digital lines controlled by data in/out registers (in a similar manner as in the GPIO-SS). In the new PRU_ICSSG hardware that block is extended by a further register named PRUSS_IEP_DIGIO_DATA_OUT_EN, in order to use those eight lines in floating mode.

So all PRUs can control floating lines by GPIO-SS with L3 latency, up to 32 lines simultaneously. In addition the new PRU_ICSSG can control eight floating lines with a fixed 2 cycle latency.

Regards

I did something similar to bit-bang a 4mhz three wire spi interface on the BBAI.
You need to clear the STANDBY_INIT on PRU startup;
CT_CFG.SYSCFG_bit.STANDBY_INIT = 0;

then whenever you want to flip I/O, Change the MUXMODE & INPUTENABLE bits in the CTRL_CORE_PAD_XXXX_NN register for the pin you are trying to change.

for the BBAI I was changing pr1_pru1_gpx5 which connected to ball F5 and P8_18 on the BBAI header.
register CTRL_CORE_PAD_VIN2A_D8 on pg 4693 of the AM572x TRM
map the physical address shown in TRM of the register to a variable.

change the MUXmode register bits 0-3


0xC pr1_pru1_gpi5 input
0xD pr1_pru1_gpo5 output

toggle bit 18 VIN2A_D8_INPUTENABLE to set input or output
1 = recv enable
0 = recv_disable

Hope this helps

I’m looking through the code in this example, and I’m focusing on the PRU interaction code.

The two places that are of most interest to me are the pruw1 struct which seems like a quite competent struct for doing PRU interactions with. Is this something you invented for this project or is this part of some API for interfacing with PRUs?

And I’m also getting the feeling that this is not the actual C-code that’s running on the PRU, but rather the higher level processor code that interacts with the PRUs. If that’s correct, where is the PRU-code (asm or c)? I don’t see it as part of the code in this project or I don’t know what I’m looking for.

In the pruw1.h, there’s a declaration for what appears to be a prototype constructor & destructor declaration for these structs. However I’m not finding the actual implementation of these prototype declarations. The syntax used in the comments suggests this would be in C++…which also follows as these are described as constructors and destructors. But I don’t see any .cpp files in the project.

I’m thinking maybe there are library files you are linking against and possibly referencing in your cmake config files. But I’ve got very little experience with cmake so it doesn’t take much for me to get lost in those files and miss something.

I got TI’s CCS setup and I’m able to setup a PRU project which knows how to interact with the PRU cross-compiler right from within CCS (TI’s modified version of Eclipse). I tried to use vanilla Eclipse CDT, but it really didn’t like my trying to add a non-gcc compliant toolchain, and trying to call the clpru compiler as a gcc compiler generated a lot of warnings & errors AND it didn’t even recognize the .c file it was being given to compile and link. But CCS has TI-specific Eclipse configuration to understand a Project is targeting a PRU and to use the PRU compiler AND call it correctly. I did have to fool CCS into believing I’m compiling for a microcontroller that TI advertises has a PRU. The J7/TVA processors aren’t listed at all, even for C/C++ development, which I find a little annoying.

Once I get all my pre-requisite setup, maybe I can actually start typing out some starter code to run on the BBAI64.

I also got the ARM cross-compiler installed on the BBAI64 itself so if I need, I can make PRU code edits and recompiles right from the BB.

This leads me to yet another question. How do I single-step debug code running in the PRU? I’ll post this as a separate/new thread if I can’t find the answer searching.

In CCS when doing a new project can you not select “J7231E_DRA829_TDA4VM” from the second target type drop down ?

On my setup that lest me target any of the internal processors

Now that I’m back home, I’m trying it again, and at first, I still didn’t see that in the list.

However if I clear the 1st list OR set it to Auto, then I see that show up. Thanks for pointing that out, one so my post isn’t spreading misinformation, but also so I know. I’ve updated my project as you see above, so I should be good to go now.

1 Like

Searching around the forum, I found this post which contains C-code intended to execute on the PRU:
PRU DMA example w/ HUB75 matrix dithering

While my needs aren’t really similar enough for me to use this code outright, I found it exceptionally helpful since it made reference to various .h files that I was confident existed, I just didn’t know where to find them. I hope this info is documented somewhere, but there’s a LOT of documentation to have to go through and an example cuts to the chase a little easier than official documentation can. Once I knew the names of those files, I could navigate to them, review them, and start getting a feel for what the various configuration and command options are, and see how they are used.

Having examples like this saves so much time when it comes to overcoming the early boilerplate requirements of a new project and why contributors on forums like this are so valuable.

1 Like

I am new to this party 6 months behind. I am using CCS12.3 to build my PRU code for uploading to the BBAI-64. The first project I got running is a pulse/square-wave generator. I can control the pulse width through the “/dev/rpmsg_pru30” interface. My next step is to get my dht22 1 wire sensor that run’s on the BBB ported to the BBAI-64. That code cleared the CT_CFG.SYSCFG_bit.STANDBY_INIT so that the PRU could get access to external memory. Hence, I was able to control GPIO pin’s directly. Is their away to allow the PRU to interface with external GPIO registers on the BAI64.

I don’t see why not. Although I have to admit, I don’t know the significance of that STANDBY_INIT flag you referenced as it relates to the BBB. So there may be more to your question than I realize. So take this for what it’s worth.

But I believe all you need to do is go into Sysconfig and setup the PRU_ICSSG’s PRU you are using to have direct GPI or GPO access. Sysconfig creates the logic that muxes the chip such that pins route to the desired internal peripheral. It also defines whether those pins have internal pull-up, pull-down, or float functionality. If the desired pin is mux-connected to the bits of your target PRU’s reg30/reg31 register bits, then reading/setting those bits from your PRU logic should be a direct-connection to the desired pins. The output files from Sysconfig can then either be incorporated into your project as device-tree overlays or C-programming.

Because a PRU’s reg30 and 31 are dedicated read and write registers, I don’t think there’s a way to mux a pin to both read and write registers of the PRU simultaneously (i.e. making the pin truly GPIO, not just GPI or GPO). Sysconfig wants there to be a 1-to-1 relationship between a pin and peripheral-tap, so I don’t know that Sysconfig would allow you to associate a single pin to two logical PRU taps.

However I have heard there are ways to programmatically sever the PRU output register bit(s) from its associated pins to let the pin float (or be pulled up or down) when you don’t want the pin being driven up or down by the PRU. With this, you can (externally to the microcontroller) wire a GPI pin and GPO pin together and get 2-way communication with some other device similar to a UART. Although I don’t know the details of how that’s done. I’ve only heard its possible. I suspect it’s literally remuxing the pin to and from the PRU output register. And if you are going to do this in PRU logic, you might as well find a pin(s) that can map to either reg30 or 31, and write PRU logic to remux the pin between the two depending on when you need the pin to be driven by the PRU vs monitored by the PRU. I don’t have a feel for just how safe/wise it is to perpetually and continually remux pins at high speed like this or how much latency there is in performing the remux. For all I know, doing so has the potential of creating EMI. Hopefully someone with more practiced knowledge on that subject can fill in the details I’ve glossed over as well as correct where my explanation might have gone off the rails of truth…if that’s functionality you care about.

@silver2row was working on connecting these inexpensive sensors that work on bi-directional mode (as I understand it). I wonder if he ever followed through with it.

I advised him not to pursue the bi-directional route, but to get the canonical hc-sr04 which has distinct trig and echo pins.

it would be interesting though to use a scope to see the change in direction on the data pin (grove sensor) and see the bi-directional action… I don’t know how to get the BBB to support such activity, but I’d be interested to know how the PI world does it.

use the level shifter or use 3.3v if you try this with the BBB.

gomer

GPIO pins can do bidirectional behavior on BBB or BBAI64 and should be able to handle that speed no problem. I don’t know anything about the Grove devices and the interface to know If a SPI or UART are appropriate, but even if they weren’t, raw bit-banging the GPIO pins with logic is an option, albeit a very manual and brute-force way of having to deal with it.

But 40kHz, from a technical could-it-do-it standpoint, should be possible. 40kHz correlates to a control/monitor period of 250 microseconds. The Cortex R5s on the BBAI64 could do that. And the BBB’s Cortex A8 definitely could if running raw code or an RTOS. However, I don’t know if a Linux application running on the BBB could keep up reliably. However a custom Linux kernel-module driver managing the GPIO pin(s) most definitely could.

But more to the point as it relates to this discussion thread, you wouldn’t use a PRU on the BBB or BBAI64 for something that requires 40kHz bi-directional com speeds. PRUs are better suited for tasks that require response-times measured in nanoseconds, not milliseconds range.

why do you assume the position of self appointed arbiter of what others would or would not do in this hobby arena?

speaking as a PRU fanboy, I would and do use the PRU for all sorts of purposes, whether it makes sense to you or any one else.

the application (PRU) that I made available for download (image) uses BOTH PRU for very low volume in normal usage (630 bytes / second ), but is CAPABLE of 20MHZ or about 1.2MB / second.

hobbyists should feel free to scratch ANY tech itch that fancies them, even if it doesn’t make sense to you.

PRU asm is FUN!

gomer

This is a comment and instuction that I found somewhere years ago.

/* Allow OCP master port access by the PRU so the PRU can read external memories */

CT_CFG.SYSCFG_bit.STANDBY_INIT = 0;

the macro is found in the linclude/am335x directory
/* PRU_CFG_SYSCFG register bit field */
union {
volatile uint32_t SYSCFG;

	volatile struct {
		unsigned IDLE_MODE : 2;
		unsigned STANDBY_MODE : 2;
		unsigned STANDBY_INIT : 1;
		unsigned SUB_MWAIT : 1;
		unsigned rsvd6 : 26;
	} SYSCFG_bit;
};	// 0x4

Their is a bit assignment structure in pru_iep.h that defines the PRU_IEP_DIGIO_CTRL register bit fields that I don’t know how to use. Both for am335x and am64xx.

I stand corrected. I admittedly was speaking from a professional standpoint, but you are absolutely correct.

This comes from the AM64x/AM243x Technical Reference Manual (Rev. F) Page 3255
Follow these steps to configure and write to the DIGIO Data Output:

  1. Pre-configure DIGIO by setting IEP_DIGIO_EXP_REG[1] OUTVALID_OVR_EN and
    IEP_DIGIO_EXP_REG[0] SW_DATA_OUT_UP
  2. Write to IEP_DIGIO_DATA_OUT_REG to configure output data.
  3. To HiZ output, set corresponding IEP_DIGIO_DATA_OUT_EN_REG[31-0] DATA_OUT_EN bits to 1h (clear
    to 0h to drive value stored in IEP_DIGIO_DATA_OUT_REG).

Has any one tried this or no of an example.

1 Like

This has an important caveat.

GPIO pins need to have their direction changed. At least on the BBB, that requires that you be in supervisor/Ring0/admin/whatever TI calls it mode.

The upshot of that is that you can’t change the direction of a GPIO pin from inside the PRU. This is an irritation when you are trying to bit bang things.

This may or may not be true on the AI64.

1 Like

I believe I have been changing direction for my BBB 1-wire DHT22 Temp/Humidity sensor. Snippet of code:
/* Allow OCP master port access by the PRU so the PRU can read external memories /
CT_CFG.SYSCFG_bit.STANDBY_INIT = 0;
.
.
__delay_cycles(100
CLKFREQ); // Delay for 100us, pins float HI
if((bank->DATAIN&DHT0_PIN) == DHT0_PIN)
{ // Do we have a DHT connected to this pin
pin0 = true; // Yes, DHT0
bank->DATAOUT|= DHT0_PIN; // Preset pin HIuint16_t
bank->OE&= ~DHT0_PIN; // Set DHT pin as output
}

Would like to port it to BBAI-64 but stuck with no OCP access,