Hello world on the C7x DSP coprocessor with the BeagleY-AI

Olof Astrand
10 min readAug 16, 2024

--

The uart debug log system on the AM67A is quite complex. In this article I will modify the hello world program by adding a resource table and loading the coprocessor code with the default beagleY-AI linux kernel from the 11/7.

Here you can find the modified example to be use with the beagleY-AI. https://github.com/Ebiroll/hello_beagley the precompiled binaries are in the dist subdirectory.

Here is a description about the debug log system.

https://www.ti.com/lit/an/spradg5/spradg5.pdf

I did not need this yet. Hopefully it will be aproved soon.

Request sent

Here is some useful information also.

Let us try again, with hello world example. You can see here how to build it. I added IPC and therefore the resource table was added.

wget https://dr-download.ti.com/software-development/software-development-kit-sdk/MD-1bSfTnVt5d/09.02.00.05/ti-processor-sdk-rtos-j722s-evm-09_02_00_05.tar.gz
unpack in ${HOME}/ti
export PSDKR_PATH=${HOME}/ti/ti-processor-sdk-rtos-j722s-evm-09_02_00_05
cd ${PSDKR_PATH}
./sdk_builder/scripts/setup_psdk_rtos.sh
cd sdk_builder
./make_sdk.sh
cd ~/ti/ti-processor-sdk-rtos-j722s-evm-09_02_00_05/mcu_plus_sdk_j722s_09_02_00_59


~/ti/ti-processor-sdk-rtos-j722s-evm-09_02_00_05/mcu_plus_sdk_j722s_09_02_00_59$ make -s -C examples/hello_world/j722s-evm/ syscfg-gui
Add IPC and check UART

Fix the linker.cmd for the c7x coprocessors.


--ram_model
-heap 0x20000
-stack 0x20000
--args 0x1000
--diag_suppress=10068 /* to suppress no matching section error */
--cinit_compression=off
-e _c_int00_secure

#define DDR0_ALLOCATED_START 0xA4000000

#define C7X_ALLOCATED_START DDR0_ALLOCATED_START

#define C7X_RESOURCE_TABLE_BASE (C7X_ALLOCATED_START + 0x00100000)
#define C7X_IPC_TRACE_BUFFER (C7X_ALLOCATED_START + 0x00100400)
#define C7X_BOOT_BASE (C7X_ALLOCATED_START + 0x00200000)
#define C7X_VECTOR_BASE (C7X_ALLOCATED_START + 0x00400000)
#define C7X_DDR_SPACE_BASE (C7X_ALLOCATED_START + 0x00410000)

MEMORY
{
L2SRAM (RWX): org = 0x7E200000, len = 0x200000
DDR0_RESERVED: org = 0x80000000, len = 0x19800000 /* Reserved for A53 OS */
C7X_IPC_D: org = C7X_ALLOCATED_START, len = 0x00100000 /* 1MB DDR */
C7X_BOOT_D: org = C7X_BOOT_BASE, len = 0x400 /* 1024B DDR */
C7X_VECS_D: org = C7X_VECTOR_BASE, len = 0x4000 /* 16KB DDR */
C7X_CIO_MEM: org = C7X_DDR_SPACE_BASE, len = 0x1000 /* 4KB */
C7X_DDR_SPACE: org = C7X_DDR_SPACE_BASE+0x1000, len = 0x00BF0000-0x1000 /* 11.9MB - 4KB DDR */
/* For resource table */
C7X_RT_D: org = C7X_RESOURCE_TABLE_BASE, len = 0x400 /* 1024B DDR */
/* IPC trace buffer */
LINUX_IPC_TRACE_BUFFER: org = C7X_IPC_TRACE_BUFFER, len = 0xFFC00 /* 1023KB DDR */
LOG_SHM_MEM : ORIGIN = 0xA7000000, LENGTH = 0x40000
/* Shared memory for RTOS NORTOS IPC */
RTOS_NORTOS_IPC_SHM_MEM: org = 0xA5000000, len = 0x1C00000 /* 8MB DDR */
}

