Feature : Shell

  • In this program, you are going to learn

  • What configurations needs to be added to enable shell?

  • How to do pre-build and post-build checks ?

  • How to execute commands on Zephyr shell?

  • How to add our own commands to execute in shell?

  • Add the following configurations in prj.conf to enable the shell on Zephyr build.

(.venv) test:zephyr$ pwd
$HOME/zephyrproject/zephyr
(.venv) test:zephyr$ vi samples/hello_world/prj.conf
CONFIG_SHELL=y
CONFIG_SHELL_BACKEND_SERIAL=y
CONFIG_SHELL_HISTORY=y
CONFIG_SHELL_CMDS_RESIZE=y
  • In this section we will see how to do pre-build checks.

  • Check whether the configurations required to enable shell for zephyr is added or not in prj.conf

CONFIG_SHELL=y
CONFIG_SHELL_BACKEND_SERIAL=y
CONFIG_SHELL_HISTORY=y
CONFIG_SHELL_CMDS_RESIZE=y
  • Check for the location of location in zephyr-sdk-0.16.4 directory

(.venv) test:zephyr$ ls -l $HOME/zephyr-sdk-0.16.4/aarch64-zephyr-elf/aarch64-zephyr-elf/bin/
total 17000
-rwxr-xr-x 2 test test 1357336 Nov 15 16:40 ar
-rwxr-xr-x 2 test test 2500544 Nov 15 16:40 as
-rwxr-xr-x 4 test test 2019136 Nov 15 16:40 ld
-rwxr-xr-x 4 test test 2019136 Nov 15 16:40 ld.bfd
-rwxr-xr-x 2 test test 1346128 Nov 15 16:40 nm
-rwxr-xr-x 2 test test 1467888 Nov 15 16:40 objcopy
-rwxr-xr-x 2 test test 2876656 Nov 15 16:40 objdump
-rwxr-xr-x 2 test test 1357368 Nov 15 16:40 ranlib
-rwxr-xr-x 2 test test  977144 Nov 15 16:40 readelf
-rwxr-xr-x 2 test test 1467888 Nov 15 16:40 strip
  • run west build command to build the application.

(.venv) test:zephyr$ pwd
$HOME/zephyrproject/zephyr


