diff --git a/content/learning-paths/embedded-and-microcontrollers/zephyr_shell/1_installation.md b/content/learning-paths/embedded-and-microcontrollers/zephyr_shell/1_installation.md new file mode 100644 index 0000000000..9ebc1dc1ca --- /dev/null +++ b/content/learning-paths/embedded-and-microcontrollers/zephyr_shell/1_installation.md @@ -0,0 +1,132 @@ +--- +title: Set up your environment +weight: 2 + +### FIXED, DO NOT MODIFY +layout: learningpathall +--- + +## Set up your environment + +In this section, you will prepare your host computer and identify the hardware needed for two Zephyr shell examples. You will use the shell over two transports: + +- MQTT over Ethernet +- UART over a USB serial connection + +By the end of this section, you will know which boards to use, which host tools to install, and how the Zephyr shell fits into an embedded application. + +## Before you begin + +Make sure you have a working Zephyr development environment set up in Visual Studio Code using the Workbench for Zephyr extension, including: + +- The Workbench for Zephyr extension installed +- A Zephyr SDK toolchain imported in Workbench +- A West workspace initialized + +If you have not done this yet, complete [Build Zephyr projects with Workbench for Zephyr in VS Code learnin path](/learning-paths/embedded-and-microcontrollers/zephyr_vsworkbench/) first. + +You also need: + +- Docker Desktop, Docker Engine, or another Docker-compatible runtime +- A USB cable for each development board + +## Hardware requirements + +For the MQTT shell example, use a Zephyr-supported development board with Ethernet. The instructions use the [FRDM-MCXN947](https://www.nxp.com/design/design-center/development-boards-and-designs/FRDM-MCXN947), with the Zephyr board identifier `frdm_mcxn947/mcxn947/cpu0`. + +For the UART shell example, use a Zephyr-supported development board with a USB UART interface. The instructions use the [FRDM-MCXN947](https://www.nxp.com/design/design-center/development-boards-and-designs/FRDM-MCXN947), with the Zephyr board identifier `frdm_mcxn947/mcxn947/cpu0`. + +To check whether another board is supported by Zephyr, refer to the [Zephyr Supported Boards list](https://docs.zephyrproject.org/latest/boards/index.html). + +## Install UART terminal tools + +For the UART shell example, install a serial terminal application on your host computer. You will use the terminal application to connect to the Zephyr shell over the board's UART interface. + +### Windows + +Install [PuTTY](https://www.putty.org/index.html), which provides a lightweight serial terminal for UART communication. + +After installation: + +1. Connect the development board over USB. + +2. Open **Device Manager** and locate the board's COM port under **Ports (COM & LPT)**. + +3. Open PuTTY and configure: + + - **Connection type**: `Serial` + + - **Serial line**: your board's COM port (for example `COM5`) + + - **Speed**: `115200` + +Select **Open** to connect to the Zephyr UART shell. + +

+ PuTTY Installation +
+ PuTTY Serial Terminal Configuration +