SECTIONS
{
boot:
{
boot.*<boot.oe71>(.text)
} load > C7X_BOOT_D
.vecs > C7X_VECS_D
.secure_vecs > C7X_DDR_SPACE ALIGN(0x100000)
.text:_c_int00_secure > C7X_DDR_SPACE ALIGN(0x100000)
.text > C7X_DDR_SPACE ALIGN(0x100000)

.bss > C7X_DDR_SPACE /* Zero-initialized data */
RUN_START(__BSS_START)
RUN_END(__BSS_END)

.data > C7X_DDR_SPACE /* Initialized data */

.cinit > C7X_DDR_SPACE /* could be part of const */
.init_array > C7X_DDR_SPACE /* C++ initializations */
.stack > C7X_DDR_SPACE ALIGN(0x2000)
.args > C7X_DDR_SPACE
.cio > C7X_CIO_MEM
.const > C7X_DDR_SPACE
.switch > C7X_DDR_SPACE /* For exception handling. */
.sysmem > C7X_DDR_SPACE /* heap */

GROUP: > C7X_DDR_SPACE
{
.data.Mmu_tableArray : type=NOINIT
.data.Mmu_tableArraySlot : type=NOINIT
.data.Mmu_level1Table : type=NOINIT
.data.gMmu_tableArray_NS : type=NOINIT
.data.Mmu_tableArraySlot_NS : type=NOINIT
.data.Mmu_level1Table_NS : type=NOINIT
}

.benchmark_buffer: > C7X_DDR_SPACE ALIGN (32)

/* This is the resource table used by linux to know where the IPC "VRINGs" are located */
.resource_table: { __RESOURCE_TABLE = .;} > C7X_RT_D
/* This IPC log can be viewed via ROV in CCS and when linux is enabled, this log can also be viewed via linux debugfs */
.bss.debug_mem_trace_buf : {} palign(128) > LINUX_IPC_TRACE_BUFFER
/* this is used when Debug log's to shared memory is enabled, else this is not used */
.bss.log_shared_mem (NOLOAD) : {} > LOG_SHM_MEM
/* this is used only when IPC RPMessage is enabled */
.bss.ipc_vring_mem (NOLOAD) : {} > RTOS_NORTOS_IPC_SHM_MEM
}

After building the firmware again.

The Linux RemoteProc driver checks the remote core firmware for a resource table before it loads the firmware into a remote core. If the firmware does not have a resource table, then Linux will not load the firmware. That means that if we want to use Linux to load the “Hello World” example (or any example), then we need to make sure the project has a resource table in it.

 readelf -a j722s-c71_0-fw | grep res
Entry point address: 0xa3600000
[Nr] Name Type Address Offset
[23] .resource_table PROGBITS 00000000a3100000 00000400
C (compressed), x (unknown), o (OS specific), E (exclude),
00 .resource_table
23: 00000000a3100000 0 SECTION LOCAL DEFAULT 23 .resource_table
77: 00000000a3100000 0 SECTION LOCAL HIDDEN 23 .resource_table
 scp  examples/hello_world/j722s-evm/c75ss1-0_freertos/ti-c7000/hello_world.release.out olof@xx:/home/olof/hello_world/j722s-c71_0-fw
scp examples/hello_world/j722s-evm/c75ss0-0_freertos/ti-c7000/hello_world.release.out olof@xx:/home/olof/hello_world/j722s-c71_1-fw
scp examples/hello_world/j722s-evm/main-r5fss0-0_freertos/ti-arm-clang/hello_world.release.out olof@xx:/home/olof/hello_world/j722s-main-r5f0_0-fw
# Then on the beagleY-AI
sudo ln -s /home/olof/hello_world/j722s-main-r5f0_0-fw /lib/firmware/j722s-main-r5f0_0-fw
sudo ln -s /home/olof/hello_world/j722s-c71_0-fw /lib/firmware/j722s-c71_0-fw
sudo ln -s /home/olof/hello_world/j722s-mcu-r5f0_0-fw /lib/firmware/j722s-mcu-r5f0_0-fw

We try again starting the r4, echo start > /sys/class/remoteproc/remoteproc4/state

