pru_rpmsg_send triggers interrupt

I want to send data in a single message from the PRU to the ARM processor when the ARM to PRU interrupt is triggered. For some reason the interrupt bit that I clear resets causing a flood of messages that completely lock up the OS after a few moments.

I am running PRU Software Support Package v5.9.0 and Kernel 5.4.106-ti-r27 on a Beaglebone Black. To demonstrate this effect I have modified the PRU_RPMsg_Echo_Interrupt0 example (in pru-software-support-package/examples/am335x/PRU_RPMsg_Echo_Interrupt0) I havenā€™t changed anything in the resourcetable, the command linker file or the Makefile. Only the main.c file was modified as seen below:

/*
 * Copyright (C) 2016-2018 Texas Instruments Incorporated - http://www.ti.com/
 *
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *	* Redistributions of source code must retain the above copyright
 *	  notice, this list of conditions and the following disclaimer.
 *
 *	* Redistributions in binary form must reproduce the above copyright
 *	  notice, this list of conditions and the following disclaimer in the
 *	  documentation and/or other materials provided with the
 *	  distribution.
 *
 *	* Neither the name of Texas Instruments Incorporated nor the names of
 *	  its contributors may be used to endorse or promote products derived
 *	  from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include <stdint.h>
#include <stdio.h>
#include <pru_cfg.h>
#include <pru_intc.h>
#include <rsc_types.h>
#include <pru_rpmsg.h>
#include "resource_table_0.h"

volatile register uint32_t __R31;

/* Host-0 Interrupt sets bit 30 in register R31 */
#define HOST_INT			((uint32_t) 1 << 30)

/* The PRU-ICSS system events used for RPMsg are defined in the Linux device tree
 * PRU0 uses system event 16 (To ARM) and 17 (From ARM)
 * PRU1 uses system event 18 (To ARM) and 19 (From ARM)
 */
#define TO_ARM_HOST			16
#define FROM_ARM_HOST			17

/*
 * Using the name 'rpmsg-pru' will probe the rpmsg_pru driver found
 * at linux-x.y.z/drivers/rpmsg/rpmsg_pru.c
 */
#define CHAN_NAME			"rpmsg-pru"
#define CHAN_DESC			"Channel 30"
#define CHAN_PORT			30

/*
 * Used to make sure the Linux drivers are ready for RPMsg communication
 * Found at linux-x.y.z/include/uapi/linux/virtio_config.h
 */
#define VIRTIO_CONFIG_S_DRIVER_OK	4


uint8_t payload[RPMSG_MESSAGE_SIZE]={0x54, 0x45, 0x53, 0x54, 0x0a};

/*
 * main.c
 */
void main(void)
{
	struct pru_rpmsg_transport transport;
	uint16_t src=1024, dst=30, len=5;
	volatile uint8_t *status;

	/* Allow OCP master port access by the PRU so the PRU can read external memories */
	CT_CFG.SYSCFG_bit.STANDBY_INIT = 0;

	/* Clear the status of the PRU-ICSS system event that the ARM will use to 'kick' us */
	CT_INTC.SICR_bit.STS_CLR_IDX = FROM_ARM_HOST;

	/* Make sure the Linux drivers are ready for RPMsg communication */
	status = &resourceTable.rpmsg_vdev.status;
	while (!(*status & VIRTIO_CONFIG_S_DRIVER_OK));

	/* Initialize the RPMsg transport structure */
	pru_rpmsg_init(&transport, &resourceTable.rpmsg_vring0, &resourceTable.rpmsg_vring1, TO_ARM_HOST, FROM_ARM_HOST);

	/* Create the RPMsg channel between the PRU and ARM user space using the transport structure. */
	while (pru_rpmsg_channel(RPMSG_NS_CREATE, &transport, CHAN_NAME, CHAN_DESC, CHAN_PORT) != PRU_RPMSG_SUCCESS);
	while (1) {
		/* Check bit 30 of register R31 to see if the ARM has kicked us */
		if (__R31 & HOST_INT) {
			pru_rpmsg_send(&transport, dst, src, payload, len);
			/* Clear the event status */
			CT_INTC.SICR_bit.STS_CLR_IDX = FROM_ARM_HOST;
		}
		__delay_cycles(200000000);
	}
}