+ +### macOS + +macOS includes a built-in UART terminal utility through the `screen` command, so no additional software is required. + +After connecting the development board over USB: + +1. Open a terminal window. + +2. List available serial devices: + +```bash + +ls /dev/tty.* + +``` + +3. Identify the board's serial device. + +4. Connect to the UART shell with: + +```bash + +screen /dev/tty.usbmodemXXXX 115200 + +``` + +Replace `/dev/tty.usbmodemXXXX` with the serial device shown on your system. + +To exit `screen`: + +1. Press `Ctrl + A` + +2. Press `K` + +3. Press `Y` to confirm + +{{% notice Note %}} + +Workbench for Zephyr supports multiple debug runners depending on the connected board. The FRDM-MCXN947 board uses the onboard CMSIS-DAP / LinkServer interface for flashing and debugging, while shell access in this Learning Path uses UART over USB. + +{{% /notice %}} + +## Network requirements + +For the MQTT shell example, the board needs access to an MQTT broker over Ethernet. You will run Mosquitto locally with Docker Compose and use the Mosquitto command-line tools to send and receive shell messages. + +Make sure that: + +- The board is connected to the same network as the host computer. +- The network provides DHCP, or you configure a static IPv4 address in `prj.conf`. +- The board can reach the MQTT broker on port `1883`. + +{{% notice Note %}} +The example configuration uses IPv4. If your network does not provide DHCP, use the static IPv4 settings shown in the next section. +{{% /notice %}} + +## What's next? + +In the next section, you will read a short overview of the Zephyr shell subsystem and the two transports used in this Learning Path. After that, you will build the MQTT shell and the UART shell on the FRDM-MCXN947 using a USB serial connection and a UART terminal application such as PuTTY or the built-in macOS `screen` utility. diff --git a/content/learning-paths/embedded-and-microcontrollers/zephyr_shell/2_overview.md b/content/learning-paths/embedded-and-microcontrollers/zephyr_shell/2_overview.md new file mode 100644 index 0000000000..3e3433b13e --- /dev/null +++ b/content/learning-paths/embedded-and-microcontrollers/zephyr_shell/2_overview.md @@ -0,0 +1,49 @@ +--- +title: Overview +weight: 3 + +### FIXED, DO NOT MODIFY +layout: learningpathall +--- + +## What is the Zephyr shell? + +The Zephyr shell subsystem (`CONFIG_SHELL=y`) adds an interactive command-line interface to your firmware. After the shell is enabled, you can inspect system state, run subsystem commands, and trigger application behavior at runtime without rebuilding or reflashing the application. + +Several Zephyr subsystems register shell commands automatically. Common built-in modules include: + +| Module | Example commands | +|--------|------------------| +| `kernel` | `version`, `uptime`, `thread list`, `thread stacks` | +| `net` | `iface`, `ping`, `dns`, `tcp` | +| `device` | `list` | +| `log` | `enable`, `disable`, `levels` | +| `shell` | `help`, `history`, `resize` | + +## How shell backends work + +The shell command tree is independent of the transport. The same commands can run over UART, RTT, MQTT, or another enabled backend. You select a transport by setting a single Kconfig option, with no code changes in `main.c`. + +In this Learning Path you will work with two transports: + +- `CONFIG_SHELL_BACKEND_MQTT=y` routes shell commands and responses over MQTT topics. Inbound on `/sh/rx`, outbound on `/sh/tx`. The backend connects automatically once the board has an IPv4 address. The MQTT backend is IPv4-only. +- `CONFIG_SHELL_BACKEND_SERIAL=y` routes shell commands and responses over the board's UART interface. The shell is accessible through a USB serial connection using a terminal application such as PuTTY on Windows or the built-in `screen` utility on macOS. The UART backend works on a wide range of Zephyr-supported development boards with no additional debug hardware required. + +Multiple backends can be enabled at the same time in a single application when the board has the required peripherals and memory. + +A minimal shell build with only the kernel and device modules adds roughly 10 to 15 KB to flash and a few hundred bytes to RAM. + +## What you will do next + +The two following sections each build a small Zephyr application that enables one of these backends: + +- **MQTT shell** on the NXP FRDM-MCXN947, with a local Mosquitto broker running in Docker. You will send commands and read responses with the `mosquitto_pub` and `mosquitto_sub` command-line tools. +- **UART shell** on the FRDM-MCXN947, using a USB serial connection with PuTTY on Windows or the built-in `screen` utility on macOS. + +Each example is portable to any Zephyr-supported board with the right peripheral (Ethernet for MQTT, J-Link for RTT). The "Switch to a different board" section near the end of each page shows how to change the target board on an existing project. + +For more information on the shell subsystem, see the [Zephyr Shell documentation](https://docs.zephyrproject.org/latest/services/shell/index.html). + +## What's next? + +In the next section, you will build the MQTT shell on the FRDM-MCXN947, run Mosquitto in Docker, and exchange shell commands with the board over MQTT topics. diff --git a/content/learning-paths/embedded-and-microcontrollers/zephyr_shell/3_mqtt_shell.md b/content/learning-paths/embedded-and-microcontrollers/zephyr_shell/3_mqtt_shell.md new file mode 100644 index 0000000000..d4646a8546 --- /dev/null +++ b/content/learning-paths/embedded-and-microcontrollers/zephyr_shell/3_mqtt_shell.md @@ -0,0 +1,419 @@ +--- +title: MQTT shell +weight: 4 + +### FIXED, DO NOT MODIFY +layout: learningpathall +--- + +## Set up the MQTT shell example + +In this section, you will build a minimal Zephyr application that enables the **Zephyr Shell MQTT backend**, run an Eclipse Mosquitto broker in Docker, and send shell commands to the board using the Mosquitto command-line tools. + +This example uses the **NXP FRDM-MCXN947** as the development board. Any other Zephyr-supported board with Ethernet works as well, because the MQTT shell backend is selected entirely through Kconfig and the application contains no board-specific code. To run the example on a different board, follow the same steps and substitute your board's Zephyr identifier in the wizard. The "Switch to a different board" section near the end of this page shows how to change boards on an existing project without recreating it. + +The application does not need networking code in `main.c`. Zephyr starts the shell, network stack, DHCP client, and MQTT shell backend from configuration options in `prj.conf`. + +## How the MQTT shell backend works + +When `CONFIG_SHELL_BACKEND_MQTT=y` is enabled, Zephyr’s MQTT shell backend connects to a broker and uses MQTT topics to carry shell traffic (commands and responses). + +The default topic pattern is: + +| Direction | Topic | +|-----------|-------| +| Commands sent to the board | `/sh/rx` | +| Responses sent from the board | `/sh/tx` | + +The backend derives `` from the hardware device ID, so each board uses a unique topic prefix. You will read this ID from the broker after the board connects for the first time. + +## Create the project + +In the **Workbench for Zephyr** panel, select **New Application** to open the **Create a new Zephyr Application Project** wizard. Fill in the following fields: + +1. **Select West Workspace**: select your initialized West workspace for Zephyr v4.4.0 (for example, `zephyr`). +2. **Select Toolchain**: select `zephyr-sdk-1.0.1`. +3. **Select Board**: select **NXP FRDM-MCXN947 (CPU0)** (Zephyr identifier `frdm_mcxn947/mcxn947/cpu0`). +4. **Application type**: select **Create new application**. +5. **Select Sample project**: select `hello_world`. +6. **Project Name**: enter `mqtt_shell_backend`. +7. **Project Location**: select the directory where you want to create the project (for example, `zephyr/apps`). +8. **Debug preset**: leave checked. +9. **Advanced options**: leave at the defaults. + +Select **Create** to generate the project. + +