[ 1353.548490] remoteproc remoteproc4: powering up 78400000.r5f
[ 1353.549236] remoteproc remoteproc4: Booting fw image j722s-main-r5f0_0-fw, size 466352
[ 1353.549266] platform 78400000.r5f: iommu not present
[ 1353.549538] platform 78400000.r5f: leveraging h/w init for TCM memories
[ 1353.549556] remoteproc remoteproc4: rsc: type 3
[ 1353.549564] remoteproc remoteproc4: vdev rsc: id 7, dfeatures 0x1, cfg len 0, 2 vrings
[ 1353.550143] remoteproc remoteproc4: vdev rsc: vring0: da 0xffffffff, qsz 256, align 4096
[ 1353.550168] remoteproc remoteproc4: vdev rsc: vring1: da 0xffffffff, qsz 256, align 4096
[ 1353.550292] remoteproc remoteproc4: rsc: type 2
[ 1353.550395] remoteproc remoteproc4: trace0 added: da 0xa250aa80, len 0x1000
[ 1353.550414] remoteproc remoteproc4: carveout va 000000005c297977, dma 0x00000000a2000000, len 0x3000
[ 1353.550431] remoteproc remoteproc4: carveout va 000000004dff685e, dma 0x00000000a2004000, len 0x3000
[ 1353.551284] platform 78400000.r5f: booting R5F core using boot addr = 0x0
[ 1353.551521] rproc-virtio rproc-virtio.8.auto: assigned reserved memory node main-r5fss-dma-memory-region@a2000000
[ 1353.551563] virtio virtio1: reset !
[ 1353.551570] virtio virtio1: status: 1
[ 1353.551842] virtio_rpmsg_bus virtio1: status: 3
[ 1353.551875] remoteproc remoteproc4: vring0: va 000000005c297977 qsz 256 notifyid 0
[ 1353.551909] remoteproc remoteproc4: vring1: va 000000004dff685e qsz 256 notifyid 1
[ 1353.552859] virtio_rpmsg_bus virtio1: status: 7
[ 1353.552887] remoteproc remoteproc4: kicking vq index: 0
[ 1353.552899] virtio_rpmsg_bus virtio1: rpmsg host is online
[ 1353.552942] rproc-virtio rproc-virtio.8.auto: registered virtio1 (type 7)
[ 1353.552951] remoteproc remoteproc4: remote processor 78400000.r5f is now up

We see on the console,

Hello World!

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 0x000a '10.0.1--v10.00.01 (Fiery Fox))') |
|------------------------------------------------------------------------------|

|------------------------------------------------------------------------------------------|
| 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_ON | 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 |
|------------------------------------------------------------------------------------------|
cat /sys/class/remoteproc/remoteproc*/state
offline
offline
offline
attached
running

Start the c7x0 echo start > /sys/class/remoteproc/remoteproc0/state

[ 2005.875825] k3-dsp-rproc 7e000000.dsp: booting DSP core using boot addr = 0xa3600000
[ 2005.912050] rproc-virtio rproc-virtio.9.auto: assigned reserved memory node c7x-dma-memory@a3000000
[ 2005.912092] virtio virtio2: reset !
[ 2005.912100] virtio virtio2: status: 1
[ 2005.912370] virtio_rpmsg_bus virtio2: status: 3
[ 2005.912391] remoteproc remoteproc0: vring0: va 000000002e77940d qsz 256 notifyid 0
[ 2005.912417] remoteproc remoteproc0: vring1: va 000000008f3bc709 qsz 256 notifyid 1
[ 2005.914750] virtio_rpmsg_bus virtio2: status: 7
[ 2005.914784] remoteproc remoteproc0: kicking vq index: 0
[ 2005.914809] virtio_rpmsg_bus virtio2: rpmsg host is online
[ 2005.914858] rproc-virtio rproc-virtio.9.auto: registered virtio2 (type 7)
[ 2005.914868] remoteproc remoteproc0: remote processor 7e000000.dsp is now up

And the c7x1

