BeagleY-AI and the C7x coprocessor

Olof Astrand
14 min readJul 17, 2024

--

overview of edge ai apps

Here I will look more into detail of how to communicate with the AM67A coprocessor on the beagleY-AI board. Note that I do not guarante that you break anything by using this information. Hopefully better documentation and support will be available at a later date.

The name of the chip on the beagleY-AI is called AM67A or J722S as it is part of the jacinto 7 family. Note that this article is not a guide. At the time of writing not TI or beagleboard.org has support for the beagleY-AI yet.

The AI algorithm performance is a key differentiator to Raspberry Pi 5, unfortunately it is not so easy to use this yet. This article demonstrates my efforts.

https://software-dl.ti.com/jacinto7/esd/processor-sdk-linux-am67a/09_02_00/exports/docs/linux/Foundational_Components_IPC_J722S.html

Download and install

You need to download the following,

ti-processor-sdk-linux-edgeai-j722s-evm-09_02_00_05-Linux-x86-Install.bin
ti-processor-sdk-linux-j722s-evm-09_02_00_04-Linux-x86-Install.bin

The ti-processor-sdk-linux-j722s-evm-09_02_00_04-Linux-x86-Install.bin is mainly for building an yocoto image.

The ./setup.sh installs the following packages xinetd tftpd nfs-kernel-server minicom libncurses5-dev lrzsz lzop swig u-boot-tools u-boot-tools

And some other tools that are normally installed on a developer machine.

I recomend that you do not install it.

Source code

This is the kernel sources for the bagleY-AI.

IPC

We clone this repo,

git clone https://git.ti.com/cgit/rpmsg/ti-rpmsg-char

The library is already installed on target.

Some hand on tests,

root@BeagleY:/home/olof/work/coprocessor# echo start > /sys/class/remoteproc/remoteproc0/state

[ 4565.061180] remoteproc remoteproc0: powering up 7e000000.dsp
[ 4565.061274] remoteproc remoteproc0: Direct firmware load for j722s-c71_0-fw failed with error -2
[ 4565.061291] remoteproc remoteproc0: request_firmware failed: -2
[ 4565.067422] remoteproc remoteproc0: Boot failed: -2
[ 4853.369596] Deferred event dump:00000000: 00000100 00100003 00070001 00820000
[ 4853.369621] Deferred event dump:00000030: 00000000 00000000 00000000 00000000
[ 4985.040811] remoteproc remoteproc1: powering up 7e200000.dsp
[ 4985.040908] remoteproc remoteproc1: Direct firmware load for j722s-c71_1-fw failed with error -2
[ 4985.040925] remoteproc remoteproc1: request_firmware failed: -2
[ 4985.047010] remoteproc remoteproc1: Boot failed: -2
If you copy the firmware ./vx_app_rtos_linux_c7x_1.out /usr/lib/firmware/j722s-c71_0-fw

[ 1615.074238] remoteproc remoteproc0: powering up 7e000000.dsp
[ 1615.089783] remoteproc remoteproc0: Booting fw image j722s-c71_0-fw, size 11722864
[ 1615.090518] remoteproc remoteproc0: bad phdr da 0xad100000 mem 0x8c
[ 1615.096876] remoteproc remoteproc0: Failed to load program segments: -22
[ 1615.106574] remoteproc remoteproc0: Boot failed: -22

It seems like the firmware does not match the booted kernel.

  1. “bad phdr” stands for “bad program header.”
  2. “da 0xad100000” represents the destination address where the firmware segment is supposed to be loaded in the remote processor’s memory.
  3. “mem 0x8c” likely refers to the size of the memory segment that couldn’t be properly mapped or loaded.

https://e2e.ti.com/support/processors-group/processors/f/processors-forum/1193620/faq-am62x-am64x-how-to-allow-linux-to-load-m4f-r5f-firmware-by-adding-a-resource-table

Elf headers from firmware

We can look at this example

more /opt/ti-psdk-firmware-09.02.00.05/j722s/vision_apps_eaik/install-j722s.sh how the coprocessor firmware is set.

#!/bin/bash

if ! id | grep -q root; then
echo "./install-j722s.sh must be run as root:"
echo "sudo ./install-j722s.sh"
exit
fi

cd /opt/ti-psdk-firmware-09.02.00.05/j722s/vision_apps_eaik/