+ Workbench for Zephyr Create a new Zephyr Application Project wizard with West Workspace zephyr, Toolchain zephyr-sdk-1.0.1, Board NXP FRDM-MCXN947 CPU0, Application type Create new application, Sample project hello_world, Project Name mqtt_shell_backend, Project Location zephyr/apps, and Debug preset checked. +
+ Create a new Zephyr Application Project wizard +

+ +## Configure the application + +The `hello_world` sample provides a working `CMakeLists.txt`, `prj.conf`, and `src/main.c`. Leave `CMakeLists.txt` unchanged, and replace `prj.conf` and `src/main.c` with the contents below. + +### prj.conf + +```bash +# Shell and MQTT backend +CONFIG_SHELL=y +CONFIG_SHELL_BACKEND_MQTT=y + +# Networking +CONFIG_NETWORKING=y +CONFIG_NET_IPV4=y +CONFIG_NET_TCP=y +CONFIG_NET_DHCPV4=y +CONFIG_NET_CONFIG_SETTINGS=y + +# MQTT broker address +CONFIG_SHELL_MQTT_SERVER_ADDR="192.168.1.233" + +# Optional shell modules and logging +CONFIG_NET_SHELL=y +CONFIG_LOG=y + +# Resource tuning +CONFIG_HEAP_MEM_POOL_SIZE=8192 +CONFIG_MAIN_STACK_SIZE=2048 +CONFIG_NET_PKT_RX_COUNT=16 +CONFIG_NET_BUF_RX_COUNT=32 +``` + +Replace `192.168.1.233` with the IP address of the host running Mosquitto, as seen from the board's Ethernet network. + +The values in the Resource tuning section are the main knobs you will adjust to keep the shell footprint small on Cortex-M while still allowing the network stack and MQTT client to operate reliably. + +### Use a static IPv4 address + +DHCP is convenient, but it is not required. To use a static address, remove: + +```bash +CONFIG_NET_DHCPV4=y +``` + +Then add values that match your network: + +```bash +CONFIG_NET_CONFIG_MY_IPV4_ADDR="192.168.1.50" +CONFIG_NET_CONFIG_MY_IPV4_NETMASK="255.255.255.0" +CONFIG_NET_CONFIG_MY_IPV4_GW="192.168.1.1" +``` + +Keep `CONFIG_NET_CONFIG_SETTINGS=y` enabled so Zephyr applies the network configuration at boot. + +### src/main.c + +The shell and MQTT backend start from Zephyr initialization hooks, so `main.c` can stay minimal: + +```c +int main(void) +{ + return 0; +} +``` + +## Build and flash + +In the **Workbench for Zephyr** panel, select your project and build configuration. Select **Build**, then select **Flash**. + +The FRDM-MCXN947 uses NXP LinkServer as the debug runner. If LinkServer is not installed, follow the Workbench for Zephyr prompt to install or configure it. + +## Create the Mosquitto Docker Compose project + +Create a directory named `mosquitto_shell` on your host computer with the following structure: + +```output +mosquitto_shell/ +|-- docker-compose.yml +`-- mosquitto/ + `-- config/ + `-- mosquitto.conf +``` + +### docker-compose.yml + +```yaml +services: + mosquitto: + image: eclipse-mosquitto:latest + container_name: mosquitto-mqtt + ports: + - "1883:1883" + volumes: + - ./mosquitto/config:/mosquitto/config:ro + - ./mosquitto/data:/mosquitto/data + - ./mosquitto/log:/mosquitto/log + restart: unless-stopped +``` + +### mosquitto/config/mosquitto.conf + +```bash +listener 1883 0.0.0.0 +allow_anonymous true + +persistence true +persistence_location /mosquitto/data/ + +log_dest file /mosquitto/log/mosquitto.log +log_dest stdout +log_type all +``` + +From the `mosquitto_shell` directory, start the broker: + +```bash +docker compose up -d +``` + +Check that the container is running: + +```bash +docker compose ps +``` + +You should see output similar to: + +```output +NAME IMAGE STATUS +mosquitto-mqtt eclipse-mosquitto:latest Up +``` + +The `eclipse-mosquitto` image includes `mosquitto_pub` and `mosquitto_sub`, so you can run both tools from inside the container with `docker exec`. + +### Install Mosquitto directly + +If you prefer not to use Docker, you can install Mosquitto directly on your host computer. This gives you the `mosquitto` broker, `mosquitto_pub`, and `mosquitto_sub` commands locally. + +Install Mosquitto with your operating system package manager: + +```bash +sudo apt install mosquitto mosquitto-clients +``` + +On macOS, use Homebrew: + +```bash +brew install mosquitto +``` + +After installing Mosquitto directly, start the broker using your operating system service manager or run it manually with a local configuration file. In the commands below, replace: + +```bash +docker exec -it mosquitto-mqtt mosquitto_sub -h localhost +``` + +with: + +```bash +mosquitto_sub -h localhost +``` + +Similarly, replace: + +```bash +docker exec -i mosquitto-mqtt mosquitto_pub -h localhost +``` + +with: + +```bash +mosquitto_pub -h localhost +``` + +## Find the device ID + +The MQTT shell backend derives its client ID from the board's hardware UID, so each board connects with topics under `/sh/rx` and `/sh/tx`. There are two ways to read this ID. + +### Option 1: from the board's serial console + +If you have a serial terminal open on the board's UART (or J-Link RTT Viewer attached), the MQTT backend logs the topics it subscribes to and publishes from at boot. A typical FRDM-MCXN947 boot log looks like this: + +```output +*** Booting Zephyr OS build v4.4.0 *** +[00:00:01.654,000] phy_mii: PHY (0) Link speed 100 Mb, full duplex +[00:00:01.654,000] eth_nxp_enet_qos_mac: Link is up +[00:00:01.656,000] shell_mqtt: Network connected +[00:00:01.656,000] app_main: MQTT shell backend demo on frdm_mcxn947 +[00:00:02.656,000] shell_mqtt: DNS resolved for 192.168.1.31:1883 +[00:00:02.656,000] shell_mqtt: mqtt_connect error: -22 +[00:00:03.656,000] shell_mqtt: DNS resolved for 192.168.1.31:1883 +[00:00:03.656,000] shell_mqtt: mqtt_connect error: -22 +[00:00:04.656,000] shell_mqtt: DNS resolved for 192.168.1.31:1883 +[00:00:04.656,000] shell_mqtt: mqtt_connect error: -22 +[00:00:05.656,000] shell_mqtt: DNS resolved for 192.168.1.31:1883 +[00:00:05.656,000] shell_mqtt: mqtt_connect error: -22 +[00:00:06.656,000] shell_mqtt: DNS resolved for 192.168.1.31:1883 +[00:00:06.818,000] shell_mqtt: MQTT client connected! +[00:00:07.823,000] shell_mqtt: MQTT subscribe: ok +[00:00:07.823,000] shell_mqtt: Logs will be published to: 1a2b3c/sh/tx +[00:00:07.823,000] shell_mqtt: Subscribing shell cmds from: 1a2b3c/sh/rx +``` + +The two ` shell_mqtt:` lines at the bottom give you the device ID directly. In this example it is `1a2b3c`. + +{{% notice Note %}} +The `mqtt_connect error: -22` lines you see during the first few seconds are expected. The Zephyr MQTT client retries the connect handshake until the broker accepts it, usually within a few attempts. The connection completes when you see `MQTT client connected!`, followed by `MQTT subscribe: ok`. +{{% /notice %}} + +### Option 2: from the broker side + +If you do not have a serial terminal open, watch every shell-output topic with a wildcard: + +```bash +docker exec -it mosquitto-mqtt mosquitto_sub -h localhost -t "+/sh/tx" -v +``` + +When the board connects, it publishes its shell prompt to `/sh/tx`. The topic prefix on the first message is the device ID: + +```output +1a2b3c/sh/tx rtt:~$ +``` + +You can also confirm the same value from the broker's connection log: + +```bash +docker logs mosquitto-mqtt | grep "as 1a2b3c" +``` + +```output +New client connected from 192.168.65.1:65496 as 1a2b3c (p4, c0, k60). +``` + +## Subscribe to shell output + +Narrow the subscription to your board's response topic only (replace `1a2b3c` with your device ID): + +```bash +docker exec -it mosquitto-mqtt mosquitto_sub -h localhost -t "1a2b3c/sh/tx" -v +``` + +Keep this terminal open. Every shell response from the board will print here. + +## Send shell commands + +Open a second terminal to publish commands to the board: + +```bash +printf 'kernel version\n' | docker exec -i mosquitto-mqtt mosquitto_pub -h localhost -t "1a2b3c/sh/rx" -s +``` + +The command is published to Mosquitto, the board executes it, and the response appears in the first terminal: + +```output +1a2b3c/sh/tx Zephyr version 4.4.0 +``` + +Try the following commands: + +| Command | Description | +|---------|-------------| +| `kernel version` | Print the Zephyr version string. | +| `kernel uptime` | Print the time since boot. | +| `kernel thread list` | Print the thread list and stack usage. | +| `net iface` | Print network interface configuration, including the assigned IPv4 address. | +| `net ping ` | Send ICMP echo requests to a reachable host (for example, your gateway). | +| `device list` | Print registered Zephyr devices. | +| `help` | Print available shell modules and commands. | + +The `net` commands are available because `CONFIG_NET_SHELL=y` was set in `prj.conf`. Without that option, only the `kernel`, `device`, and `shell` modules are exposed. + +Example output for `kernel uptime`: + +```output +1a2b3c/sh/tx Uptime: 55310 ms +``` + +Example output for `kernel thread list` on the FRDM-MCXN947 (truncated; the full list shows the network and Ethernet driver threads): + +```output +1a2b3c/sh/tx Scheduler: 1046 since last call +Threads: +*0x300015d0 shell_mqtt + options: 0x0, priority: 14 timeout: 0 + state: queued, entry: 0x100069e5 + stack size 2048, unused 1096, usage 952 / 2048 (46 %) + + 0x30001c30 sh_mqtt_workq + options: 0x0, priority: -9 timeout: 800 + state: pending, entry: 0x100223cd + stack size 2048, unused 1160, usage 888 / 2048 (43 %) + + 0x30002688 conn_mgr_monitor + options: 0x0, priority: -1 timeout: 0 + state: pending, entry: 0x1001ea0d + stack size 512, unused 264, usage 248 / 512 (48 %) + + 0x300027c0 ENETQOS_RX + options: 0x0, priority: -13 timeout: 0 + state: pending, entry: 0x100223cd + stack size 1024, unused 752, usage 272 / 1024 (26 %) + + 0x300028b0 idle + options: 0x1, priority: 15 timeout: 0 + state: , entry: 0x1003a335 + stack size 320, unused 256, usage 64 / 320 (20 %) +``` + +The `*` next to `shell_mqtt` marks the running thread, which is the shell that just executed the command. Note that responses larger than the MQTT buffer are split across multiple publishes; `mosquitto_sub -v` reassembles them sequentially under the `1a2b3c/sh/tx` topic prefix. + +Example output for `net iface` on the FRDM-MCXN947 (truncated to the IPv4 section): + +```output +1a2b3c/sh/tx Default interface: 1 + +Interface eth0 (0x30000c70) (Ethernet) [1] +=================================== +Link addr : XX:XX:XX:XX:XX:XX +MTU : 1500 +Flags : AUTO_START,IPv4,IPv6 +Status : oper=UP, admin=UP, carrier=ON +Ethernet link speed: 100 Mbits full-duplex +IPv4 unicast addresses (max 1): + 192.168.1.41/255.255.255.0 DHCP preferred +IPv4 gateway : 192.168.1.1 +DHCPv4 state : bound +DHCPv4 server : 192.168.1.1 +``` + +Example output for `net ping 192.168.1.1` (board pinging its gateway): + +```output +1a2b3c/sh/tx PING 192.168.1.1 +28 bytes from 192.168.1.1 to 192.168.1.41: icmp_seq=1 ttl=64 time=0 ms +28 bytes from 192.168.1.1 to 192.168.1.41: icmp_seq=2 ttl=64 time=0 ms +28 bytes from 192.168.1.1 to 192.168.1.41: icmp_seq=3 ttl=64 time=0 ms +``` + +Replace `192.168.1.1` with the gateway address shown by `net iface`. The board sends three ICMP echo requests by default. + +{{% notice Note %}} +The MQTT shell backend executes a command after it receives a newline character. The `printf 'kernel version\n' | ... mosquitto_pub -s` form sends the command with the required newline. +{{% /notice %}} + +## Switch to a different board + +The application is portable across any Zephyr-supported board with Ethernet, because the MQTT backend is selected through Kconfig and there is no board-specific code in `main.c`. You do not need to recreate the project to test it on another board. + +To change the target board on an existing project: + +1. Open the **Workbench for Zephyr** panel in the VS Code Activity Bar. +2. Expand the **Applications** section. The project you created appears with its current board name underneath. +3. Right-click the board name and select **Change board**. Pick a new board from the list (for example, an STM32 Nucleo, Nordic nRF52, or another Cortex-M board with Ethernet). +4. Right-click the application and select **Clean** to remove the previous build artifacts. +5. Right-click the application and select **Build (pristine)** to rebuild the project from scratch with the new board configuration. + +After the pristine build completes, flash the board as before. The same `prj.conf` and `main.c` work without changes, and the MQTT backend connects as soon as the new board acquires an IPv4 address. + +{{% notice Note %}} +A pristine build is required when you change the board because Workbench for Zephyr caches board-specific generated files (device tree, Kconfig, linker script) in the build directory. Without a clean rebuild, the previous board's configuration leaks into the new build and produces incorrect binaries. +{{% /notice %}} + +## What's next? + +You now have a working Zephyr shell over MQTT on the FRDM-MCXN947. In the next section, you will enable the UART shell backend on the FRDM-MCXN947 and interact with the shell through a USB serial connection using PuTTY on Windows or the built-in `screen` utility on macOS diff --git a/content/learning-paths/embedded-and-microcontrollers/zephyr_shell/4_uart_shell.md b/content/learning-paths/embedded-and-microcontrollers/zephyr_shell/4_uart_shell.md new file mode 100644 index 0000000000..f757287db2 --- /dev/null +++ b/content/learning-paths/embedded-and-microcontrollers/zephyr_shell/4_uart_shell.md @@ -0,0 +1,188 @@ +--- +title: UART shell +weight: 5 + +### FIXED, DO NOT MODIFY +layout: learningpathall +--- + +## Set up the UART shell example + +In this section, you will build a Zephyr application that enables the UART shell backend, flash it with Workbench for Zephyr, connect with a UART terminal application, and run shell commands over the USB serial connection. + +The example uses the **FRDM-MCXN947** because it provides an onboard CMSIS-DAP / LinkServer debug interface together with a USB UART connection that can be accessed from a serial terminal application such as PuTTY on Windows or the built-in `screen` utility on macOS. + +The "Switch to a different board" section near the end of this page shows how to change boards on an existing project without recreating it. + +UART shell access uses the board's USB serial interface and does not require additional debug hardware or network connectivity. + +The Zephyr UART shell backend maps shell input and output to the active UART console. + +## Create the project + +In the **Workbench for Zephyr** panel, select **New Application** to open the **Create a new Zephyr Application Project** wizard. Fill in the following fields: + +1. **Select West Workspace**: select your initialized West workspace for Zephyr v4.4.0. +2. **Select Toolchain**: select `zephyr-sdk-1.0.1`. +3. **Select Board**: select **FRDM-MCXN947** (Zephyr identifier `frdm_mcxn947/mcxn947/cpu0`). +4. **Application type**: select **Create new application**. +5. **Select Sample project**: select `hello_world`. +6. **Project Name**: enter `frdm_uart_shell`. +7. **Project Location**: select the directory where you want to create the project. +8. **Debug preset**: leave checked. +9. **Advanced options**: leave at the defaults. + +Select **Create** to generate the project. + +## Configure the application + +The `hello_world` sample provides a working `CMakeLists.txt`, `prj.conf`, and `src/main.c`. Leave `CMakeLists.txt` unchanged, and replace `prj.conf` and `src/main.c` with the contents below. + +### prj.conf + +```bash +CONFIG_SHELL=y +CONFIG_LOG=y + +CONFIG_SERIAL=y +CONFIG_CONSOLE=y +CONFIG_UART_CONSOLE=y +CONFIG_SHELL_BACKEND_SERIAL=y + +CONFIG_MAIN_STACK_SIZE=2048 +``` + +The UART shell backend routes shell input and output through the board's USB serial interface. + +### src/main.c + +```c +#include + +LOG_MODULE_REGISTER(app_main, LOG_LEVEL_INF); + +int main(void) +{ + LOG_INF("UART shell backend demo on %s", CONFIG_BOARD); + LOG_INF("Open PuTTY at 115200 baud and use the uart:~$ prompt"); + return 0; +} +``` + +No shell initialization code is required in `main.c`. Zephyr registers and starts the UART shell backend from the Kconfig options in `prj.conf`. + +## Build and flash + +Connect the FRDM-MCXN947 board to your host computer over USB. + +In the **Workbench for Zephyr** panel, select your project and build configuration. Select **Build**, then select **Flash**. + +The FRDM-MCXN947 uses the onboard CMSIS-DAP / LinkServer interface for flashing and debugging. + +## Connect with a UART terminal + +After flashing, the board resets and starts running. Open a UART terminal application and connect to the board's serial port. + +### Windows with PuTTY + +Configure PuTTY with: + +- **Connection type**: `Serial` +- **Serial line**: your board's COM port +- **Speed**: `115200` + +Select **Open** to connect. + +