I have added the delay so that it doesnā€™t lag out. The position of the event status clear does not appear to make a difference.
To install the firmware and make it run I used the following commands:

sudo cp gen/PRU_RPMsg_Echo_Interrupt0.out /lib/firmware/test
echo 'test' > /sys/class/remoteproc/remoteproc1/firmware
echo 'start' > /sys/class/remoteproc/remoteproc1/state

To trigger the first interrupt I just echo a random string and observe the output with cat

echo '1' > /dev/rpmsg_pru30
cat /dev/rpmsg_pru30

I expected to read a single line saying TEST, however every second a new line saying TEST is printed until I terminate the firmware.
The only way to achieve my desired behaviour so far was to ignore the next interrupt with the code below:

`#include <stdint.h>
#include <stdio.h>
#include <pru_cfg.h>
#include <pru_intc.h>
#include <rsc_types.h>
#include <pru_rpmsg.h>
#include "resource_table_0.h"
#include <stdbool.h>

bool fired=true;
volatile register uint32_t __R31;

/* Host-0 Interrupt sets bit 30 in register R31 */
#define HOST_INT			((uint32_t) 1 << 30)

/* The PRU-ICSS system events used for RPMsg are defined in the Linux device tree
 * PRU0 uses system event 16 (To ARM) and 17 (From ARM)
 * PRU1 uses system event 18 (To ARM) and 19 (From ARM)
 */
#define TO_ARM_HOST			16
#define FROM_ARM_HOST			17

/*
 * Using the name 'rpmsg-pru' will probe the rpmsg_pru driver found
 * at linux-x.y.z/drivers/rpmsg/rpmsg_pru.c
 */
#define CHAN_NAME			"rpmsg-pru"
#define CHAN_DESC			"Channel 30"
#define CHAN_PORT			30

/*
 * Used to make sure the Linux drivers are ready for RPMsg communication
 * Found at linux-x.y.z/include/uapi/linux/virtio_config.h
 */
#define VIRTIO_CONFIG_S_DRIVER_OK	4


uint8_t payload[RPMSG_MESSAGE_SIZE]={0x54, 0x45, 0x53, 0x54, 0x0a};

/*
 * main.c
 */
void main(void)
{
	struct pru_rpmsg_transport transport;
	uint16_t src=1024, dst=30, len=5;
	volatile uint8_t *status;

	/* Allow OCP master port access by the PRU so the PRU can read external memories */
	CT_CFG.SYSCFG_bit.STANDBY_INIT = 0;

	/* Clear the status of the PRU-ICSS system event that the ARM will use to 'kick' us */
	CT_INTC.SICR_bit.STS_CLR_IDX = FROM_ARM_HOST;

	/* Make sure the Linux drivers are ready for RPMsg communication */
	status = &resourceTable.rpmsg_vdev.status;
	while (!(*status & VIRTIO_CONFIG_S_DRIVER_OK));

	/* Initialize the RPMsg transport structure */
	pru_rpmsg_init(&transport, &resourceTable.rpmsg_vring0, &resourceTable.rpmsg_vring1, TO_ARM_HOST, FROM_ARM_HOST);

	/* Create the RPMsg channel between the PRU and ARM user space using the transport structure. */
	while (pru_rpmsg_channel(RPMSG_NS_CREATE, &transport, CHAN_NAME, CHAN_DESC, CHAN_PORT) != PRU_RPMSG_SUCCESS);
	while (1) {
		/* Check bit 30 of register R31 to see if the ARM has kicked us */
		if (__R31 & HOST_INT) {
			if(!fired){
				pru_rpmsg_send(&transport, dst, src, payload, len);
				fired=true;
			}
			else{
				fired=false;
			}
			CT_INTC.SICR_bit.STS_CLR_IDX = FROM_ARM_HOST;
		}
		__delay_cycles(200000000);
	}
}

If I follow the same steps as for the first program I receive exactly one line saying TEST. The number of interrupts that I cause by writing to the device endpoint is exactly the number of message lines that I get in the end.

What am I doing wrong? Did I misconfigure something or missed something obvious? I couldnā€™t find any good documentation and the rpmsg echo example seems to be the only one out there.

Am I using pru_rpmsg_send wrong or is this actually a bug?

Iā€™ve not used this specific example but I have been using remoteproc for several months now and fought several issues.

So where are you setting the values of true and false? Have your tried just setting fired =1 or fired =0? I try to be very discrete when debugging.

I have very good results with remoteproc usually. I have not changed the values of src or dst. I do change the value I pass as len in pru_rpmsg_send() but just enter in the discrete number. I also use strcpy() to load the payload variable. Itā€™s an extra line of code but it reads nicely.

So something like thisā€¦

strcpy(payload_out,"KICK:STOP\0");  // put the acknowledgement response in payload_out
pru_rpmsg_send(&transport, dst, src, payload_out, 10);  // send the response back

I have C code running on the ARM side that sends the messages so I donā€™t use the echo and cat from the Linux command line like you are using. Usually, when I send a single message, the PRU reads it fine and responds accordingly. I donā€™t get repeat messages unless I have the PRU instructed to do so.

I have experienced an issue I could never solve. The desired behavior is this.

  1. ARM send ā€˜STARTā€™ to PRU.
  2. PRU receives messages and sees it is ā€˜STARTā€™ and goes into a routine. Regularly in this routine it checks for a ā€˜kickā€™ from the ARM using

if (__R31 & HOST_INT)

  1. The ARM needs to stop the PRU for some reason, so it sends a second message ā€œSTOPā€.
  2. The PRU never seems to get the second message. Itā€™s as if the HOST_INT bit isnā€™t being set.

I clear the HOST_INT bit whenever it Is set, so Iā€™m not sure what is going on.

Iā€™m not sure which versions I am running of the support package I am running. How did you check that?

Thank you for your reply!

Regarding the true false values I am using the stdbool library that does the definitions. I have been spoiled with c#, so my preferences might differ from a classic c programmer that does logic with an integer 0 and 1.

In normal communication between ARM and PRU core I wouldnā€™t manually change the src and dst either, however in my particular problem (that is way too long to describe) I have a triangle communication, where ARM sends a command to PRU1, PRU1 interrupts PRU0 and PRU0 then sends a message. Since I never send anything from ARM to PRU0 I donā€™t get the benefit of pru_rpmsg_receive that does the value setting for me. Thatā€™s why Iā€™m using constants instead. They are the exact same as the ones that receive would set. My issue seems only to occur when pru_rpmsg_send stands unenclosed by a pru_rpmsg_recieve.

I wanted to eliminate as many points of failure as possible (tho I agree that some string copy for readability wouldnā€™t have hurt). I want to show this error already occurs with the most fundamental commands and isnā€™t due to some other mistake hidden in a support program.

I canā€™t tell you much about your issue. It might deserve its own thread with code snippets and all. At the top of my head I can only think of two issues.

  1. The program wanders of into an infinite loop never to be seen again
  2. if you clear the bit at the end and the program takes a moment to run you could be ā€œdouble settingā€ the interrupt and only clearing it once. Itā€™s not a real interrupt and things like that can happen all the time.

On a default image the PSSP is located in /usr/lib/ti/pru-software-support-package. If the Manifest html is to be believed it is version 5.0. On my upgraded Kernel it didnā€™t run, so I always get the latest version from git. I specifically download v5.9.0, since the latest v6.1.0 doesnā€™t run on kernel 5.4 anymore. It has a neat little release notes file that says that my version is 5.9.0. I havenā€™t found a better way to check.

1 Like

Thanks for the info. Our development platforms are running kernel 4.19 and weā€™ve had no need to update to anything more recent so far. I would like to get the latest PRU Software Support Package. Iā€™m a real novice with git. I noticed that on our main development Beagle that running

git status

in directory /usr/lib/ti/pru-software-support-package

results in

fatal: not a git repository (or any of the parent directories): .git

If I wanted to update the pru-software-support-package, can I initial the repo at this directory somehow and pull it from TIā€™s repo? And how would I do that?

Ugh, thatā€™s not goodā€¦ iā€™ll branch that deb package into versionsā€¦

itā€™s from this repo: Gitweb @ Texas Instruments - Open Source Git Repositories - git.TI.com/gitweb - pru-software-support-package/pru-software-support-package.git/summary

let me clean things up by having versionsā€¦

Okay, iā€™ve pushed two new packages:

ti-pru-software-v5.9
files: /usr/lib/ti/pru-software-support-package-v5.9/
ti-pru-software-v6.0
files: /usr/lib/ti/pru-software-support-package-v6.0/

Please ping me if you need another specific tag:

https://git.ti.com/gitweb?p=pru-software-support-package/pru-software-support-package.git;a=summary

Regards,

@RobertCNelson ā€¦I get a bit lost in all of this. So if Iā€™m running 4.19, can I do an update and get the latest PRU support packages that are compatible? Or are your pushes just applicable to kernel 5.x?

honestly, up until this thread, i always assumed it supported allā€¦ now that we know TI eolā€™s kernel versions we need to be more careful with that git repoā€¦

Currently, iā€™m mostly focused on v5.10.x, so really anything to keep, v4.14.x/v4.19.x/v5.4.x ā€˜workingā€™ let me know which version we need to buildā€¦

The readmeā€™s kinda suck so we need to look at commits: Gitweb @ Texas Instruments - Open Source Git Repositories - git.TI.com/gitweb - pru-software-support-package/pru-software-support-package.git/shortlog

Regards,

Iā€™m updating my master microSD card so Iā€™d like to get the latest supported PRU software support package on it while I am doing this. Iā€™m currently on

Linux beaglebone 4.19.94-ti-r64 #1buster SMP PREEMPT Fri May 21 23:57:28 UTC 2021 armv7l GNU/Linux

I am doing

sudo apt update
sudo apt install bbb.io-kernel-4.19-ti-am335x
sudo reboot

as you suggested on another topic/thread to fix a problem with pin configs.

What do I need to do to get the latest PRU Software Support package on this image @robertcnelson?

git clone https://git.ti.com/git/pru-software-support-package/pru-software-support-package.git
cd ./pru-software-support-package
git checkout <tag> -b tmp
voodoo@hestia:~/pru-software-support-package$ git tag 
v2.0.0
v3.0.0
v4.0.0
v4.0.1
v4.0.2
v5.0.0
v5.0.1
v5.1.0
v5.2.0
v5.2.1
v5.3.0
v5.4.0
v5.5.0
v5.6.0
v5.7.0
v5.8.0
v5.9.0
v6.0.0
v6.0.1

We know v6.0.1 and v6.0.0 only work on v5.10.x

So start with v5.9.0 and work older till it works with v4.19.x, when it works let me know an iā€™ll make a deb packageā€¦

Regards,

Thanks. Iā€™ve downloaded it.

Iā€™m thinking the simplest way to test these is to modify the Makefile to point to the directory where this repo is cloned to on my dev BBB. Then as I check out various tagged commits and try them, my primary existing pru-software-support-package directory is left alone. Is this the best way?

I did this with v5.9.0 and an existing program set that we have for the PRU and ARM work together to send messages back and forth. Nothing broke but I canā€™t absolutely confirm that I compiled the PRU code with the v5.9.0 library.

@RobertCNelson I am not sure if I am testing this the best way or not. I believe I have compiled some existing pru code for pru0 using v5.9.0 and it works like the version compiled with our prior version of the pru-software-support-package. Just to make sure I was actually pointing to the latest codeā€™s directory, I checkedout v6.0.0 and tried to compile the same code and got these errors immediately.

"/var/lib/cloud9/common/resource_table_0.h", line 60: error #71: incomplete type is not allowed
"/var/lib/cloud9/common/resource_table_0.h", line 129: error #71: incomplete type is not allowed
"/var/lib/cloud9/common/resource_table_0.h", line 131: error #28: expression must have a constant value

Mainly all I think I accomplished is to prove that Iā€™m pointing to different versions of the pru-software-support-package.

As far as I know, we donā€™t have code that uses every single feature of the remoteproc capability. We just send text back and forth. That seems to be working with v5.9.0 and in fact seems to be a little bit faster than it ran when compiled with the older version.

What other tests can I run to determine itā€™s compatible with 4.19.94-ti-r68. I want to be helpful but not give a false test report inadvertently.

@RobertCNelson We have been working with v5.9.0 for a day and a half and everything seems to be working fine with this version of the remoteproc library and 4.19. If anything, the virtual io seems to be a bit faster.