- Table of contents
- AM62x M4 RPMsg echo to Arm/Linux
- Objectives:
- Prerequisites
- Step 1: Building the M4 program
- Creating the project and getting the initial source
- Modifying the source for a debugger wait loop
- Building the project
- Putting the program on the target
- Using remoteproc to start the program on the target
- Checking the output of the program
- Comment on the program and the resource table
- Using just a makefile to build the program.
- Step 2: Building the Arm/Linux user program
- Step 3: Run both programs in debuggers
- Create a Target Configuration
- Make the debugger wait loop longer (180 seconds)
- Put rebuilt program on the target
- Use remoteproc to stop and start the program on the target
- Connect the M4 debugger, set breakpoint
- Start the Linux program in gdbserver, set breakpoint
- Run program and stop when messages are received.
- Summary
AM62x M4 RPMsg echo to Arm/Linux¶
Objectives:¶
- Build and run an M4 program which will echo any RPMsg message it receives back to the sender.
- Build and run an ARM/Linux user program which will send a number of messages to the M4 and receive the messages echoed back.
- Run both of these programs in debuggers.
Prerequisites¶
- Code Composer installed
- M4 sdk installed
- ti-processor-sdk installed
- Name the target am62x as described in: Ssh_target_naming_and_port_forwarding
Step 1: Building the M4 program¶
Creating the project and getting the initial source¶
- Import CCS projects. File->Import...->Code Composer Studio->CCS Projects-> Next
- Select Search-directory: Browse to ~/ti/mcu_plus_sdk_am62x_08_06_00/examples/drivers/ipc/ipc_rpmsg_echo_linux
- Select the ipc_rpmsg_echo_linux_am62x-sk_m4fss0-0_freertos_ti-arm-clang project (make sure Copy projects into workspace is checked.)
- Finish
Modifying the source for a debugger wait loop¶
- Open ipc_rpmsg_echo.c
- In the function ipc_rpmsg_echo_main() near line 360, change the initial code to look like:
Initial Code
void ipc_rpmsg_echo_main(void *args) { int32_t status; Drivers_open(); Board_driversOpen(); DebugP_log("[IPC RPMSG ECHO] Version: %s (%s %s): \r\n", IPC_FW_VERSION, __DATE__, __TIME__);
Modified Code
void ipc_rpmsg_echo_main(void *args) { int32_t status; int max_wait_time = 30; Drivers_open(); Board_driversOpen(); DebugP_log("[IPC RPMSG ECHO] Version: %s (%s %s): \r\n", IPC_FW_VERSION, __DATE__, __TIME__); DebugP_log("Starting to wait for debugger attach. %d seconds\r\n", max_wait_time); for (int ii = 0; ii < max_wait_time; ++ii) { if ((ii % 5) == 0) { DebugP_log("%3d secs: Waiting for debugger attach\r\n", ii); } ClockP_sleep(1); } DebugP_log("Done waiting for debugger attach. Moving on...\r\n");
Building the project¶
Do one of the following:- Press ctrl-B to start the build of the project.
- Project->Build Project
- In the Project Explorer, point the mouse to the project name, rightmouse->Build Project
Putting the program on the target¶
- Open a Terminal window, local terminal
cd <your_workspace>/ipc_rpmsg_echo_linux_am62x-sk_m4fss0-0_freertos_ti-arm-clang/Debug ssh am62x mkdir mcu_rpmsg scp am62-mcu-m4f0_0-fw am62x:mcu_rpmsg ssh am62x ln -sf /home/root/mcu_rpmsg/am62-mcu-m4f0_0-fw /lib/firmware/am62-mcu-m4f0_0-fw
Using remoteproc to start the program on the target¶
For these commands, it is best to use the serial console of the target so you can see the system messages printed on the console. When stopping the remoteproc, if the remoteproc is already stopped, you will see an error message that can be ignored. When starting the remoteproc, there should be several messages indicating that the remoteproc is loaded and up and running.
It would also be useful to attach to the second uart of the usb uart connection. The second uart will be the uart connected to the M4. When the M4 is running, there will be messages printed on this second console.
Commands for the target console:
echo stop >/sys/class/remoteproc/remoteproc0/state echo start >/sys/class/remoteproc/remoteproc0/state
These commands can also be given from the Local Terminal in Code Composer:
ssh am62x 'echo stop >/sys/class/remoteproc/remoteproc0/state' ssh am62x 'echo start >/sys/class/remoteproc/remoteproc0/state'
Checking the output of the program¶
On the ARM UART, when you stop and start the M4 remoteproc, you should see output like:
root@mitysom-am62x:~# echo stop >/sys/class/remoteproc/remoteproc0/state [85761.244261] remoteproc remoteproc0: stopped remote processor 5000000.m4fss root@mitysom-am62x:~# echo start >/sys/class/remoteproc/remoteproc0/state [85776.450011] remoteproc remoteproc0: powering up 5000000.m4fss [85776.456996] remoteproc remoteproc0: Booting fw image am62-mcu-m4f0_0-fw, size 119820 [85776.466410] remoteproc0#vdev0buffer: assigned reserved memory node m4f-dma-memory@9cb00000 [85776.475484] virtio_rpmsg_bus virtio0: rpmsg host is online [85776.482169] remoteproc0#vdev0buffer: registered virtio0 (type 7) [85776.488394] remoteproc remoteproc0: remote processor 5000000.m4fss is now up root@mitysom-am62x:~# [85806.479843] virtio_rpmsg_bus virtio0: creating channel ti.ipc4.ping-pong addr 0xd [85806.487819] virtio_rpmsg_bus virtio0: creating channel rpmsg_chrdev addr 0xe
Note that the final 2 messages come out 30 seconds after the initial messages.
The extra 30 seconds is the time inserted to wait for the debugger connection. This is not really a long time and it will be made longer when we want to do debugging. For now, it is enough to be observable but not greatly annoying.
On the M4 UART, you should see output like:
[IPC RPMSG ECHO] Version: REL.MCUSDK.08.06.00.12 (May 5 2023 14:32:31): Starting to wait for debugger attach. 30 seconds 0 secs: Waiting for debugger attach 5 secs: Waiting for debugger attach 10 secs: Waiting for debugger attach 15 secs: Waiting for debugger attach 20 secs: Waiting for debugger attach 25 secs: Waiting for debugger attach Done waiting for debugger attach. Moving on... [IPC RPMSG ECHO] Remote Core waiting for messages at end point 13 ... !!! [IPC RPMSG ECHO] Remote Core waiting for messages at end point 14 ... !!!
At this point, the M4 program is running and waiting for the Arm/Linux to send it messages.
Comment on the program and the resource table¶
- This program has a resource table which is needed in order to be loaded by the remoteproc mechanism. If you are not familiar with resource tables, you might ask where it is. The resource table is specified by checking the IPC in the syscfg. There is an entry in the linker.cmd file to position the resource table at the correct location. The content is specified by the syscfg and is present in generated source files in Debug/syscfg.
- For more information, see 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
Using just a makefile to build the program.¶
If you want to build the program with a makefile without using Code Composer, you can just use the makefile that comes with the example. Try the following:
Create a script like the following to do the proper setup for using the makefile.
Contents of build.sh:
#!/bin/bash export MCU_PLUS_SDK_PATH=/home/$USERNAME/ti/mcu_plus_sdk_am62x_08_06_00_18 cd ipc_rpmsg_echo_linux/am62x-sk/m4fss0-0_freertos/ti-arm-clang make "$@"
With this script, you can just copy the example at ~/ti/mcu_plus_sdk_arm62x_08_06_00_18/examples/drivers/ipc/ipc_rpmsg_echo_linux to a work directory and run build.sh.
mkdir work_dir cd work_dir cp -r ~/ti/mcu_plus_sdk_am62x_08_06_00_18/examples/drivers/ipc/ipc_rpmsg_echo_linux . # create build.sh with above contents, make it executable ./build.sh # Use ./build.sh clean to clean the generated files with: ./build.sh clean
This example program could be used as a starting point for your own application. Or you could pick a different example that might be closer to your application and use that as a starting point. If the example is close enough, then your modifications may just consist of adding more source files. This approach is usually much easier than trying to create a makefile from scratch.
Step 2: Building the Arm/Linux user program¶
Getting the source files¶
The source files are contained in a TI git repository.
mkdir rpmsg cd rpmsg git clone https://git.ti.com/cgit/rpmsg/ti-rpmsg-char
Adding the project¶
In the existing workspace with the M4 program, we can add a second project for the Arm/Linux program.
- File->New->Project->C/C++->C Project->Next
- C Project
- Project name: linux_rpmsg_demo
- Project type: Empty Project
- Toolchains: Cross GCC
- Next
- Select Configurations
- Next
- Cross GCC Command
- Browse to the C Compiler in the ti-processor-sdk.
- Cross compiler path: ~/ti-processor-sdk-linux-am62xx-evm-08.06.00.42/linux-devkit/sysroots/x86_64-arago-linux/usr/bin
- Cross compiler prefix: aarch64-none-linux-gnu-
- Finish
- Add the source files
- File->Import...->General->File System->Next
- From Directory: Browse to the rpmsg/ti-rpmsg-char path
- In the examples directory, select *.c file
- In the include directory, select all the *.h files
- In the src directory, select all *.c and *.h files
- Into folder: linux_rpmsg_demo
- Finish
The linux_rpmsg_demo project should now have examples, include, and src folders.
Building the project¶
Build the linux_rpmsg_demo project by doing one of the following.
- Select the project in the Project Explorer. right-mouse->Build Project
- Enter ctrl-B. (this will build both project)
- Project->Build Project
Putting the program on the target¶
In the Local Terminal of Code Composer
cd <your_workspace_path>/linux_rpmsg_demo/Debug scp linux_rpmsg_demo am62x:mcu_rpmsg
Running the program¶
- Wait for the M4 program to get past the debugger wait
- Processor ids are listed in rproc_id.h. The id "9" represents M4F_MCU0_0.
- From the Terminal window, here is the command and expected output.
ssh am62x ./mcu_rpmsg/linux_rpmsg_demo -r 9 -n 10 Created endpt device rpmsg-char-9-1638, fd = 3 port = 1024 Exchanging 10 messages with rpmsg device ti.ipc4.ping-pong on rproc id 9 ... Sending message #0: hello there 0! Receiving message #0: hello there 0! Sending message #1: hello there 1! Receiving message #1: hello there 1! Sending message #2: hello there 2! Receiving message #2: hello there 2! Sending message #3: hello there 3! Receiving message #3: hello there 3! Sending message #4: hello there 4! Receiving message #4: hello there 4! Sending message #5: hello there 5! Receiving message #5: hello there 5! Sending message #6: hello there 6! Receiving message #6: hello there 6! Sending message #7: hello there 7! Receiving message #7: hello there 7! Sending message #8: hello there 8! Receiving message #8: hello there 8! Sending message #9: hello there 9! Receiving message #9: hello there 9! Communicated 10 messages successfully on rpmsg-char-9-1638 TEST STATUS: PASSED
Step 3: Run both programs in debuggers¶
Create a Target Configuration¶
- Select the ipc_rpmsg_echo_linux_am62x-sk_m4fss0-0_freertos_ti-arm-clang project in the Project Explorer
- Right-mouse->File->Target Configuration File
- File name: am62x.ccxml
- Finish
- General Setup
- Change Connection to the type of probe you are using.
- Board or Device should be AM62
- Advanced
- Select CortexA53_0, Check the Bypass box.
- Select CortexA53_1, Check the Bypass box.
- Select CortexA53_2, Check the Bypass box.
- Select CortexA53_3, Check the Bypass box.
- Click the Save button
Bypassing the 4 ARM cpus is a safety measure so you don't accidentally connect to a Linux cpu with the JTAG connection. This doesn't usually turn out well.
Make the debugger wait loop longer (180 seconds)¶
- In the ipc_rpmsg_echo.c file near line 364, change the value of "max_wait_time" from 30 to 180.
- Build the program
Put rebuilt program on the target¶
In the Local Terminal view on Code Composer.
cd <your_workspace>/ipc_rpmsg_echo_linux_am62x-sk_m4fss0-0_freertos_ti-arm-clang/Debug scp am62-mcu-m4f0_0-fw am62x:mcu_rpmsg
Use remoteproc to stop and start the program on the target¶
In the Local Terminal view on Code Composer.
ssh am62x 'echo stop >/sys/class/remoteproc/remoteproc0/state' ssh am62x 'echo start >/sys/class/remoteproc/remoteproc0/state'
Connect the M4 debugger, set breakpoint¶
- Launch the Target Configuration
- Window->Show View->Target Configurations
- In Target Configurations View-
- Projects->ipc_rpmsg_echo_linux_am62x-sk_m4fss0-0_freertos_ti-arm-clang->am62x.ccxml
- right-mouse->Launch Selected Configuration
- Connect to the M4
- In the Debug view, select BLAZAR_Cortex_M4F_1->right-mouse->Connect Target
- Load the Symbols
- Run->Load->Load Symbols
- Browse the ipc_rpmsg_echo_linux_am62x-sk_m4fss0-0_freertos_ti-arm-clang project and select the ipc_rpmsg_echo_linux_am62x-sk_m4fss0-0_freertos_ti-arm-clang.out executable
- note that the am62-mcu-m4f0_0-fw which is copied to the target does not contain symbols and is not helpful to the debugger
- Run->Load->Load Symbols
- Set breakpoint in the delay loop.
- around line 378 in ipc_rpmsg_echo.c, set a breakpoint at the ClockP_sleep(1);
- Resume the target. Run->Resume
- Move out of the loop
- When stopped at the call to ClockP_sleep()
- Select the first line outside the delay loop (line 381)
- Right-mouse->Move Line
- Set a breakpoint when a message is received.
- In ipc_rpmsg_echo.c, near line 163
- Set a breakpoint at the first line after the call to RPMessage_recv()
- Run. Run->Resume
Start the Linux program in gdbserver, set breakpoint¶
- ssh am62x gdbserver :10000 ./mcu_rpmsg/linux_rpmsg_demo -r 9 -n 10
- In the Project Explorer, select the linux_rpmsg_demo project
- Run->Debug Configurations
- C/C++ Remote Application->right-mouse->New Configuration
- Name: linux_rpmsg_demo Debug
- At the bottom: Using GDB (DSF)... click on Select other...
- Check the Use configuration specific settings
- Select GDB Manual Remote Debugging Launcher
- OK
- Debugger Tab
- Main Tab
- GDB debugger: gdb-multiarch
- Connection Tab
- TCP, localhost, 10000 (or local port that am62x is using)
- Main Tab
- Debug
- Set breakpoint when message is received
- In rpmsg_char_simple.c, near line 137
- Set a breakpoint at the first line after the call to recv_msg()
Run program and stop when messages are received.¶
Resume the linux program.- Should stop in the M4
- Resume the M4
- Should stop in the linux program
- Resume the linux program
- Should stop in the M4
- ...
Summary¶
This page has demonstrated how to:
- Build and run an M4 program which will echo any RPMsg message it receives back to the sender.
- Build and run an ARM/Linux user program which will send a number of messages to the M4 and receive the messages echoed back.
- Run both of these programs in debuggers at the same time.
Go to top