(.venv) test:zephyr$ west build -b rpi4b samples/hello_world/
-- west build: making build dir /home/wifi/zephyr_with_rpi4/zephyrproject/zephyr/build pristine
-- west build: generating a build system
Loading Zephyr default modules (Zephyr base).
-- Application: /home/wifi/zephyr_with_rpi4/zephyrproject/zephyr/samples/hello_world
-- CMake version: 3.24.2
-- Found Python3: /home/wifi/zephyrproject/.venv/bin/python3 (found suitable version "3.10.7", minimum required is "3.8") found components: Interpreter
-- Cache files will be written to: /home/wifi/.cache/zephyr
-- Zephyr version: 3.6.0-rc2 (/home/wifi/zephyr_with_rpi4/zephyrproject/zephyr)
-- Found west (found suitable version "1.2.0", minimum required is "0.14.0")
-- Board: rpi_4b
-- ZEPHYR_TOOLCHAIN_VARIANT not set, trying to locate Zephyr SDK
-- Found host-tools: zephyr 0.16.4 (/home/wifi/double_thread_zephyr_build/zephyr-sdk-0.16.4)
-- Found toolchain: zephyr 0.16.4 (/home/wifi/double_thread_zephyr_build/zephyr-sdk-0.16.4)
-- Found Dtc: /home/wifi/double_thread_zephyr_build/zephyr-sdk-0.16.4/sysroots/x86_64-pokysdk-linux/usr/bin/dtc (found suitable version "1.6.0", minimum required is "1.4.6")
-- Found BOARD.dts: /home/wifi/zephyr_with_rpi4/zephyrproject/zephyr/boards/arm64/rpi_4b/rpi_4b.dts
-- Generated zephyr.dts: /home/wifi/zephyr_with_rpi4/zephyrproject/zephyr/build/zephyr/zephyr.dts
-- Generated devicetree_generated.h: /home/wifi/zephyr_with_rpi4/zephyrproject/zephyr/build/zephyr/include/generated/devicetree_generated.h
-- Including generated dts.cmake file: /home/wifi/zephyr_with_rpi4/zephyrproject/zephyr/build/zephyr/dts.cmake
Parsing /home/wifi/zephyr_with_rpi4/zephyrproject/zephyr/Kconfig
Loaded configuration /home/wifi/zephyr_with_rpi4/zephyrproject/zephyr/boards/arm64/rpi_4b/rpi_4b_defconfig
Merged configuration /home/wifi/zephyr_with_rpi4/zephyrproject/zephyr/samples/hello_world/prj.conf
Configuration saved to /home/wifi/zephyr_with_rpi4/zephyrproject/zephyr/build/zephyr/.config
Kconfig header saved to /home/wifi/zephyr_with_rpi4/zephyrproject/zephyr/build/zephyr/include/generated/autoconf.h
-- Found GnuLd: /home/wifi/double_thread_zephyr_build/zephyr-sdk-0.16.4/aarch64-zephyr-elf/bin/../lib/gcc/aarch64-zephyr-elf/12.2.0/../../../../aarch64-zephyr-elf/bin/ld.bfd (found version "2.38")
-- The C compiler identification is GNU 12.2.0
-- The CXX compiler identification is GNU 12.2.0
-- The ASM compiler identification is GNU
-- Found assembler: /home/wifi/double_thread_zephyr_build/zephyr-sdk-0.16.4/aarch64-zephyr-elf/bin/aarch64-zephyr-elf-gcc
-- Using ccache: /usr/bin/ccache
-- Configuring done
-- Generating done
-- Build files have been written to: /home/wifi/zephyr_with_rpi4/zephyrproject/zephyr/build
-- west build: building application
[1/119] Preparing syscall dependency handling

[2/119] Generating include/generated/version.h
-- Zephyr version: 3.6.0-rc2 (/home/wifi/zephyr_with_rpi4/zephyrproject/zephyr), build: v3.6.0-rc2-104-g793c507209eb
[118/119] Linking C executable zephyr/zephyr.elf
Memory region         Used Size  Region Size  %age Used
           FLASH:          0 GB         0 GB
             RAM:      155652 B       512 KB     29.69%
        IDT_LIST:          0 GB        32 KB      0.00%
Generating files from /home/wifi/zephyr_with_rpi4/zephyrproject/zephyr/build/zephyr/zephyr.elf for board: rpi_4b
[119/119] cd /home/wifi/zephyr_with_rpi4/zephyrproject/zephyr/build/zephyr && /home/wifi/zephyrproject/....k_init_priorities.py --elf-file=/home/wifi/zephyr_with_rpi4/zephyrproject/zephyr/build/zephyr/zephyr.elf
  • In this section we will see how to do post-build checks

  • Here we will see how to do static post build checks

  • Lets check for the location of the final application target image to make sure the build is completed successfully without any errors.

(.venv) test:zephyr$ ls -l build/zep build/zephyr/
-rwxrwxr-x 1 test test   39190 Jan 24 18:38 zephyr.bin
-rw-rw-r-- 1 test test   23193 Jan 24 18:38 zephyr.dts
-rw-rw-r-- 1 test test    3011 Jan 24 18:38 zephyr.dts.d
-rw-rw-r-- 1 test test   97435 Jan 24 18:38 zephyr.dts.pre
-rwxrwxr-x 1 test test 1023460 Jan 24 18:38 zephyr.elf
-rw-rw-r-- 1 test test  399931 Jan 24 18:38 zephyr_final.map
-rw-rw-r-- 1 test test  110346 Jan 24 18:38 zephyr.hex
-rw-rw-r-- 1 test test  399931 Jan 24 18:38 zephyr.map
-rwxrwxr-x 1 test test 1024056 Jan 24 18:38 zephyr_pre0.elf
-rw-rw-r-- 1 test test  400481 Jan 24 18:38 zephyr_pre0.map
-rw-rw-r-- 1 test test    4675 Jan 24 18:38 zephyr.stat
  • Here we will see how to do runtime post-build checks

  • Go to main directory

