SEGGER has released a new version of their J-Link tools suite. That suite includes the J-Run utility which loads, executes and monitors the output of the target. Output can be with RTT (Real-Time Transfer) or semihosting. This makes it useful for automated tests with CMake and CTest:

What has been added from the V7.98g release is the ability to send arguments to the running application using the --args command, for example with CMake/CTest:
set (RUNNER_CTEST_COMMAND "$ENV{SEGGER_PATH}/JRun" --verbose --device LPC55S16 --silent --rtt -if SWD)
add_test(
NAME Led_1
COMMAND ${RUNNER_CTEST_COMMAND} --args "Led_1" ${TEST_EXECUTABLE}
) Like applications running on the host, I can now pass arguments to the running application. This is useful to set up the target, or to tell which kind of tests to run.
Outline
In Modern On-Target Embedded System Testing with CMake and CTest. I explained how J-Run can be used with CMake. J-Run can also be used with CTest for automated tests. But I had to use workarounds to use it for on-target testing. One feature missing has been the ability to pass arguments to the application, and now from V7.98 this has been implemented.
💡 Use V7.98i or later. This includes important fixes for J-Run with RTT. It also addresses issues with NXP LPC55S16 devices handling PC and SP values.
Before, I had to use a combination of fixed memory variables with a J-Link Script. See section ‘Parameter Passing’ in Modern On-Target Embedded System Testing with CMake and CTest.
J-Run supports RTT and semihosting: in my tests I’m using it with RTT. RTT is similar to UART, but works through the debug probe. So no extra pins or hardware is required, and is supported by J-Link and other debug probes.
J-Run –args
Now J-Run offers the –args option:
SEGGER J-Run V7.98i Command Line Version
Compiled Sep 18 2024 15:52:22
(c) 2019-2024 SEGGER Microcontroller GmbH www.segger.com
Syntax:
JRun [option option ...] elf-file
Option Default Description
--usb <SerialNo> not set Set serial number of J-Link to connect to via USB.
--ip <str> not set Set host name of J-Link to connect to via TCP/IP.
--device <str>, --d <str> STM32F407IE Set device name to str.
--if SWD | JTAG SWD Select SWD or JTAG as target interface.
--speed <kHz> 4000 Set interface speed to n kHz.
--rtt Auto Explicitly enable RTT.
--nortt Auto Explicitly disable RTT.
--semihost Auto Explicitly enable semihosting.
--nosemihost Auto Explicitly disable semihosting.
--args <args> not set Arguments passed to target application via semihosting and RTT
--wargs <str> *ARGS* Set RTT getargs wildcard to str.
--wexit <str> *STOP* Set RTT exit wildcard to str.
--wait Off Wait for key press on application exit.
--2, --stderr Off Also send target output to stderr.
--s, --silent Off Work silently.
--v, --verbose Off Increase verbosity.
--dryrun Off Dry run. Parse elf-file only.
--jlinkscriptfile <str> not set Set path of J-Link script file to use to str.
Further info : wiki.segger.com / J - Link_script_files
--pc <mode> | 0xXXXXXXXX vec Initialize PC before start (according to <mode> or fixed address).
<mode>: vec - Vector table, elf - ELF start address, off - do not init.
--sp <mode> | 0xXXXXXXXX vec Initialize SP before start (according to <mode> or fixed address).
<mode>: vec - Vector table, off - do not init.
PC and SP Initialization
I tried the V7.98g of J-Run with the –args option. I noticed that some test did not work for the RP2040. The reason is that the RP2040 does start through the ROM bootloader. Thus, the SP (Stack Pointer) and PC (Program Counter) need to be untouched by J-Run. So for the RP2040 I had to turn off setting the PC and SP with --pc off --sp off:
set (JRUN_CTEST_COMMAND "$ENV{SEGGER_PATH}/JRun" --verbose --device RP2040_M0_0 --rtt -if SWD --pc off --sp off) For the LPC55S16 I did not had to add the two options.
💡 Would be good if the SEGGER Wiki lists the devices which need that setting. Otherwise you just have to try out things.
Receiving Arguments
How does the application receive the options passed with --args, for example --args "Led_1"? A SEGGER Article explains the usage with semihosting and RTT: basically it requires sending a special text to J-Run.
To get the arguments as string with RTTT, I have added the a function to McuUnity:
int McuUnity_RTT_GetArgs(const char* buffer, size_t bufSize) { /* from https://wiki.segger.com/Passing_Command-line_arguments_in_C_for_Embedded_Targets */ int NumBytes; SEGGER_RTT_printf(0, "*ARGS*\n"); /* send special command to J-Run to get the arguments */ NumBytes = 0; do { NumBytes += SEGGER_RTT_Read (0, (void*)&buffer[NumBytes], bufSize - NumBytes); } while ((NumBytes == 0 || buffer[NumBytes-1] != '\n') && (NumBytes < bufSize)); return NumBytes; } It sends a special command through RTT to J-Run. The received argument string is stored in a buffer.
Using Arguments
Next, the buffer then can be checked in the running application, for example:
static void TestTask(void *pv) { int nofFailures; uint32_t test_arg = -1; int nofBytes; unsigned char buf[32]; McuLog_info("starting test task"); nofBytes = McuUnity_RTT_GetArgs(buf, sizeof(buf)); McuLog_info("args = %s, nofBytes = %d\n", buf, nofBytes); if (nofBytes>0) { if (McuUtility_strcmp(buf, "Led_1")==0) { test_arg = 1; } else if (McuUtility_strcmp(buf, "Led_2")==0) { test_arg = 2; } } else { test_arg = -1; } UNITY_BEGIN(); switch(test_arg) { case 1: RUN_TEST(TestLeds_OnOff); break; case 2: RUN_TEST(TestLeds_Toggle); break; default: RUN_TEST(TestArgFailed); break; } nofFailures = UNITY_END(); /* report failed or passed */ if (nofFailures==0) { McuLog_info("*** PASSED ***"); } else { McuLog_error("*** FAILED ***"); } if (nofFailures==0) { McuLog_info("*STOP*0"); /* stop test runner with exit code 0 (ok) */ } else { McuLog_info("*STOP*1"); /* stop test runner with exit code 1 (failed), negative error codes are J-Run error codes */ } vTaskDelete(NULL); /* terminate task */ } With this, I can control the on-target test execution.
💡 The current version of J-Run still requires a regular expression in CTest to parse the test output. See Modern On-Target Embedded System Testing with CMake and CTest.
Summary
The --arg option makes my test with CMake and CTest much easier to use. I don’t have to use a JLink script file for argument passing. Instead I can use the --args option and then use it in the running application. Using the argument, I can control the test application execution, for example which tests to run or passing configuration values.
If you are interested in on-target testing: have a look at Modern On-Target Embedded System Testing with CMake and CTest. Check out CI/CD for Embedded with VS Code, Docker and GitHub Actions.
Happy argumenting 🙂
Links
- CI/CD for Embedded with VS Code, Docker and GitHub Actions
- Modern On-Target Embedded System Testing with CMake and CTest
- CMake: https://cmake.org/
- SEGGER J-Run: https://www.segger.com/products/debug-probes/j-link/tools/j-run/
- SEGGER J-Run Wiki: https://wiki.segger.com/J-Run
- SEGGER: Passing Command-line arguments in C for Embedded Targets