Set pinmux to PRU Industrial Ethernet Peripheral (IEP) from Linux

55 views
Skip to first unread message

Andrew P. Lentvorski

unread,
Jan 18, 2020, 2:14:52 AM1/18/20
to BeagleBoard
Is there a way to set the pinmux for a pin to the PRU Industrial Ethernet Peripheral from Linux (for example: set pin P9_17 to pr1_edio_data_out0)?

If not, what would be the recommended way to do so?

Thanks.

Andrew P. Lentvorski

unread,
Jan 18, 2020, 7:29:35 AM1/18/20
to BeagleBoard
As far as I can tell, the old mmap() method fails.  What's my next step?

#include <stdint.h>

#include <stdio.h>
#include <stdlib.h>

#include <unistd.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>

#include <assert.h>


#define CONTROL_MODULE_START  ((uint32_t)0x44E10000)
#define CONTROL_MODULE_END    ((uint32_t)0x44E11FFF)
#define CONTROL_MODULE_LENGTH (CONTROL_MODULE_END - CONTROL_MODULE_START + 1)


// Official pin name for pr1_edio_data_out0 is SPI0_D1 in Mode 6
// Official pin name for pr1_edio_data_out1 is SPI0_CS0 in Mode 6

#define CONF_SPI0_D1_OFFSET  0x958
#define CONF_SPI0_CS0_OFFSET 0x95C

#define MODE_1 0x1
#define MODE_4 0x4
#define MODE_6 0x6

int main(int argc, char *argv[])
{
    uint32_t
volatile * control_mode_mapped_base = NULL;
   
   
int fd = open("/dev/mem", O_RDWR);
    printf
("/dev/mem opened: %d\n", fd);
    printf
("Mapping %X - %X (size: %X)\n", CONTROL_MODULE_START, CONTROL_MODULE_END, CONTROL_MODULE_LENGTH);

    uint32_t
volatile * const control_module_mapped_base = mmap(NULL, CONTROL_MODULE_LENGTH, PROT_READ | PROT_WRITE, MAP_SHARED, fd, CONTROL_MODULE_START);
    printf
("Mapped base to: %p\n", control_module_mapped_base);
   
assert(control_mode_mapped_base != ((uint32_t volatile * const)(-1)));

    uint32_t
volatile * const u32_control_P9_17 = (control_module_mapped_base + (CONF_SPI0_CS0_OFFSET/4));  // / 4 is due to the way C handles a pointer to uint32_t
    uint32_t
volatile * const u32_control_P9_18 = (control_module_mapped_base + (CONF_SPI0_D1_OFFSET/4));

   
*u32_control_P9_17 = MODE_1; // Fails to write
   
*u32_control_P9_18 = MODE_1;

    printf
("Mode for P9_17: %X\n", (*u32_control_P9_17 & 0x7));  // Read is fine--config-pin will cause this to change apropriately
    printf
("Mode for P9_18: %X\n", (*u32_control_P9_18 & 0x7));

   
assert((*u32_control_P9_17 & 0x7) == MODE_1);
   
assert((*u32_control_P9_18 & 0x7) == MODE_1);

    munmap
((void *)control_mode_mapped_base, CONTROL_MODULE_LENGTH);

    close
(fd);
}




TJF

unread,
Jan 18, 2020, 9:59:50 AM1/18/20
to BeagleBoard
No way! P9_17 is for PRU-1.

But libpruio can set P9_18 to pr1_edio_data_out0, which is mode 6. Find example code at http://users.freebasic-portal.de/tjf/Projekte/libpruio/doc/html/pruss__toggle_8c_source.html

In your case it needs a line at line number 110 like

    if (io->setPin(io, P9_18, 6)) {
           printf("P9_18 configuration failed (%s)\n", io->Errr); break;}
 

OR a resistor to the mode, if needed.

Regards

TJF

unread,
Jan 18, 2020, 10:13:40 AM1/18/20
to BeagleBoard
I forgot to mention:

If you want to use that pin for tri-state (as discussed in an other thread), you've to enable the receiver as well

    if (io->setPin(io, P9_18, 6 | PRUIO_RX_ACTIV)) {

Andrew P. Lentvorski

unread,
Jan 19, 2020, 3:20:58 AM1/19/20
to BeagleBoard
Well, sort of, except you omit the *EXTREMELY* important point that you install a custom kernel module in order to expose the clock activation and pinmux system to all users.

Okay, yes, if I build a kernel module I now have full access to all registers on the system with no restrictions.  That's sort of like swatting a fly with an H-Bomb, but it will work.

This means that config-pin has a fairly significant bug in not being able to route the IEP pins.  Has that bug ever been filed anywhere?

TJF

unread,
Jan 19, 2020, 3:38:28 AM1/19/20
to BeagleBoard

Am Sonntag, 19. Januar 2020 09:20:58 UTC+1 schrieb Andrew P. Lentvorski:
Well, sort of, except you omit the *EXTREMELY* important point that you install a custom kernel module in order to expose the clock activation and pinmux system to all users.

That's not correct. Only users with write access to the sysfs entry can pinmux. By default that're members of the pruio system group.
 
Okay, yes, if I build a kernel module I now have full access to all registers on the system with no restrictions.  That's sort of like swatting a fly with an H-Bomb, but it will work.

It was your idea to use the PRU-IEP module. I recommended to use a pin on a GPIO-SS. Yet, you didn't explain why the L3/L4 latency isn't aceptable for your target.

This means that config-pin has a fairly significant bug in not being able to route the IEP pins.  Has that bug ever been filed anywhere?

config-pin isn't able to set lots of useful pin configurations, and has lots of bugs. Ie. you can set GPIO for P9_42 and P9_92 in oposite output states and damage the CPU. C. Steinkuehler didn't develop that tool with a standard solution in mind. At the beginning it was a work-aroung, and only cosmetic changes were done.

Anyway, you can pinmux at boot-time by writing, compiling and installing a customized device tree overlay. The tool http://users.freebasic-portal.de/tjf/Projekte/libpruio/doc/html/dts__custom_8bas.html may be helpful in that case.

TJF

unread,
Jan 19, 2020, 4:28:15 AM1/19/20
to BeagleBoard
BTW:


Am Sonntag, 19. Januar 2020 09:20:58 UTC+1 schrieb Andrew P. Lentvorski:
Okay, yes, if I build a kernel module I now have full access to all registers on the system with no restrictions.  That's sort of like swatting a fly with an H-Bomb, but it will work.

You need not build your own H-Bomp. You can use the existing one

sudo apt-get install libpruio-modules-`uname -r`

Note: AFAIK RCN didn't update the source code, yet. That version uses a slightly different encoding than the LKM in the current libpruio-0.6.6. Check the source in RCNs build-farm.

Note: libpruio offers some safety features. Ie. it doesn't remux a pin claimed by an other system (, unless this feature gets disabled). Using the LKM without libpruio is at you own risc. Your code has to care about such issues.

Robert Nelson

unread,
Jan 19, 2020, 12:54:09 PM1/19/20
to Beagle Board
and merged: https://github.com/rcn-ee/libpruio/commits/master

Should have updated v4.14/v4.19/v5.4 kernels this week..

Regards,

--
Robert Nelson
https://rcn-ee.com/

Andrew P. Lentvorski

unread,
Jan 20, 2020, 1:12:34 AM1/20/20
to BeagleBoard
Okay, then I'm just missing something obvious.  What is a GPIO-SS?  What unit and what register address?  I see no mention of "GPIO-SS" anywhere in the AM335x Technical Reference Manual.

Normally, I associate SS with "slave select" which means SPI.  I see that you *can* turn around the CS lines on the McSPI subsystem, but you have to switch from Master to Slave Mode.  That doesn't seem like what you are suggesting.

On Sunday, January 19, 2020 at 12:38:28 AM UTC-8, TJF wrote:

It was your idea to use the PRU-IEP module. I recommended to use a pin on a GPIO-SS.

I went hunting for GPIO-SS--I didn't find anything.  I went hunting for OE (output enable) in the PRU docs.  I found one on the digio.  I also found that TI used the IEP to implement the 1-Wire interface on the PRUCAPE.  You were also implementing bidirectionality on a 1-Wire interface.  I drew an, incorrect in retrospect, inference that people were using the IEP digio for bidirectional and tri-state functions.

TJF

unread,
Jan 20, 2020, 4:27:12 AM1/20/20
to BeagleBoard
SS=subsystem -> chapter 25

Andrew P. Lentvorski

unread,
Jan 20, 2020, 5:52:10 PM1/20/20
to BeagleBoard

Thank you.
Reply all
Reply to author
Forward
0 new messages