+ PuTTY Installation +
+ PuTTY Serial Terminal Configuration +

+ +### macOS with screen + +Open a terminal window and identify the serial device: + +```bash +ls /dev/tty.* +``` + +Connect with: + +```bash +screen /dev/tty.usbmodemXXXX 115200 +``` + +Replace `/dev/tty.usbmodemXXXX` with the serial device shown on your system. + + +## Check the shell prompt + +In your UART terminal application, you should see the boot log followed by the shell prompt: + +```output +uart:~$ *** Booting Zephyr OS build v4.4.0 *** +uart:~$ [00:00:00.001,037] app_main: UART shell backend demo on frdm_mcxn947 +uart:~$ [00:00:00.001,037] app_main: Open PuTTY at 115200 baud and use the uart:~$ prompt +uart:~$ +``` + +The `uart:~$` prompt confirms that the UART shell backend is active. + +The boot banner and the `` log lines are prefixed with `uart:~$` because `SHELL_LOG_BACKEND` is enabled by default when `CONFIG_SHELL=y` and `CONFIG_LOG=y` are both set, so log output is routed through the active shell backend. + +## Run shell commands + +Type each of the following commands at the `uart:~$` prompt: + +```bash +kernel version +kernel uptime +kernel thread list +``` + +

+ Uart Shell Output +
+ Uart Shell Output +