cp -v ./vx_app_rtos_linux_c7x_1.out /usr/lib/firmware/j722s-c71_0-fw
cp -v ./vx_app_rtos_linux_c7x_2.out /usr/lib/firmware/j722s-c71_1-fw
cp -v ./vx_app_rtos_linux_mcu2_0.out /usr/lib/firmware/j722s-main-r5f0_0-fw

update-initramfs -uk `uname -r`
cp -v /boot/initrd.img-`uname -r` /boot/firmware/initrd.img

rpmsg char library

 dpkg -L ti-rpmsg-char
/.
/usr
/usr/include
/usr/include/rproc_id.h
/usr/include/ti_rpmsg_char.h
/usr/lib
/usr/lib/aarch64-linux-gnu
/usr/lib/aarch64-linux-gnu/libti_rpmsg_char.a
/usr/lib/aarch64-linux-gnu/libti_rpmsg_char.la
/usr/lib/aarch64-linux-gnu/libti_rpmsg_char.so.0.6.6
/usr/share
/usr/share/doc
/usr/share/doc/ti-rpmsg-char
/usr/share/doc/ti-rpmsg-char/changelog.Debian.gz
/usr/lib/aarch64-linux-gnu/libti_rpmsg_char.so
/usr/lib/aarch64-linux-gnu/libti_rpmsg_char.so.0
gcc rpmsg_char_simple.c  -l ti_rpmsg_char

/* Simple Example application using rpmsg-char library
*
* Copyright (c) 2020 Texas Instruments Incorporated - https://www.ti.com
*/

#include <sys/select.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <stdint.h>
#include <stddef.h>
#include <fcntl.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <time.h>
#include <stdbool.h>
#include <semaphore.h>

#include <linux/rpmsg.h>
#include <ti_rpmsg_char.h>

#define NUM_ITERATIONS 100
#define REMOTE_ENDPT 14

int send_msg(int fd, char *msg, int len)
{
int ret = 0;

ret = write(fd, msg, len);
if (ret < 0) {
perror("Can't write to rpmsg endpt device\n");
return -1;
}

return ret;
}

int recv_msg(int fd, int len, char *reply_msg, int *reply_len)
{
int ret = 0;

/* Note: len should be max length of response expected */
ret = read(fd, reply_msg, len);
if (ret < 0) {
perror("Can't read from rpmsg endpt device\n");
return -1;
} else {
*reply_len = ret;
}

return 0;
}

/* single thread communicating with a single endpoint */
int rpmsg_char_ping(int rproc_id, char *dev_name, unsigned int local_endpt, unsigned int remote_endpt,
int num_msgs)
{
int ret = 0;
int i = 0;
int packet_len;
char eptdev_name[64] = { 0 };
char packet_buf[512] = { 0 };
rpmsg_char_dev_t *rcdev;
int flags = 0;
struct timespec ts_current;
struct timespec ts_end;

/*
* Open the remote rpmsg device identified by dev_name and bind the
* device to a local end-point used for receiving messages from
* remote processor
*/
sprintf(eptdev_name, "rpmsg-char-%d-%d", rproc_id, getpid());
rcdev = rpmsg_char_open(rproc_id, dev_name, local_endpt, remote_endpt,
eptdev_name, flags);
if (!rcdev) {
perror("Can't create an endpoint device");
return -EPERM;
}
printf("Created endpt device %s, fd = %d port = %d\n", eptdev_name,
rcdev->fd, rcdev->endpt);

printf("Exchanging %d messages with rpmsg device %s on rproc id %d ...\n\n",
num_msgs, eptdev_name, rproc_id);

for (i = 0; i < num_msgs; i++) {
memset(packet_buf, 0, sizeof(packet_buf));
sprintf(packet_buf, "hello there %d!", i);
packet_len = strlen(packet_buf);
printf("Sending message #%d: %s\n", i, packet_buf);
clock_gettime(CLOCK_MONOTONIC, &ts_current);
ret = send_msg(rcdev->fd, (char *)packet_buf, packet_len);
if (ret < 0) {
printf("send_msg failed for iteration %d, ret = %d\n", i, ret);
goto out;
}
if (ret != packet_len) {
printf("bytes written does not match send request, ret = %d, packet_len = %d\n",
i, ret);
goto out;
}

ret = recv_msg(rcdev->fd, 256, (char *)packet_buf, &packet_len);
clock_gettime(CLOCK_MONOTONIC, &ts_end);
if (ret < 0) {
printf("recv_msg failed for iteration %d, ret = %d\n", i, ret);
goto out;
}
printf("Received message #%d: round trip delay(usecs) = %ld\n", i,ts_end.tv_nsec - ts_current.tv_nsec);
/* TODO: Verify data integrity */

/* TODO: Reduce number of prints */
printf("%s\n", packet_buf);
}

printf("\nCommunicated %d messages successfully on %s\n\n",
num_msgs, eptdev_name);

out:
ret = rpmsg_char_close(rcdev);
if (ret < 0)
perror("Can't delete the endpoint device\n");

return ret;
}

