Make PRU-controlled pin change direction or go tri-state?

161 views
Skip to first unread message

Andrew P. Lentvorski

unread,
Jan 16, 2020, 3:39:18 AM1/16/20
to BeagleBoard
I've got to be missing something obvious, but I even after several rounds of RTFM, I can't seem to figure out how to get the PRU to change the direction of a pin or, at the very least, to let it go to a tri-state value.

I would go out over the L3/L4 (although that kinda smashes the whole "real-time" thing), but won't that bump into the fact that the processor needs to be in supervisor mode?

Any help would be appreciated.

Thanks.

TJF

unread,
Jan 16, 2020, 11:39:20 AM1/16/20
to BeagleBoard
There's no supervisor mode for the PRU.

There's no tri-state-mode for AM335x GPIO.

In order to change direction for a pin on a GPIO-SS, it needs a write access to its OE register. The PRU can do that.

Find an example at https://github.com/DTJF/libpruw1/blob/master/src/bas/w1_prucode.p, which is a driver for a one-wire (w1) bus, reading and sending data on a single GPIO line for multiple divices. The library documentation is at http://users.freebasic-portal.de/tjf/Projekte/libpruw1/doc/html/

Dimitar Dimitrov

unread,
Jan 16, 2020, 12:08:44 PM1/16/20
to BeagleBoard
I don't think you can tri-state PRU output GPO. But you can hook external buffer (e.g. 74HC245) and dedicate one PRU GPO for output enable.

Regards,
Dimitar

Jason Kridner

unread,
Jan 16, 2020, 12:58:39 PM1/16/20
to beagl...@googlegroups.com


On Thu, Jan 16, 2020 at 3:39 AM Andrew P. Lentvorski <bsd...@gmail.com> wrote:
>
> I've got to be missing something obvious, but I even after several rounds of RTFM, I can't seem to figure out how to get the PRU to change the direction of a pin or, at the very least, to let it go to a tri-state value.
>
> I would go out over the L3/L4 (although that kinda smashes the whole "real-time" thing), but won't that bump into the fact that the processor needs to be in supervisor mode?

I see you got some other answers, but it might help you to qualify if you are using a chip-level GPIO or PRU-level GPIO.

As mentioned, you don't need a supervisor mode to get to the L3 bus needed to configure the GPIO or pinmux. You do need to clear the STANDBY_INIT bit in SYSCFG. Then, the PRU can poke all the SoC registers that the ARM can. Below is an example that clears this bit, but doesn't need to do so, because the PRU GPIO bits are INSIDE the PRUSS, so I'll likely remove those lines from this example in the future.

https://github.com/beagleboard/cloud9-examples/blob/master/BeagleBone/Black/pru/blinkR30.pru0.c :

////////////////////////////////////////
// blinkR30.pru0.c
// Blinks LEDs wired to P9_29 (and others) by writing register R30 on the PRU
// Wiring: P9_29 connects to the plus lead of an LED. The negative lead of the
// LED goes to a 220 Ohm resistor. The other lead of the resistor goes
// to ground.
// Setup: config_pin P9_29 pruout
// See: prugpio.h to see which pins attach to R30
// PRU: pru0
////////////////////////////////////////
#include <stdint.h>
#include <pru_cfg.h>
#include "resource_table_empty.h"
#include "prugpio.h"
volatile register unsigned int __R30;
volatile register unsigned int __R31;
void main(void) {
// Select which pins to toggle. These are all on pru1_1
uint32_t gpio = P9_29;
/* Clear SYSCFG[STANDBY_INIT] to enable OCP master port */
CT_CFG.SYSCFG_bit.STANDBY_INIT = 0;
while(1) {
__R30 |= gpio; // Set the GPIO pin to 1
__delay_cycles(500000000/5); // Wait 1/2 second
__R30 &= ~gpio; // Clear the GPIO pin
__delay_cycles(500000000/5);
}
__halt();
}
// Sets pinmux
#pragma DATA_SECTION(init_pins, ".init_pins")
#pragma RETAIN(init_pins)
const char init_pins[] =
"/sys/devices/platform/ocp/ocp:P9_29_pinmux/state\0pruout\0" \
"\0\0";

