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: Data transfer from PRU to ARM

Part Number: PROCESSOR-SDK-AM335X

Tool/software: TI C/C++ Compiler

I am trying to use the PRU for an encoder for my research.

I am using a BeagleBlack Board, with Debian and RT_PREEMPT Patch.
My objective is to be able to send an integer from the PRU (calculated in the PRU) and send it to the ARM, to be able to use it in real-time. My background is mechanics so I have some problem understanding the process for that. Nevertheless, I have been trying to understand the example proposed by TI and on some git hub repository (https://github.com/ZeekHuge/BeagleScope). So far I am able to calculate the value on the PRU and send it to the arm, using the pru_rpmsg_send function, but when I cat the value, I obtain either a letter or an unknown caracter. I have tried multiple solution to avoid this but I can not figure this out.

Could you help solve this issue.

  • Hi,

    Debian is not supported by TI. I will notify the PRU experts. They will comment here if they have some suggestions.
  • When you 'cat' the value from user space it is assuming an ASCII character encoding when displaying the values. So, a decimal value of 65 would be displayed as 'A' for instance.

    You need to use a user space program to open the /dev/rpmsg_pruX character device, read the data from the character device, and then cast the read values to the type that you expect:

    PRU Side:
    int number = 65;
    pru_rpmsg_send(&transport, dst, src, &number, sizeof(int));

    ARM user space C program:
    #define MAX_BUFFER_SIZE 512
    char readBuf[MAX_BUFFER_SIZE];
    struct pollfd pollfds[1];
    int result = 0;
    int number;
    /* Open the rpmsg_pru character device file */
    pollfds[0].fd = open(/dev/rpmsg_pru30, O_RDWR);
    result = read(pollfds[0].fd, readBuf, MAX_BUFFER_SIZE);
    if(result > 0)
            number= (int*)readBuf;
    /* Close the rpmsg_pru character device file */
    close(pollfds[0].fd);

    I haven't tested that code exactly but it should be fairly close to what you need.

    Jason Reeder

  • Thank you very much for you fast answer. I have done as you have suggested me and also some stuff on my own. It seems to work fine since the output value is the same as the one I have set in the PRU side. I have tried with a value greater than 255, in my case 1000. Also, I use c++ but I don't think it change that much. I am writing my code, if other people have the same issue.

    PRU Side:

    int number = 1000;
    pru_rpmsg_send(&transport, dst, src, &number, sizeof(int));

    ARM user space C++ program:

    #define MAX_BUFFER_SIZE 512
    char readBuf[MAX_BUFFER_SIZE];
    struct pollfd pollfds[1];
    int result = 0;
    int number1;
    int number2;
    int number3;
    int number4;
    int finalResult;
    char filename[18] = "/dev/rpmsg_pru31";
    int fd;

    /* Open the rpmsg_pru character device file */
    pollfds[0].fd = open(filename, O_RDWR);
    result = read(pollfds[0].fd, readBuf, MAX_BUFFER_SIZE);
    if(result > 0)
            number1= (int)(readBuf[0]);
            number2= (int)(readBuf[1]);
            number3= (int)(readBuf[2]);
            number4= (int)(readBuf[3]);
    /* Close the rpmsg_pru character device file */
    close(pollfds[0].fd);

    finalResult=number1+number2*256+number3*256*256+number4*256*256*256;
    cout << "The number send by the PRU is : " << finalResult << endl;

    Since I would like to use this for real-time purpose, I will test if it can be done in a 1ms loop, and publish the results.

    Anyway, thank you very much for your help, the quality and the rapidity of it.

    V. Babin

  • Mr. Reeder, thank you for your support.

    I have tested your solution as I have stated earlier but I still face some problem. To explain them, I will detail a little bit further the goal of the utilization of the PRU in my case.

    I would like to use the PRU as a "counter board": from two pins connected to the signal A and B, I would like to be able to measure the angle given by the encoder. To do so, the PRU create a while loop that check for each pin if the logical state is different from the previous one. If different, from logical tests, I am able to say if it incremented positively or negatively. (So far, I am using only pin, but would like to expend to 2). So as I said before, I send this value to the ARM via pru_rpmsg_send.

    The problem I am facing now, is on the ARM side. The objective is to fetch the last value send by the PRU every 1ms to use it to calculate the velocity of the encoder in real-time (I do not need all the values sent by the PRU, just the latest). From the method I am using now, it seems that I read the buffer from the latest value read. This create two problems, I can not access the latest value send, thus the calculation of the velocity is wrong and also it seems that the buffer become full (the logical state of the channel is changing around 10 times per ms, so 10KHz). From the different documentation I have read,

    https://git.ti.com/pru-software-support-package/pru-software-support-package/blobs/fcbe64c1fbde0ae0f4946a2c3a67c224895b67d3/lib/src/rpmsg_lib/pru_rpmsg.c

    https://git.ti.com/pru-software-support-package/pru-software-support-package/blobs/aa9606013059eb8728bcc1165c5032f0589469e0/include/pru_rpmsg.h

    https://git.ti.com/pru-software-support-package/pru-software-support-package/blobs/aa9606013059eb8728bcc1165c5032f0589469e0/include/pru_virtqueue.h

    I seems that one data is deleted from the buffer only when the ARM reads it.

    So could you tell me if there is a solution to read the last value of the buffer ? Is there a solution to delete the content of the buffer after reading the last value ?

    Sincerely,

    V. Babin

  • The rpmsg character device driver uses a kernel FIFO to store the messages from the PRU until user space reads them. So your observations are correct that you aren't seeing the latest message from the PRU when you read (first in first out) and also that the FIFO will fill up if user space doesn't read from it as the PRU continues to write to it.

    Here are a few methods to achieve your desired results:

    • Set up a very simple request protocol between user space and the PRU
      • Have user space send a request for the PRU to send the latest data (could be as simple as writing a single character from user space to the rpmsg_pru device)
      • The PRU could constantly be monitoring the pins and keeping a local copy of the latest data. When a message is received from user space, the PRU could send a message with the latest data
      • Have user space send a request once a millisecond
    • Only have the PRU send the latest data once a millisecond
      • You can use the CYCLE register in the PRU_ICSS_PRU_CTRL register set to only send one rpmsg per millisecond that contains the latest data
    • You can have your user space program constantly reading the data from the character device and discarding all data except one message per millisecond

    My suggestion would be the first option but all three should work for your use case.

    Jason Reeder

  • Thank you very much for your reply.

    I have tried your first option by modifying the code of the example "Hello World", I am able to do the communication every 1 ms. Nonetheless, as my goal of using the PRU is to do a counter board for an encoder, I am checking within a (infinite) while loop the logical state of two pins (channel A and B of the encoder) and incrementing the angle if necessary. The solution works fine until the speed rotation of the encoder reached a certain speed. It seems that the communication between the ARM and the PRU is taking too much time, thus, the while loop is taking too much time to complete, missing logical state's change during the loop.

    PS : From the ARM side, I have used timestamp to measure the duration to send a message to the PRU and receive the answer, on the beaglebone black, using a RT_PREEMPT patch, it takes around 0.4ms to complete.

    I will continue to search ways to transmit data to the ARM faster.

    Sincerely,

    V. Babin