void usage()
{
printf("Usage: rpmsg_char_simple [-r <rproc_id>] [-n <num_msgs>] [-d \
<rpmsg_dev_name] [-p <remote_endpt] [-l <local_endpt] \n");
printf("\t\tDefaults: rproc_id: 0 num_msgs: %d rpmsg_dev_name: NULL remote_endpt: %d\n",
NUM_ITERATIONS, REMOTE_ENDPT);
}

int main(int argc, char *argv[])
{
int ret, status, c;
int rproc_id = 0;
int num_msgs = NUM_ITERATIONS;
unsigned int remote_endpt = REMOTE_ENDPT;
unsigned int local_endpt = RPMSG_ADDR_ANY;
char *dev_name = NULL;

while (1) {
c = getopt(argc, argv, "r:n:p:d:l:");
if (c == -1)
break;

switch (c) {
case 'r':
rproc_id = atoi(optarg);
break;
case 'n':
num_msgs = atoi(optarg);
break;
case 'p':
remote_endpt = atoi(optarg);
break;
case 'd':
dev_name = optarg;
break;
case 'l':
local_endpt = atoi(optarg);
break;
default:
usage();
exit(0);
}
}

if (rproc_id < 0 || rproc_id >= RPROC_ID_MAX) {
printf("Invalid rproc id %d, should be less than %d\n",
rproc_id, RPROC_ID_MAX);
usage();
return 1;
}

/* Use auto-detection for SoC */
ret = rpmsg_char_init(NULL);
if (ret) {
printf("rpmsg_char_init failed, ret = %d\n", ret);
return ret;
}

status = rpmsg_char_ping(rproc_id, dev_name, local_endpt, remote_endpt, num_msgs);

rpmsg_char_exit();

if (status < 0) {
printf("TEST STATUS: FAILED\n");
} else {
printf("TEST STATUS: PASSED\n");
}

return 0;
}

Check available endpoints like this,

k3conf dump processor
|--------------------------------------------------------------------------------|
| VERSION INFO |
|--------------------------------------------------------------------------------|
| K3CONF | (version 0.3-nogit built Wed Mar 27 21:29:14 UTC 2024) |
| SoC | J722S SR1.0 |
| SYSFW | ABI: 3.1 (firmware version 0x0009 '9.0.6--w2023.01-j722s (Kool Koa)') |
|--------------------------------------------------------------------------------|

|------------------------------------------------------------------------------------------|
| Device ID | Processor ID | Processor Name | Processor State | Processor Frequency |
|------------------------------------------------------------------------------------------|
| 121 | 1 | WKUP_R5FSS0_CORE0 | DEVICE_STATE_ON | 800000000 |
| 9 | 3 | MCU_R5FSS0_CORE0 | DEVICE_STATE_OFF | 800000000 |
| 262 | 4 | R5FSS0_CORE0 | DEVICE_STATE_OFF | 800000000 |
| 135 | 32 | A53SS0_CORE_0 | DEVICE_STATE_ON | 1250000000 |
| 136 | 33 | A53SS0_CORE_1 | DEVICE_STATE_ON | 1250000000 |
| 137 | 34 | A53SS0_CORE_2 | DEVICE_STATE_ON | 1250000000 |
| 138 | 35 | A53SS0_CORE_3 | DEVICE_STATE_ON | 1250000000 |
| 208 | 48 | C7X256V0_C7XV_CORE_0 | DEVICE_STATE_OFF | 1000000000 |
| 268 | 49 | C7X256V1_C7XV_CORE_0 | DEVICE_STATE_OFF | 1000000000 |
| 225 | 128 | HSM0 | DEVICE_STATE_ON | 500000000 |
|------------------------------------------------------------------------------------------|