+ +The `*` next to `shell_uart` in the thread list marks the currently running thread, which is the shell that just executed the command. + +{{% notice Note %}} +Application log messages such as `LOG_INF` and `LOG_WRN` appear in the terminal together with the shell prompt. This is expected when both `CONFIG_SHELL=y` and `CONFIG_LOG=y` are enabled. +{{% /notice %}} + +## Debug while UART shell is connected + +You can run a debug session in Workbench for Zephyr while the UART terminal remains connected. + +To start debugging, select your build configuration in the **Workbench for Zephyr** panel and select **Debug**. You can set breakpoints, inspect variables, and step through code in Visual Studio Code while the UART shell remains open. + +When execution stops at a breakpoint, shell output pauses with the target. After you continue execution, the UART shell becomes responsive again. + +## Switch to a different board + +The application is portable across many Zephyr-supported boards because the UART shell backend is selected through Kconfig and there is no board-specific code in `main.c`. + +To change the target board on an existing project: + +1. Open the **Workbench for Zephyr** panel in the VS Code Activity Bar. +2. Expand the **Applications** section. +3. Right-click the board name and select **Change board**. +4. Right-click the application and select **Clean**. +5. Right-click the application and select **Build (pristine)**. + +{{% notice Note %}} +A pristine build is required when you change the board because Workbench for Zephyr caches board-specific generated files in the build directory. +{{% /notice %}} + +## What you accomplished + +You built and flashed a Zephyr application that enables the UART shell backend on the FRDM-MCXN947. You connected with a UART terminal application, opened the Zephyr shell over USB serial, and ran Zephyr shell commands from the host computer. \ No newline at end of file diff --git a/content/learning-paths/embedded-and-microcontrollers/zephyr_shell/_index.md b/content/learning-paths/embedded-and-microcontrollers/zephyr_shell/_index.md new file mode 100644 index 0000000000..a14d5b302d --- /dev/null +++ b/content/learning-paths/embedded-and-microcontrollers/zephyr_shell/_index.md @@ -0,0 +1,51 @@ +--- +title: Build a Lightweight Shell on Cortex-M with Zephyr RTOS + +minutes_to_complete: 30 + +who_is_this_for: This learning path is for embedded developers targeting Arm Cortex-M microcontrollers who want a small, configurable command-line shell (CLI) for bring-up, diagnostics, and interactive testing using Zephyr RTOS. You will use VS Code with the Workbench for Zephyr extension to build, flash, and debug on supported boards. + +learning_objectives: + - Enable and tailor Zephyr Shell (Kconfig/prj.conf) to produce a minimal CLI footprint + - Build, flash, and debug the shell-enabled Zephyr app on an Arm Cortex-M board (UART/RTT logging, breakpoints) + +prerequisites: + - Basic familiarity with embedded C programming + - Visual Studio Code with the Workbench for Zephyr extension installed and configured. Follow the [Build Zephyr projects with Workbench for Zephyr in VS Code](/learning-paths/embedded-and-microcontrollers/zephyr_vsworkbench/) Learning Path if you have not done this yet. + - A Zephyr-supported Arm Cortex-M board (for example, NXP FRDM-MCXN947) + - Windows 10+ (64-bit), macOS with Homebrew, or Linux (preferably Ubuntu 20.04+) + +author: + - Ayoub Bourjilat + - Odin Shen + - Akash Malik + +skilllevels: Introductory +subjects: RTOS Fundamentals +armips: + - Cortex-M +operatingsystems: + - RTOS +tools_software_languages: + - Zephyr + - C + +further_reading: + - resource: + title: Zephyr Project Documentation + link: https://docs.zephyrproject.org/latest/index.html + type: documentation + - resource: + title: Workbench for Zephyr Official Website + link: https://z-workbench.com/ + type: website + - resource: + title: AC6 Zephyr Training + link: https://www.ac6-training.com/en/cours.php/cat_oRT/ref_oRT5/zephyr-rtos-programming + type: website + +# ================================================================================ +weight: 1 # _index.md always has weight of 1 to order correctly +layout: "learningpathall" # All files under learning paths have this same wrapper +learning_path_main_page: "yes" # This should be surfaced when looking for related content. Only set for _index.md of learning path content. +--- diff --git a/content/learning-paths/embedded-and-microcontrollers/zephyr_shell/_next-steps.md b/content/learning-paths/embedded-and-microcontrollers/zephyr_shell/_next-steps.md new file mode 100644 index 0000000000..c3db0de5a2 --- /dev/null +++ b/content/learning-paths/embedded-and-microcontrollers/zephyr_shell/_next-steps.md @@ -0,0 +1,8 @@ +--- +# ================================================================================ +# FIXED, DO NOT MODIFY THIS FILE +# ================================================================================ +weight: 21 # Set to always be larger than the content in this path to be at the end of the navigation. +title: "Next Steps" # Always the same, html page title. +layout: "learningpathall" # All files under learning paths have this same wrapper for Hugo processing. +--- diff --git a/content/learning-paths/embedded-and-microcontrollers/zephyr_shell/images/jlink_rttviewer-output.png b/content/learning-paths/embedded-and-microcontrollers/zephyr_shell/images/jlink_rttviewer-output.png new file mode 100644 index 0000000000..b213286993 Binary files /dev/null and b/content/learning-paths/embedded-and-microcontrollers/zephyr_shell/images/jlink_rttviewer-output.png differ diff --git a/content/learning-paths/embedded-and-microcontrollers/zephyr_shell/images/jlink_rttviewer_configuration.png b/content/learning-paths/embedded-and-microcontrollers/zephyr_shell/images/jlink_rttviewer_configuration.png new file mode 100644 index 0000000000..b6d8fbd8a9 Binary files /dev/null and b/content/learning-paths/embedded-and-microcontrollers/zephyr_shell/images/jlink_rttviewer_configuration.png differ diff --git a/content/learning-paths/embedded-and-microcontrollers/zephyr_shell/images/putty_installation.png b/content/learning-paths/embedded-and-microcontrollers/zephyr_shell/images/putty_installation.png new file mode 100644 index 0000000000..a9bbcdb6bb Binary files /dev/null and b/content/learning-paths/embedded-and-microcontrollers/zephyr_shell/images/putty_installation.png differ diff --git a/content/learning-paths/embedded-and-microcontrollers/zephyr_shell/images/uart_shell_output.png b/content/learning-paths/embedded-and-microcontrollers/zephyr_shell/images/uart_shell_output.png new file mode 100644 index 0000000000..9aef493f95 Binary files /dev/null and b/content/learning-paths/embedded-and-microcontrollers/zephyr_shell/images/uart_shell_output.png differ diff --git a/content/learning-paths/embedded-and-microcontrollers/zephyr_shell/images/wz_new_project.png b/content/learning-paths/embedded-and-microcontrollers/zephyr_shell/images/wz_new_project.png new file mode 100644 index 0000000000..4b305faae9 Binary files /dev/null and b/content/learning-paths/embedded-and-microcontrollers/zephyr_shell/images/wz_new_project.png differ