$ cd $HOME
$ mkdir Zephyr_flash
$ cd Zephyr_flash
$ wget https://raw.githubusercontent.com/raspberrypi/firmware/master/boot/bcm2711-rpi-4-b.dtb
$ wget https://raw.githubusercontent.com/raspberrypi/firmware/master/boot/bootcode.bin
$ wget https://raw.githubusercontent.com/raspberrypi/firmware/master/boot/start4.elf
  • Create the config.txt file and copy the below lines and save the file

$ vi config.txt
  • Place the following contents in config.txt file.

kernel=zephyr.bin
arm_64bit=1
enable_uart=1
uart_2ndstage=1
  • Copy the zephyr.bin file to Zephyr_flash directory

$ cp /home/test/zephyrproject/zephyr/build/zephyr/zephyr.bin /home/Zephyr_flash
  • Copy all the below files to TF card(SD card)

bcm2711-rpi-4-b.dtb
bootcode.bin
start4.elf
config.txt
zephyr.bin
  • Copy using cp command,

$ cp Zephyr_flash/bcm2711-rpi-4-b.dtb /mnt/boot/
$ cp Zephyr_flash/bootcode.bin /mnt/boot/
$ cp Zephyr_flash/start4.elf /mnt/boot/
$ cp Zephyr_flash/config.txt /mnt/boot/
$ cp Zephyr_flash/zephyr.bin /mnt/boot/
  • Disconnect the micro SD Card reader from Linux Desktop machine.

  • Insert SD Card to the RPI Board

  • Then, use serial usb cable to connect the RPI board and Linux Desktop machine.

  • After connecting, check whether /dev/ttyUSB0 created or not.

$ ls /dev/ttyUSB0
  • Run minicom to access RPI board

$ sudo minicom -D /dev/ttyUSB0 -b 115200
  • We can confirm the application is successfully loaded without any errors if the prompt is displayed on the virtual environment.

uart:~$
  • In this section, we will see about zephyr shell commands in detail.

  • “cycles” subcommand is used to give information about the kernel cycles.

uart:~$ kernel cycles
cycles: 541874435 hw cycles
  • “stacks” subcommand is used to list the thread stack usage.

uart:~$ kernel stacks
0x20000430 sysworkq                         (real size 1024):   unused  816     usage  208 / 1024 (20 %)
0x20000100 shell_uart                       (real size 2048):   unused  872     usage 1176 / 2048 (57 %)
0x200002a0 idle                             (real size  256):   unused  168     usage   88 /  256 (34 %)
0x200011a0 IRQ 00                           (real size 2048):   unused 1652     usage  396 / 2048 (19 %)
  • “threads” subcommand is used to list kernel threads along with various information like priority, state and stack size.

uart:~$ kernel threads
Scheduler: 1529 since last call
Threads:
 0x20000430 sysworkq
        options: 0x0, priority: -1 timeout: 0
        state: pending, entry: 0x8005681
        stack size 1024, unused 816, usage 208 / 1024 (20 %)

*0x20000100 shell_uart
        options: 0x0, priority: 14 timeout: 0
        state: queued, entry: 0x8001d81
        stack size 2048, unused 872, usage 1176 / 2048 (57 %)

 0x200002a0 idle
        options: 0x1, priority: 15 timeout: 0
        state: , entry: 0x800782f
        stack size 256, unused 168, usage 88 / 256 (34 %)
  • “list” subcommand is used to list the configured devices.