dmesg | grep rpmsg
[ 13.406159] virtio_rpmsg_bus virtio0: rpmsg host is online
[ 13.406618] virtio_rpmsg_bus virtio0: creating channel ti.ipc4.ping-pong addr 0xd
[ 13.406830] virtio_rpmsg_bus virtio0: creating channel rpmsg_chrdev addr 0xe

It seems like the bootloader installed a ping-pong firmware on the WKUP core. Not sure why number 15 works here, but you can do this.

sudo ./a.out -r 15 -n 4
Created endpt device rpmsg-char-15-1860, fd = 4 port = 1025
Exchanging 4 messages with rpmsg device rpmsg-char-15-1860 on rproc id 15 ...

Sending message #0: hello there 0!
Received message #0: round trip delay(usecs) = 117267
hello there 0!
Sending message #1: hello there 1!
Received message #1: round trip delay(usecs) = 69056
hello there 1!
Sending message #2: hello there 2!
Received message #2: round trip delay(usecs) = 473871
hello there 2!
Sending message #3: hello there 3!
Received message #3: round trip delay(usecs) = 82266
hello there 3!

Communicated 4 messages successfully on rpmsg-char-15-1860

TEST STATUS: PASSED

In order to build a process that replies to this, we need the compiler for the DSP. And also most likely a memory map for the coprocessors that matches the one in our device tree. https://openbeagle.org/beagleboard/BeagleBoard-DeviceTrees/-/blob/v6.1.x-Beagle/src/arm64/ti/k3-am67a-beagley-ai.dts?ref_type=heads

Here is the ti yocoto device tree as reference.

https://git.ti.com/cgit/ti-linux-kernel/ti-linux-kernel/tree/arch/arm64/boot/dts/ti/k3-j722s-evm.dts?h=ti-linux-6.1.y

It seems like things are also abit confused for the AI-64 https://forum.beagleboard.org/t/beaglebone-ai-64-c7x-mma-programming-details/33890

Check available packages ,

apt-cache search . | grep ‘^ti’

Clone and compile accelerated gst plugins

This is most easily done on the board. However SOC=AM67A is not yet supported. SOC=j722s works.

sudo apt-get install gstreamer1.0-dev meson  libgstreamer-plugins-base1.0-dev  
libgstreamer1.0-dev
export SOC=j722s
meson build --prefix=/usr -Dpkg_config_path=pkgconfig

gst-inspect-1.0 tiovx

We get from ../gst-libs/gst/tiovx/gsttiovximagebufferpool.c:66:
../gst-libs/gst/tiovx/gsttiovxbufferpool.h:70:10: fatal error: TI/tivx.h: No such file or directory
70 | #include <TI/tivx.h>

But it exists in ./ti/ti-processor-sdk-rtos-j722s-evm-09_02_00_05/tiovx/include/TI/tivx.h

I give up at this point, but could get you started.

Download dsp compiler

Build TIDL tools

sudo apt-get install libyaml-cpp-dev
git clone https://github.com/TexasInstruments/edgeai-tidl-tools.git
cd edgeai-tidl-tools
git checkout rel_09_02
export SOC=am67a
source ./setup.sh
#
cd edgeai-tidl-tools
export SOC=am67a
export TIDL_TOOLS_PATH=$(pwd)/tidl_tools
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$TIDL_TOOLS_PATH
export ARM64_GCC_PATH=$(pwd)/gcc-arm-9.2-2019.12-x86_64-aarch64-none-linux-gnu

Building apache TVM

git clone https://github.com/TexasInstruments/tvm.git

git submodule update ;git submodule init

mkdir build ; cd build; cp ../cmake/config.cmake

sudo apt-get install llvm-15-dev
sudo apt-get install libc6-dev-arm64-cross linux-libc-dev-arm64-cross
sudo apt-get install qemu-user

Make sure the following is set in config.cmake

set(USE_LLVM /usr/bin/llvm-config-15)

Update: August,

git switch tidl-j7

This branch seems to support J722S

These are the changed files that made this possible.

