This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

Compiler/PROCESSOR-SDK-AM335X: PRU communication problem

Part Number: PROCESSOR-SDK-AM335X

Tool/software: TI C/C++ Compiler

I'm trying to make PRU talk to ARM host in a beaglebone. The difficulty is I want to check on both ends to see if the other side has sent any message, in a non-blocking fashion.

On the host side, just polling and reading on /dev/rpmsg_pru30 and /dev/rpmsg_pru31 seems to be good enough.

On the PRU side, I'm having a problem with too many interrupts.

I'm using

CT_INTC.SICR = FROM_ARM_HOST;

to clear the interrupt, and

#define CHAN_PORT       30
#define CHAN_DESC   "Channel 30"
#define TO_ARM_HOST     16
#define FROM_ARM_HOST   17
#define INT_MASK            ((uint32_t)1 << CHAN_PORT)
#define FROM_ARM_MASK       ((uint32_t)1 << FROM_ARM_HOST)

if (((__R31 & INT_MASK) && (CT_INTC.SECR0 & FROM_ARM_MASK)) != 0) {...}

(Both FROM_ARM_HOST and TO_ARM_HOST are set using pru_rpmsg_init.)

to check for the interrupt for PRU0. I also clear the interrupt after every read.

It seems to work fine when I"m just receiving message from the host. However, if I send a message from PRU0 to ARM host, the interrupt is on but since there was nothing to read from ARM to PRU0, the reading fails.

It doesn't help if I immediately clear the interrupt after the send. The clearing seems to work, however, if I send message from PRU0 to ARM, wait for about 4E5 cycles, clear the interrupt, wait for the next message from ARM, then it works (the interrupt is cleared and next interrupt from ARM to PRU0 is registered normally).

I don't understand why the interrupt on this two way channel is not reliable. Is there something I did wrong? If I try to clear the interrupt with CT_INTC.SICR_bit.STS_CLR_IDX = FROM_ARM_HOST I see the same problem. If I check the interrupt simply with if (__R31 & HOST_INT) like in the lab examples, the flag is always true and never gets cleared.

  • Hi, 

    Our expert in this area is out for a couple of days. He'll reply as soon as he can and we're sorry for the delay.

  • Hello Keji,

    1) Are you simply trying to use RPMsg to communicate between the ARM and the PRU? Or are you  trying to create a custom communication protocol based on RPMsg?

    2) What version of linux processor SDK are you using?

    3) What is the rate at which you want to send messages back and forth between ARM and PRU?

    Regards,

    Nick

  • Hello Nick,

    I'm simply trying to communicate between ARM and PRU using RPMsg, it's just I would like to check for the interruption like in Lab 5. The sdk is version 4.3 and PRU-ICSS is at 5.1.0. I'm currently sleeping for 1E5 cycles between communications which means 2kHz, but ideally I want to increase it to 20kHz. Is there any other information you need to debug the issue?

  • Hello Keji,

    RPMsg will not be able to keep up with 20kHz communication cycles. We will need to find you another way to communicate.

    It sounds like you want PRU to communicate with ARM Linux userspace. Will your solution have root privileges? If so, you should just be able to mmap to the PRU memory from userspace. If not, you would probably be looking at a small kernel driver to expose PRU data & interrupts.

    Regards,

    Nick

  • Hi Nick, thanks for the clarification and suggestion. Is there a good PRU mmap memory tutorial/lab, or section of the manual you can point me to? Also if I'm going the mmap route, how do I set and check the interrupt from the arm host side?

  • Hello Keji,

    I am sorry for the delayed response. For an example of using mmap from user space, please see the customer's solution in the post PRU UIO Client Support.

    That customer used RPMsg for sending interrupts, and mmap to allow the ARM to access data in a portion of PRU memory. However, you could also expose the PRU's INTC registers and allow the ARM to set interrupts directly.

    Let me know if you have any follow-up questions,

    Nick

  • Hi Nick,

    The post you pointed to is very helpful and mmap is working for me on both directions and it works at high frequency. Thank you!

    However, for my application I still need to kick and check PRU interrupt from the ARM host side. Is there a post or tutorial for how to do it from the user land?

  • Hello Keji,

    if you mmap the INTC memory space, you can access the INTC registers. Take a look at the PRU > Functional Description > Interrupt Controller (INTC) and Registers > PRU_ICSS_INTC Registers sections in the AM335x Technical Reference Manual.

    In particular, I'd write to the SISR register from the ARM to send an interrupt to the PRU. e.g., if you mapped System event 20 to channel 0 to host interrupt 0, then you would write 20 to the SISR register and the PRU would be able to observe the bit value change in R31.

    Regards,

    Nick

  • Hi Nick, thanks for the pointer. Just to be clear, mmapping to SISR does not require UIO_PRUSS or any specific driver right? I'm asking becuase firmware loading by symlinking /lib/firmware/am335x-fw-pruX doesn't seem to work without the remoteproc module, and that seemed to be allow large executive files larger than the 4K limit.

  • Hello Keji,

    I would not expect mmapping to SISR to require any specific driver. If userspace does not have mmap permissions, then you would need a driver to expose that memory space (like UIO_PRUSS or a custom driver). But that is not needed for you. Your use case should be able to use remoteproc to load your firmware.

    By "executive files", I assume you mean PRU firmware files that are loaded into IRAM.

    Regards,

    Nick

  • Hi Nick, it's reassuring to know that no drivers are needed to mmap to the interrupt registers.

    However I don't really understand the firmware loading part. The IRAM is 4Kb each but clpru already gives something tens of Kb or even >100Kb, even when debugging symbols were not included. But they were successfully loaded without problem, how was that done? I imagine it was loaded differently from the small binaries output from the assembler?

  • Could you show me what you are talking about? If your PRU firmware is larger than the IRAM space, it should not successfully load and run. However, the size of your Linux userspace application does not matter for loading and running the PRU firmware.

    Regards,

    Nick

  • Hi Nick, attached is an example. The pru1.out file is 61k and when i copy over to the bealgebone it loads fine and generates a square wave. Is it not the final binary, i.e.: remoteproc did something to it and the actual machine code is in some other intermediate file?3833.files.zip

  • Hello Keji,

    I apologize for the delayed response. the .out file is an ELF object file. Only a portion of the ELF binary is loaded into the PRU IRAM and DRAM by RemoteProc, and that portion of the binary must be smaller than the PRU IRAM or DRAM size. You can get an idea of what is inside your .out file by running readelf -S outFile.out. Some sections will be familiar from your command linker file AM335x_ PRU.cmd (e.g., your instructions go in .text, which is placed in IRAM). But there is also a lot more information that is not loaded directly into the PRU.

    So how do you figure out how much memory your code will take up? Take a look at the map file. PAGE 0 tells you how much used and unused IRAM you have, while PAGE 1 should say how much used and unused DMEM you have.

    FYI, the map file be generated in your Makefile by adding the linker command -m. See the PRU Optimizing C/C++ Compiler Guide for more information. You can also see an example in any of our makefiles in the PRU Software Support Package. 

    Regards,

    Nick

  • Thanks! That's a very clear explanation. I was confused by the difference introduced by the new system.