[ 2120.353030] k3-dsp-rproc 7e200000.dsp: booting DSP core using boot addr = 0xa4600000
[ 2120.389547] rproc-virtio rproc-virtio.10.auto: assigned reserved memory node c7x-dma-memory@a4000000
[ 2120.389592] virtio virtio3: reset !
[ 2120.389601] virtio virtio3: status: 1
[ 2120.389870] virtio_rpmsg_bus virtio3: status: 3
[ 2120.389891] remoteproc remoteproc1: vring0: va 00000000d2bfcf0a qsz 256 notifyid 0
[ 2120.389917] remoteproc remoteproc1: vring1: va 000000003256c824 qsz 256 notifyid 1
[ 2120.390737] virtio_rpmsg_bus virtio3: status: 7
[ 2120.390761] remoteproc remoteproc1: kicking vq index: 0
[ 2120.390786] virtio_rpmsg_bus virtio3: rpmsg host is online
[ 2120.390836] rproc-virtio rproc-virtio.10.auto: registered virtio3 (type 7)
[ 2120.390847] remoteproc remoteproc1: remote processor 7e200000.dsp is now up
cat /sys/class/remoteproc/remoteproc*/state
running
running
offline
attached
running
root@BeagleBone:/home/olof/hello_world# 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 0x000a '10.0.1--v10.00.01 (Fiery Fox))') |
|------------------------------------------------------------------------------|

|------------------------------------------------------------------------------------------|
| 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_ON | 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_ON | 1000000000 |
| 268 | 49 | C7X256V1_C7XV_CORE_0 | DEVICE_STATE_ON | 1000000000 |
| 225 | 128 | HSM0 | DEVICE_STATE_ON | 500000000 |
|------------------------------------------------------------------------------------------|

For completeness we start the last core,

 echo start > /sys/class/remoteproc/remoteproc2/state
root@BeagleBone:/home/olof/hello_world# cat /sys/class/remoteproc/remoteproc*/state
running
running
running
attached
running
[ 3504.513620] platform 79000000.r5f: booting R5F core using boot addr = 0x0
[ 3504.514685] rproc-virtio rproc-virtio.11.auto: assigned reserved memory node mcu-r5fss-dma-memory-region@a1000000
[ 3504.514735] virtio virtio4: reset !
[ 3504.514742] virtio virtio4: status: 1
[ 3504.515015] virtio_rpmsg_bus virtio4: status: 3
[ 3504.515041] remoteproc remoteproc2: vring0: va 000000001b667e0a qsz 256 notifyid 0
[ 3504.515066] remoteproc remoteproc2: vring1: va 00000000b99d56da qsz 256 notifyid 1
[ 3504.516168] virtio_rpmsg_bus virtio4: status: 7
[ 3504.516196] remoteproc remoteproc2: kicking vq index: 0
[ 3504.516210] virtio_rpmsg_bus virtio4: rpmsg host is online
[ 3504.516266] rproc-virtio rproc-virtio.11.auto: registered virtio4 (type 7)
[ 3504.516276] remoteproc remoteproc2: remote processor 79000000.r5f is now up
[ 3645.989924] Deferred event dump:00000000: 00000100 00100004 00070001 00820000
[ 3645.989952] Deferred event dump:00000010: 24051642 00000102 00000000 00000000
[ 3645.989960] Deferred event dump:00000020: 00000000 00000000 00000000 00000000
[ 3645.989966] Deferred event dump:00000030: 00000000 00000000 00000000 00000000

And on the console

Hello World!
Hello World!
Hello World!

We only got 3 Hello World! but the mcu core was set to the CAN UART. Not something that I recomend.

 make -s -C  examples/hello_world/j722s-evm/mcu-r5fss0-0_freertos/ti-arm-clang/ syscfg-gui
UART logging on CAN UART

This is the example ,that is now running on 4 cores.



#include <stdio.h>
#include <kernel/dpl/DebugP.h>
#include "ti_drivers_config.h"
#include "ti_drivers_open_close.h"
#include "ti_board_open_close.h"

