Is RPMsg the fastest possible option?

I’m checking how fast can I copy data from Beaglebone Black PRU to an userspace app on ARM. I’m using kernel v4.19 TI PREEMPT-RT.

So far I simply modified the PRU_RPMsg_Echo_Interrupt1 example from here: https://processors.wiki.ti.com/index.php/PRU_Training:_Hands-on_Labs#LAB_5:_RPMsg_Communication_between_ARM_and_PRU . Added IEP timer value as part of 480 byte message sent from PRU to ARM to check time delta between data dispatches. For RPMsg I’m using “rpmsg-pru” channel and on the ARM side in userspace app I’m reading the data from /dev/rpmsg_pru31 with function read() to get the data. In this configuration I’m reading the data on ARM side every 90us.

Here I wonder whether there is anything I could gather after writing custom kernel module (beaglelogic approach?) over using RPMsg character device. If yes, how much and what would be the best approach to collect the PRU data as quickly as possible?

I achieved decent throughput by using the standard RPMSG PRU driver with a larger buffer size (MAX_FIFO_MSG in rpmsg_pru.c changed from 32 to 4096) and by batching the PRU data into 496 byte chunks (512 byte RPMSG message - header).

There is a project using the DMA controller which might be a very fast option, I haven’t tested it yet (but it looks promising): https://github.com/maciejjo/beaglebone-pru-dma

IIRC there are other projects that use the second PRU for data shoveling instead.

Thank you for your reply. I’ve seen Maciej’s DMA project and it is certainly something I’d like to try myself, similarly as writing a kernel module with similar capabilities as beaglelogic (using remoteproc to boot pruss, exchanging data with pruss etc.). The problem I have right now is that since kernel v4.9 which Kumar used in his newer beaglelogic some things have changed (I’m using v4.19). For example the function pruss_get, which in 4.9 was taking two arguments, first of them being struct device, now takes one argument of type rproc. The thing is, I have no idea where to get a handle to rproc from or how to get pruss handle without providing rproc handle. I can’t see remoteproc defined anywhere in am335x-boneblack-uboot-univ.dts which I’m using and I don’t know how (and whether it’s a good way to go) to define it myself. I’ll appreciate any hints regarding this topic.

My overlay:

`

/dts-v1/;
/plugin/;

/ {
compatible = “ti,beaglebone”, “ti,beaglebone-black”, “ti,beaglebone-green”;

// identification
part-number = “DRONEDRIVER”;
version = “00A0”;

fragment@1 {
target-path="/";
overlay {
/* Add default settings for the LA core */
pru-dronedriver {
compatible = “dronedriver,dronedriver”;

pruss = <&pruss>;
interrupt-parent = <&pruss_intc>;
interrupts = <22>, <23>, <24>;
interrupt-names = “from_dd_1”, “to_dd”, “from_dd_2”;
};
};
};
};

`

Fragment of kernel module I’m trying to get to work:

`

static struct dronedriver_private_data dronedriver_pdata = {
.fw_names[0] = “am335x-pru0-fw”,
.fw_names[1] = “am335x-pru1-fw”,
};

static const struct of_device_id dronedriver_dt_ids[] = {
{ .compatible = “dronedriver,dronedriver”, .data = &dronedriver_pdata, },
{ /* sentinel */ },
};

MODULE_DEVICE_TABLE(of, dronedriver_dt_ids);

static int dronedriver_probe(struct platform_device *pdev)
{
struct rproc *rproc;
struct device_node *node = pdev->dev.of_node;

//if (!node)
// return -ENODEV; /* No support for non-DT platforms */
printk(KERN_INFO “[1]\n”);

match = of_match_device(dronedriver_dt_ids, &pdev->dev);
if (!match)
return -ENODEV;
printk(KERN_INFO “[2]\n”);

dddev = kzalloc(sizeof(*dddev), GFP_KERNEL);
if (!dddev)
{
ret = -1;
goto fail;
}
printk(KERN_INFO “[3]\n”);

dddev->fw_data = match->data;
dddev->miscdev.fops = &pru_dronedriver_fops;
dddev->miscdev.minor = MISC_DYNAMIC_MINOR;
dddev->miscdev.mode = S_IRUGO;
dddev->miscdev.name = “dronedriver”;
printk(KERN_INFO “[5]\n”);

dddev->p_dev = &pdev->dev;
dev_set_drvdata(dddev->p_dev, dddev);
printk(KERN_INFO “[6]\n”);

dev = &pdev->dev;
rproc = pru_rproc_get(node,NULL);
if(IS_ERR_OR_NULL(rproc))
{
ret = PTR_ERR(rproc);
if (ret != -EPROBE_DEFER)
dev_err(dev, “Unable to get rproc handle.\n”);
goto fail_free;
}

printk(KERN_INFO “[OK] pruss handle\n”);
printk(KERN_INFO “[OK] rproc:\nname = \n”, rproc->name);

dddev->pruss = pruss_get(rproc);

if (IS_ERR(dddev->pruss))
{
ret = PTR_ERR(dddev->pruss);
if (ret != -EPROBE_DEFER)
dev_err(dev, “Unable to get pruss handle.\n”);
goto fail_free;
}
goto fail_free;
printk(KERN_INFO “[OK] pruss handle\n”);


}

static int dronedriver_remove(struct platform_device *pdev)
{
return 0;
}

static struct platform_driver dronedriver_driver = {
.driver = {
.name = DRV_NAME,
.owner = THIS_MODULE,
.of_match_table = dronedriver_dt_ids,
},
.probe = dronedriver_probe,
.remove = dronedriver_remove,
};

module_platform_driver(dronedriver_driver);

`

After insmoding this module the last log in dmesg is “Unable to get rproc handle.”. Before I commented out checking “if (!node)” it wasn’t making it to [1] in dmesg. I don’t understand the relationship between device tree and kernel driver enough to tell why of_node is a null pointer here… Please, help.