CMakeLists.txt                                                               |  1 +
python/tvm/contrib/tidl/c7x.py | 3 ++-
python/tvm/contrib/tidl/compile.py | 2 +-
python/tvm/relay/backend/contrib/tidl/build_c7x_mod.py | 4 +++-
python/tvm/topi/c7x/injective.py | 2 +-
python/tvm/topi/c7x/pooling.py | 2 +-
src/relay/backend/contrib/tidl/codegen.cc | 3 ++-
src/runtime/contrib/tidl/c7x/CMakeLists.txt | 13 +++++++++++++
src/runtime/contrib/tidl/c7x/Makefile.c7x_mod | 2 ++
src/runtime/contrib/tidl/c7x/bundle_static.c | 2 +-
src/runtime/contrib/tidl/c7x/c7x_tvm_runtime.h | 4 ++--
src/runtime/contrib/tidl/c7x/make.inc | 3 +++
src/runtime/contrib/tidl/c7x/py_dist_files.txt | 4 ++++
src/runtime/contrib/tidl/c7x/tidl_api.c | 2 +-
src/runtime/contrib/tidl/c7x/tvm_tidl_dmautils.c | 5 +++++
src/runtime/contrib/tidl/tidl_runtime.cc | 12 ++++++++----

ti_build.sh

export PSDKR_PATH=${HOME}/ti/ti-processor-sdk-rtos-j722s-evm-09_02_00_05

export EVM_IP=192.168.1.33

export TVM_DEPS_PATH=${HOME}/ti

/home/olof/ti/psdk_rtos_auto_j7_06_02_00_21/tidl_j7_01_01_00_10

Finally the scripts does someting like this, cmake -DCMAKE_EXPORT_COMPILE_COMMANDS=YES -DUSE_MICRO=ON -DUSE_SORT=ON -DUSE_TIDL=ON ‘-DUSE_LLVM=llvm-config-15 — link-static’ -DHIDE_PRIVATE_SYMBOLS=ON -DUSE_TIDL_RT_PATH=/home/olas/ti/psdk_rtos_auto_j7_06_02_00_21/tidl_j7_01_01_00_10 -DHIDE_PRIVATE_SYMBOLS=ON -DUSE_TIDL_RT_PATH=/home/olas/ti/ti-processor-sdk-rtos-j722s-evm-09_02_00_05/c7x-mma-tidl/arm-tidl/rt/ -DUSE_TIDL_P
SDKR_PATH=/home/olof/ti/psdk_rtos_auto_j7_06_02_00_21 -DUSE_CGT7X_ROOT=/home/olof/ti/ti-cgt-c7000_4.1.0.LTS ..

in the tvm/build directory. Still no success building here.

From the page; We are making BeagleY-AI available to thousands of developers on June 1, 2024 and the AI algorithm performance is a key differentiator to Raspberry Pi 5. We need to be able to demonstrate this function in the multitude of OS images available for running on Raspberry Pi, otherwise the performance of the AM67A TI processor will look bad.

not good news

Back to basics

Edge AI tools

No need to build unless you want to run tests.

sudo apt-get install libyaml-cpp-dev
export SOC=am67a
source ./setup.sh
export TIDL_TOOLS_PATH=$(pwd)/tidl_tools
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$TIDL_TOOLS_PATH
mkdir build
cd build

Compile and validate on pc

mkdir build && cd build
cmake ../examples && make -j && cd ..
source ./scripts/run_python_examples.sh
python3 ./scripts/gen_test_report.py

Test report

 more test_report_pc_am67a.csv
Completed_Model,Name,Output File,Functional,info,rt type
0,cl-tfl-mobilenet_v1_1.0_224,py_out_cl-tfl-mobilenet_v1_1.0_224_airshow.jpg,FAIL,output file mismatch,tfl-py
1,ss-tfl-deeplabv3_mnv2_ade20k_float,py_out_ss-tfl-deeplabv3_mnv2_ade20k_float_ADE_val_00001801.jpg,PASS,,tfl-py
2,od-tfl-ssd_mobilenet_v2_300_float,py_out_od-tfl-ssd_mobilenet_v2_300_float_ADE_val_00001801.jpg,PASS,,tfl-py
3,od-tfl-ssdlite_mobiledet_dsp_320x320_coco,py_out_od-tfl-ssdlite_mobiledet_dsp_320x320_coco_ADE_val_00001801.jpg,PASS,,
tfl-py
4,cl-ort-resnet18-v1,py_out_cl-ort-resnet18-v1_airshow.jpg,FAIL,output file mismatch,ort-py
5,od-ort-ssd-lite_mobilenetv2_fpn,py_out_od-ort-ssd-lite_mobilenetv2_fpn_ADE_val_00001801.jpg,PASS,,ort-py
6,cl-tfl-mobilenet_v1_1.0_224,cpp_out_cl-tfl-mobilenet_v1_1.0_224.jpg,PASS,,tfl-cpp
7,ss-tfl-deeplabv3_mnv2_ade20k_float,cpp_out_ss-tfl-deeplabv3_mnv2_ade20k_float.jpg,PASS,,tfl-cpp
8,cl-ort-resnet18-v1,cpp_out_cl-ort-resnet18-v1.jpg,PASS,,ort-cpp
9,od-ort-ssd-lite_mobilenetv2_fpn,cpp_out_od-ort-ssd-lite_mobilenetv2_fpn.jpg,PASS,,ort-cpp

