July 11, 2020


Working with rpmsg on PRU0 and PRU1

Introduction

Beaglebone boards are an example of Heterogenous computing systems . Such systems refers to systems that use more than one kind of processors or cores. The objective of deploying different architectures can be to gain performance or energy efficiency by adding dissimilar coprocessors. In the beaglbone boards one of the coprocessors implemented is called PRUs. There are two of these termed as PRU0 and PRU1 and are used to perform tasks where real time performence is required.

In order to establish communication between the two RPMsg framework is used. It is based on virtio vrings to send/receive messages to/from the remote CPU over shared memory.The vrings are uni-directional, one vring is dedicated to messages sent to the remote processor, and the other vring is used for messages received from the remote processor. In addition, shared buffers are created in memory space visible to both processors.The Mailbox framework is then used to notify cores when new messages are waiting in the shared buffers. Relying on these frameworks, The RPMsg framework implements a communication based on channels. The channels are identified by a textual name and have a local (“source”) RPMsg address, and a remote (“destination”) RPMsg address”. Recently i wanted to implement communication between PRU0 and ARM core. I started with the Ultrasonic sensor example. Here you can see the Rpmsg fuctionality is implemented on the PRU1 core.But I wanted write my own code that could run on PRU0 as most of the enhanced PRU pins exposed on the header of pocketbeagle belongs to PRU0. In my further investigation i figured out some important aspects that one need to keep me mind to succeed in porting or implmenting rpmsg on any PRU core. Here i will be showing the changes that one should make in the ultrasonic sensor code to run it on Core0 and in the process you would understand some important aspects.

Broadly speaking when the code is loaded in the PRU using remoteproc, a channel is created with the name defined in the CHAN_NAME. Setting right value to it is very important as it determines which kernal module will be probed and used. Moreover, system events are configured using TO_ARM_HOST and FROM_ARM_HOST. Further whenever ARM core writes to shared memory it sets the interrupt pin, There is bit 31 of r31 register for PRU1 interrupt and bit 30 for PRU0.

Configuration for PRU1

#define HOST_INT ((uint32_t) 1 << 31)
#define TO_ARM_HOST 18
#define FROM_ARM_HOST 19
#define CHAN_NAME "rpmsg-pru"
#define CHAN_DESC "Channel 31"
#define CHAN_PORT 31

Apart from this you will have a resoure_table_1.h file included in your main file. This file also has 2 important sections which need to be configured with specific values as shown.

Mapping ofsystem events to a channel. Each pair contains a sysevt, channel.>

struct ch_map pru_intc_map[] = { {18, 3},
{19, 1}, };

Channel-to-host mapping, 255 is used for unused Mapping Channel-1 to Host-1 (PRU0/1 R31 bit 31), HOST_UNUSED represents 255

{ HOST_UNUSED, 1, HOST_UNUSED, 3, HOST_UNUSED,
HOST_UNUSED, HOST_UNUSED, HOST_UNUSED, HOST_UNUSED, HOST_UNUSED
},

Configuration For PRU0

#define HOST_INT ((uint32_t) 1 << 30)
#define TO_ARM_HOST 16
#define FROM_ARM_HOST 17
#define CHAN_NAME "rpmsg-pru"
#define CHAN_DESC "Channel 30"
#define CHAN_PORT 30

Similarly resource_table_0 file need to have following values
Mapping ofsystem events to a channel. Each pair contains a sysevt, channel.>

struct ch_map pru_intc_map[] = { {16, 2},
{17, 0}, };

Channel-to-host mapping, 255 is used for unused Mapping Channel-0 to Host-0 HOST_UNUSED represents 255

{ 0, HOST_UNUSED, 2, HOST_UNUSED, HOST_UNUSED,
HOST_UNUSED, HOST_UNUSED, HOST_UNUSED, HOST_UNUSED, HOST_UNUSED
},

I have also created a patch to automatically make the changes and port the code in the repository to run on PRU0. Patch using the instructions in README

TI resource file links