What I am thinking about adding to this repo is an example for reading an ultrasonic sensor that kinda stupidly (IMHO) uses the same pin to trigger a sample as to read it back. I think using the PRU for that would be good, but it means changing the pin direction. The way to do that without external hardware is to alter the PADCONF (ie., pinmux) settings on the pin to go from pru_out mode to pru_in. Otherwise, the PRU itself doesn't have any way to go into a high-Z or tristate mode.

I'd be happy if someone beat me to both updates to the repo and provided a pull-request.

>
> Any help would be appreciated.
>
> Thanks.
>
> --
> For more options, visit http://beagleboard.org/discuss
> ---
> You received this message because you are subscribed to the Google Groups "BeagleBoard" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to beagleboard...@googlegroups.com.
> To view this discussion on the web visit https://groups.google.com/d/msgid/beagleboard/16640740-240b-4e94-950d-f4bbe369fb76%40googlegroups.com.

Jason Kridner

unread,
Jan 16, 2020, 1:03:39 PM1/16/20
to beagl...@googlegroups.com
Thanks for the great example!

For those that don't quite follow, you are using the chip-level or SoC-level GPIO subsystem for this example and not the PRU subsystem GPIOs that can be accessed directly from R30/R31 on the PRU CPU itself. For those pins, the PADCONF or pinmux settings must be adjusted at the chip/SoC-level to disable the PRU GPIO output.
 

--
For more options, visit http://beagleboard.org/discuss
---
You received this message because you are subscribed to the Google Groups "BeagleBoard" group.
To unsubscribe from this group and stop receiving emails from it, send an email to beagleboard...@googlegroups.com.

Andrew P. Lentvorski

unread,
Jan 16, 2020, 11:27:06 PM1/16/20
to BeagleBoard


On Thursday, January 16, 2020 at 9:58:39 AM UTC-8, Jason Kridner wrote:


On Thu, Jan 16, 2020 at 3:39 AM Andrew P. Lentvorski <bsd...@gmail.com> wrote:
>
> I've got to be missing something obvious, but I even after several rounds of RTFM, I can't seem to figure out how to get the PRU to change the direction of a pin or, at the very least, to let it go to a tri-state value.
>
> I would go out over the L3/L4 (although that kinda smashes the whole "real-time" thing), but won't that bump into the fact that the processor needs to be in supervisor mode?

I see you got some other answers, but it might help you to qualify if you are using a chip-level GPIO or PRU-level GPIO.

As mentioned, you don't need a supervisor mode to get to the L3 bus needed to configure the GPIO or pinmux. You do need to clear the STANDBY_INIT bit in SYSCFG. Then, the PRU can poke all the SoC registers that the ARM can. Below is an example that clears this bit, but doesn't need to do so, because the PRU GPIO bits are INSIDE the PRUSS, so I'll likely remove those lines from this example in the future.



I guess I'm still missing something because the following program doesn't work.  When I try to write to *u32_control_P9_27, nothing changes.  I *CAN* however read from it and config-pin can change it externally just fine.  So, I got the actual *pointer address* as well as various clocks and enables correct since I can read it properly.

What did I get wrong?


#include <stdint.h>
#include <pru_cfg.h>
#include "resource_table_empty.h"

volatile register uint32_t __R30;   // 32 output gpios
volatile register uint32_t __R31;   // 32 input gpios

#define CONTROL_MODULE_START ((uint32_t)0x44E10000)
#define CONF_MCASP0_FSR_OFFSET 0x9A4
uint32_t
volatile * const u32_control_P9_27 = (uint32_t volatile * const)(CONTROL_MODULE_START + CONF_MCASP0_FSR_OFFSET);

#define PINMUX_PRU_OUT 0x5
#define PINMUX_PRU_IN  0x6