Copy files to board

scp -r model-artifacts olof@192.x.x.x:/home/olof/edgeai-tidl-tool/
scp -r models olof@192.x.x.x:/home/olof/edgeai-tidl-tool

Unfortunately I do not think this is supported on the BeagleY-AI yet.

export DEVICE=j7
export SOC=am67a
source ./setup.sh
mkdir build && cd build
cmake ../examples && make -j && cd ..

~/edgeai-tidl-tools/examples/osrt_cpp/post_process/post_process.h:77:10: fatal error: tensorflow/lite/kernels/register.h: No such file or directory
77 | #include <tensorflow/lite/kernels/register.h>
./scripts/run_python_examples.sh

Here are some instructions for you, https://software-dl.ti.com/jacinto7/esd/processor-sdk-rtos-j722s/09_02_00_05/exports/docs/vision_apps/docs/user_guide/BUILD_INSTRUCTIONS.html#QUICK_SETUP_STEPS_LINUX_TI_RTOS

Compile a pong program for the dsp

Install code composer studio

Only the last options is really required. Here is a simple program

#include <c7x.h>
#include <drivers/ipc_rpmsg.h>
#include <kernel/dpl/DebugP.h>

/* Below code is for reference, recommended to use SysCfg to generate this code */

/* Below is common code for all the CPUs participating in this IPC */
#define NUM_CPUS (4u)
#define VRING_NUM (NUM_CPUS*(NUM_CPUS-1))
#define VRING_NUM_BUF (8u)
#define VRING_MAX_MSG_SIZE (128u)

/* Size of each VRING is
* number of buffers x ( size of each buffer + space for data structures of one buffer (32B) )
*/
#define VRING_SIZE RPMESSAGE_VRING_SIZE(VRING_NUM_BUF, VRING_MAX_MSG_SIZE)

/* Make sure of below,
* - The section defined below should be placed at the exact same location in memory for all the CPUs
* - the memory should be marked as non-cached for all the CPUs
* - the section should be marked as NOLOAD in all the CPUs linker command file
*/
unsigned char gVringMem[VRING_NUM][VRING_SIZE] __attribute__((aligned(8192), section(".bss.sharedmemory")));

/* All RPMessage_Object MUST be global */
RPMessage_Object gRecvMsgObject;

void print_message(const char* msg) {
/* Replace this with the appropriate method to output messages on your system */
DebugP_log("[C7x DSP] %s\n", msg);
}