uart:~$ device list
devices:
- rcc40021000 (READY)
- reset-controller (READY)
- interrupt-controller40021800 (READY)
- gpio50001400 (READY)
- gpio50001000 (READY)
- gpio50000c00 (READY)
- gpio50000800 (READY)
- gpio50000400 (READY)
- gpio50000000 (READY)
- serial40004400 (READY)
- serial40013800 (READY)






  • In this section we will see how to see our own command in zephyr shell.

  • Add the following instructions in main.c

(.venv) test:zephyr$ pwd
$HOME/zephyrproject/zephyr
(.venv) test:zephyr$ vi samples/hello_world/src/main.c
#include <zephyr/kernel.h>
#include <zephyr/shell/shell.h>

static int hello_cmd_handler(const struct shell *shell, size_t argc, char **argv)
{
    ARG_UNUSED(argc);
    ARG_UNUSED(argv);

    shell_print(shell, "Hello, World!");
    return 0;
}

SHELL_CMD_REGISTER(hello, NULL, "Prints Hello, World!'", hello_cmd_handler);
static int hello_cmd_handler(const struct shell *shell, size_t argc, char **argv)
{
        ARG_UNUSED(argc);
        ARG_UNUSED(argv);

        shell_print(shell, "Hello, World!");
        return 0;
}
  • This defines a function named hello_cmd_handler, which will be the handler for the custom shell command.

  • The function does not use the argc and argv parameters, so “ARG_UNUSED(argc)” and “ARG_UNUSED(argv)” are used to avoid compiler warnings about unused parameters.

  • “shell_print” is used to print the “Hello, World!” message to the shell.

SHELL_CMD_REGISTER(hello, NULL, "Prints Hello, World!'", hello_cmd_handler);
  • This line registers the hello command with the Zephyr shell.

  • The SHELL_CMD_REGISTER macro takes four parameters:

    • hello: The name of the command. Users will type this command in the shell.

    • NULL: The subcommands. In this case, there are no subcommands, so its set to NULL.

    • “Prints Hello, World!’”: A description of the command, which will be displayed when users type help in the shell.

    • hello_cmd_handler: The function that will handle the command.

  • run west build to build the application.

(.venv) test:zephyr$ west build -b rpi_4b samples/hello_world/
  • Go to main directory

$ cd $HOME
$ mkdir Zephyr_flash
$ cd Zephyr_flash
$ wget https://raw.githubusercontent.com/raspberrypi/firmware/master/boot/bcm2711-rpi-4-b.dtb
$ wget https://raw.githubusercontent.com/raspberrypi/firmware/master/boot/bootcode.bin
$ wget https://raw.githubusercontent.com/raspberrypi/firmware/master/boot/start4.elf
  • Create the config.txt file and copy the below lines and save the file

$ vi config.txt
  • Place the following contents in config.txt file.

kernel=zephyr.bin
arm_64bit=1
enable_uart=1
uart_2ndstage=1
  • Copy the zephyr.bin file to Zephyr_flash directory

$ cp /home/test/zephyrproject/zephyr/build/zephyr/zephyr.bin /home/Zephyr_flash
  • Copy all the below files to TF card(SD card)

bcm2711-rpi-4-b.dtb
bootcode.bin
start4.elf
config.txt
zephyr.bin
  • Copy using cp command,

$ cp Zephyr_flash/bcm2711-rpi-4-b.dtb /mnt/boot/
$ cp Zephyr_flash/bootcode.bin /mnt/boot/
$ cp Zephyr_flash/start4.elf /mnt/boot/
$ cp Zephyr_flash/config.txt /mnt/boot/
$ cp Zephyr_flash/zephyr.bin /mnt/boot/
  • Disconnect the micro SD Card reader from Linux Desktop machine.

  • Insert SD Card to the RPI Board

  • Then, use serial usb cable to connect the RPI board and Linux Desktop machine.

  • After connecting, check whether /dev/ttyUSB0 created or not.

$ ls /dev/ttyUSB0
  • Run minicom to access RPI board

$ sudo minicom -D /dev/ttyUSB0 -b 115200
  • run “hello” on the minicom console to execute our own command.

uart:~$ hello
Hello, World!