void hello_world_main(void *args)
{
/* Open drivers to open the UART driver for console */
Drivers_open();
Board_driversOpen();

DebugP_log("Hello World!\r\n");

Board_driversClose();
Drivers_close();
}
k3conf dump devices
| 206 | J722S_DEV_C7XV_RSWS_BS_LIMITER6 | DEVICE_STATE_ON |
| 207 | J722S_DEV_C7X256V0 | DEVICE_STATE_ON |
| 208 | J722S_DEV_C7X256V0_C7XV_CORE_0 | DEVICE_STATE_ON |
| 209 | J722S_DEV_C7X256V0_CORE0 | DEVICE_STATE_ON |
| 210 | J722S_DEV_C7X256V0_CLEC | DEVICE_STATE_ON |
| 211 | J722S_DEV_C7X256V0_CLK | DEVICE_STATE_ON |
| 212 | J722S_DEV_C7X256V0_DEBUG | DEVICE_STATE_ON |
| 213 | J722S_DEV_C7X256V0_GICSS | DEVICE_STATE_ON |

That was a very complicated way to print Hello World! on the serial port, but now we know that the c7x coprocessors are working. We could use the kernel from July but we had to patch the hello world example to include the resource table to allow linux to load the firmware with remoteproc. I built my own bootloader but I do not think that was necessary. The order you start the coprocessors might be important.

uname -a
Linux BeagleBone 6.1.83-ti-arm64-r63 #1bookworm SMP PREEMPT_DYNAMIC Wed Jul 10 23:00:56 UTC 2024 aarch64 GNU/Linux

After rebooting,
Ä 7.729795Ü k3-dsp-rproc 7e000000.dsp: booting DSP core using boot addr = 0xa3600000
Ä 7.741216Ü k3-dsp-rproc 7e200000.dsp: booting DSP core using boot addr = 0xa4600000
Ä OK Ü Started systemd-networkd.service -àHello World!
Hello World!
Hello World!
Now it is not possible to use the serial console to log in.
sudo wall "This is a system-wide broadcast message."

I also noticed that things hangups occured after the reboot. I unlinked some firmware links, sudo unlink /lib/firmware/j722s-c71_1-fw and now it seems to be running ok.

Here is the complete modified hello world program: https://github.com/Ebiroll/hello_beagley the precompiled binaries are in the dist subdirectory.

I aslo ran this to get more debug info from the kernel.

echo 'file drivers/remoteproc/ti_k3_dsp_remoteproc.c +p' > /sys/kernel/debug/dynamic_debug/control
echo "module remoteproc_elf_loader.c +p" > /proc/dynamic_debug/control
echo "module ti_k3_dsp_remoteproc +p" > /proc/dynamic_debug/control

If you do not have a serial connection you can also verify the trace from the other remote processors like this.

$ cd /sys/kernel/debug/remoteproc/remoteproc4
$ sudo tail -f trace0
[main-r5f0-0] 0.000733s : Hello World!

$ cd /sys/kernel/debug/remoteproc/remoteproc0
$ sudo cat resource_table
Entry 0 is of type vdev
ID 7
Notify ID 0
Device features 0x1
Guest features 0x1
Config length 0x0
Status 0x7
Number of vrings 2
Reserved (should be zero) [0][0]

Vring 0
Device Address 0xa3000000
Alignment 4096
Number of buffers 256
Notify ID 0
Physical Address 0x0

Vring 1
Device Address 0xa3004000
Alignment 4096
Number of buffers 256
Notify ID 1
Physical Address 0x0

Entry 1 is of type trace
Device Address 0xa3100400
Length 0x1000 Bytes
Reserved (should be zero) [0]
Name trace:c75ss0_0

$ cd /sys/kernel/debug/remoteproc/remoteproc0
$ sudo cat trace0
[c75ss0] 0.002019s : Hello World!

$ sudo cat carveout_memories
Carveout memory entry:
Name: vdev0vring0
Virtual address: 00000000d6c6411e
DMA address: 0x00000000a3000000
Device address: 0xa3000000
Length: 0x3000 Bytes

Carveout memory entry:
Name: vdev0vring1
Virtual address: 000000005b071dfa
DMA address: 0x00000000a3004000
Device address: 0xa3004000
Length: 0x3000 Bytes

--

--