int main(void) {
RPMessage_CreateParams createParams;
int status;

/* Initialize the RPMessage */
status = RPMessage_init(0); /* 0 is typically used for the C7x DSP core */
if (status != SystemP_SUCCESS) {
print_message("RPMessage_init failed");
return -1;
}

RPMessage_CreateParams_init(&createParams);
createParams.localEndPt = 13; /* Pick any unique value on that core between 0..RPMESSAGE_MAX_LOCAL_ENDPT-1
* The value need not be unique across cores
*/
status = RPMessage_construct(&gRecvMsgObject, &createParams);
if (status != SystemP_SUCCESS) {
print_message("RPMessage_construct failed");
return -1;
}

print_message("C7x DSP: RPMessage initialized and constructed");

while(1)
{
char recvMsg[64];
char replyMsg[64];
uint16_t recvMsgSize, remoteCoreId, remoteCoreEndPt;

/* Wait for messages forever in a loop */
/* Set 'recvMsgSize' to size of recv buffer,
* after return `recvMsgSize` contains actual size of valid data in recv buffer
*/
recvMsgSize = sizeof(recvMsg);
status = RPMessage_recv(&gRecvMsgObject,
recvMsg, &recvMsgSize,
&remoteCoreId, &remoteCoreEndPt,
SystemP_WAIT_FOREVER);

if (status == SystemP_SUCCESS) {
print_message("Received message");
print_message(recvMsg);

/* Echo the message string as reply */
snprintf(replyMsg, sizeof(replyMsg), "C7x DSP Echo: %s", recvMsg);

/* Send reply to sender CPU at the sender end point */
status = RPMessage_send(
replyMsg, strlen(replyMsg) + 1,
remoteCoreId, remoteCoreEndPt,
RPMessage_getLocalEndPt(&gRecvMsgObject),
SystemP_WAIT_FOREVER);

if (status != SystemP_SUCCESS) {
print_message("Failed to send reply");
} else {
print_message("Reply sent");
}
} else {
print_message("Failed to receive message");
}
}

/* This point is never reached, but if we did exit the loop: */
RPMessage_destruct(&gRecvMsgObject);
return 0;
}

c7_mem_map.cmd

MEMORY
{
/* L3 for C7x_1 [ size 2.00 MB ] */
L2RAM_C7x_1_MAIN ( RWIX ) : ORIGIN = 0x7E000000 , LENGTH = 0x00200000
/* L2 for C7x_1 [ size 240.00 KB ] */
L2RAM_C7x_1_AUX ( RWIX ) : ORIGIN = 0x7F000000 , LENGTH = 0x0003C000
/* L1 for C7x_1 [ size 16.00 KB ] */
L2RAM_C7x_1_AUX_AS_L1 ( RWIX ) : ORIGIN = 0x7F03C000 , LENGTH = 0x00004000
/* Memory for IPC Vring's. MUST be non-cached or cache-coherent [ size 32.00 MB ] */
IPC_VRING_MEM ( RWIX ) : ORIGIN = 0xA5000000 , LENGTH = 0x02000000
/* C7x_1 memory region as specified in the device tree */
C7X_1_MEMORY ( RWIX ) : ORIGIN = 0xA4100000 , LENGTH = 0x00F00000
/* DDR for C7x_1 for code/data [ size 57.98 MB ] */
DDR_C7x_1 ( RWIX ) : ORIGIN = 0xAD604000 , LENGTH = 0x039FC000
/* DDR for c7x_1 for local heap [ size 112.00 MB ] */
DDR_C7X_1_LOCAL_HEAP ( RWIX ) : ORIGIN = 0x102000000 , LENGTH = 0x07000000
/* DDR for c7x_1 for Scratch Memory [ size 112.00 MB ] */
DDR_C7X_1_SCRATCH ( RWIX ) : ORIGIN = 0x109000000 , LENGTH = 0x07000000
}

export CGT7X_ROOT=/home/olof/ti/ti-cgt-c7000_4.1.0.LTS/
cl7x -z c7_mem_map.cmd -mv7504 -I$CGT7X_ROOT/include -I/home/olof/ti/ti-processor-sdk-rtos-j722s-evm-09_02_00_05/mcu_plus_sdk_j722s_09_02_00_59/source --warn_sections --display_error_number --diag_wrap=off --ram_model -o "c7x_rpmsg_example.out" test.c -l$CGT7X_ROOT/lib/libc.a
This worked better
cl7x -mv7524 --abi=eabi -I/home/olof/ti/ti-cgt-c7000_4.1.0.LTS/include -I/home/olof/ti/ti-cgt-c7000_4.1.0.LTS/include/libcxx -I/home/olof/ti/ti-processor-sdk-rtos-j722s-evm-09_02_00_05/mcu_plus_sdk_j722s_09_02_00_59/source/ --output_file c7x_test.out test.cpp -z --map_file=link.map -L/home/olof/ti/ti-cgt-c7000_4.1.0.LTS/lib/libc.a --library=c7_mem_map.cmd

Note that was not possible to compile or run, but should be something like this. CS7x hardware and interrupts must be set up properly also.

Look further in the processor-sdk-rtos in mcu_plus_sdk_j722s_09_02_00_59/examples/drivers/ipc/ipc_rpmsg_echo

No real success here either but I will continue this in another article.

--

--

Olof Astrand
Olof Astrand

Responses (5)