#define DELAY_CYCLES (50000000/2)
void main(void) {
    uint32_t
const led = 0x00000028; // Use pru0_pru_r30_5 and pru0_pru_r32_3 as an output

   
// You can now monitor P9_28 frequency as reflecting state of P9_27 pinmux
   
    CT_CFG
.SYSCFG_bit.STANDBY_INIT = 0;

   
unsigned int ui = 0;
   
unsigned int ui_fast = 0;

   
while (1) {
       
*u32_control_P9_27 = PINMUX_PRU_IN;  // No effect on frequency while config-pin causes expected frequency shifts

       
++ui;

       
if (((*u32_control_P9_27) & 0x07) == PINMUX_PRU_OUT) {  // This verifies that I actually got the correct address of the pinmux
            ui_fast
= 1;
       
} else {
            ui_fast
= 0;
       
}
           
        __R30
= led;                
        __delay_cycles
(DELAY_CYCLES);
       
if (ui_fast != 1) {
            __delay_cycles
(DELAY_CYCLES);
       
}
       
        __R30
= 0;                
        __delay_cycles
(DELAY_CYCLES);
       
if (ui_fast != 1) {
            __delay_cycles
(DELAY_CYCLES);
       
}
   
}

    __halt
();
}




Jason Kridner

unread,
Jan 16, 2020, 11:50:12 PM1/16/20
to beagl...@googlegroups.com
On Thu, Jan 16, 2020 at 11:27 PM Andrew P. Lentvorski <bsd...@gmail.com> wrote:


On Thursday, January 16, 2020 at 9:58:39 AM UTC-8, Jason Kridner wrote:


On Thu, Jan 16, 2020 at 3:39 AM Andrew P. Lentvorski <bsd...@gmail.com> wrote:
>
> I've got to be missing something obvious, but I even after several rounds of RTFM, I can't seem to figure out how to get the PRU to change the direction of a pin or, at the very least, to let it go to a tri-state value.
>
> I would go out over the L3/L4 (although that kinda smashes the whole "real-time" thing), but won't that bump into the fact that the processor needs to be in supervisor mode?

I see you got some other answers, but it might help you to qualify if you are using a chip-level GPIO or PRU-level GPIO.

As mentioned, you don't need a supervisor mode to get to the L3 bus needed to configure the GPIO or pinmux. You do need to clear the STANDBY_INIT bit in SYSCFG. Then, the PRU can poke all the SoC registers that the ARM can. Below is an example that clears this bit, but doesn't need to do so, because the PRU GPIO bits are INSIDE the PRUSS, so I'll likely remove those lines from this example in the future.



I guess I'm still missing something because the following program doesn't work.  When I try to write to *u32_control_P9_27, nothing changes.  I *CAN* however read from it and config-pin can change it externally just fine.  So, I got the actual *pointer address* as well as various clocks and enables correct since I can read it properly.

What did I get wrong?

Looks like *I* got it wrong that you can change PADCONF from the PRUs. Apparently, from the PRUs those registers are read-only. :-(

 
--
For more options, visit http://beagleboard.org/discuss
---
You received this message because you are subscribed to the Google Groups "BeagleBoard" group.
To unsubscribe from this group and stop receiving emails from it, send an email to beagleboard...@googlegroups.com.


--
https://beagleboard.org/about - a 501c3 non-profit educating around open hardware computing

Andrew P. Lentvorski

unread,
Jan 17, 2020, 4:17:19 AM1/17/20
to BeagleBoard
On Thursday, January 16, 2020 at 8:39:20 AM UTC-8, TJF wrote:

In order to change direction for a pin on a GPIO-SS, it needs a write access to its OE register. The PRU can do that.

Let me see if I have this straight, I need access to an output enable from the PRU.  The only output enable I can see involves the Industrial Ethernet Peripheral.

So, by setting the PINMUX up front to the IEP, I can route my data through the IEP DIGIO in order to gain the tri-state capability I want?

That ... might actually be what I need.

Thanks.
Reply all
Reply to author
Forward
0 new messages