From 4abbd6b054f8c4a243787b6151f4f1c4a8240458 Mon Sep 17 00:00:00 2001 From: thorenscientific Date: Thu, 18 Jun 2026 18:15:55 -0700 Subject: [PATCH 1/5] Add ADI DataX diagrams, edit intro section. --- docs/learning/tools_for_ls/adi_datax_diag.png | 3 + .../tools_for_ls/adi_datax_diag_w_apps.png | 3 + docs/learning/tools_for_ls/index.rst | 125 ++++++++++++------ 3 files changed, 91 insertions(+), 40 deletions(-) create mode 100644 docs/learning/tools_for_ls/adi_datax_diag.png create mode 100644 docs/learning/tools_for_ls/adi_datax_diag_w_apps.png diff --git a/docs/learning/tools_for_ls/adi_datax_diag.png b/docs/learning/tools_for_ls/adi_datax_diag.png new file mode 100644 index 00000000000..60b83d468f0 --- /dev/null +++ b/docs/learning/tools_for_ls/adi_datax_diag.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:67825fdcb74bf82ae549375f194cabcd689406bf2cdd313d5d8da4a002c0a3d3 +size 166467 diff --git a/docs/learning/tools_for_ls/adi_datax_diag_w_apps.png b/docs/learning/tools_for_ls/adi_datax_diag_w_apps.png new file mode 100644 index 00000000000..1074efbeec9 --- /dev/null +++ b/docs/learning/tools_for_ls/adi_datax_diag_w_apps.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6aa9c7d5f18b53d06a4549f0ccde10f99f7811458e2d47c17c039af2155aea7a +size 380375 diff --git a/docs/learning/tools_for_ls/index.rst b/docs/learning/tools_for_ls/index.rst index 5596583016e..ef78b3c355a 100644 --- a/docs/learning/tools_for_ls/index.rst +++ b/docs/learning/tools_for_ls/index.rst @@ -1,7 +1,7 @@ .. _datax-tools-for-ls-system-design: -ADI DataX Tools for Low Speed Mixed Signal System Design --------------------------------------------------------- +ADI DataX™ Tools for Low Speed Mixed Signal System Design +--------------------------------------------------------- .. note:: @@ -10,44 +10,89 @@ ADI DataX Tools for Low Speed Mixed Signal System Design Introduction ~~~~~~~~~~~~ -The goal of this tutorial is to equip the reader with a collection of `ADI DataX -`__-enabled hardware and -software tools for developing low-speed mixed-signal applications. Complete -written instructions follow, as well as a video guide and a slide deck that can -be used for delivering as a hands-on workshop. - -But first - what exactly does “Low Speed” mean? In the context of this tutorial, -it means that timing is not very critical. Signals are either completely static -or moving slowly such that it doesn't matter if the instant that an ADC samples -the signal wiggles around a bit relative to the previous sampling. While clock -jitter is one source of this uncertainty, software delays (such as the time -between a timer interrupt and the assertion of a “convert” edge) will likely be -dominant. Important parameters in low-speed applications are offset, gain error, -linearity, and temperature drift. “Noise” in a low-speed application is -typically synonymous with resolution, and can be roughly measured by applying a -quiet input signal (like a short circuit) and taking a histogram of the output -readings. AC performance metrics such as signal to noise ratio and total -harmonic distortion extracted from a Fourier transform of the data will not be -considered. In contrast - sample jitter is important in a “high speed” -application. If you are measuring signal to noise ratio, the Signal to Noise -ratio (SNR) can be no greater than: - -:math:`SNR <= -20 * log(2*\pi*f_{IN}*t_{j})` - -Where: -:math:`f_{IN}` is the analog input frequency in Hz -:math:`t_{j}` is the RMS jitter in seconds RMS - -In this tutorial, we will use a transistor curve tracer as an example -application that involves setting voltages and currents, reading voltages and -currents, doing some basic math, and displaying a result. Each reading will be -treated independently, no correlation to previous or future readings. We will -NOT be measuring AC Signal to Noise Ratio (SNR), Total Harmonic Distortion -(THD), nor measuring steps, wiggles, or any other situation where precise timing -is required. Rest assured, there are lots of very interesting applications in -this category; consider a vector network analyzer (VNA) - set an excitation -frequency, measure forward and reflected power and phase, do some math, step, -repeat, and when done, display the results. +`ADI DataX™ `__ is a highly +adaptable, open technology stack that bridges the gap between signal chains and +applications across a wide range of processing platforms, operating systems, and +software ecosystems to enable physically intelligent systems. + +Rather than being a single library or runtime, ADI DataX is a collection of +reusable software building blocks, including device drivers, middleware, FPGA +IP, and reference designs - aligned under a common architecture and enablement +model. This concept is depicted somewhat abstractly in :numref:`fig-datax_diag` + +.. _fig-datax_diag: + +.. figure:: adi_datax_diag.png + :width: 700px + :height: 400px + :align: center + + ADI DataX Layers + +The goal of this tutorial is to bring :numref:`fig-datax_diag` to life in a +tangible way by working through two application examples that map into the +diagram as shown in :numref:`fig-datax_diag_w_apps` + +.. _fig-datax_diag_w_apps: + +.. figure:: adi_datax_diag_w_apps.png + :width: 700px + :height: 400px + :align: center + + Applications mappped onto ADI DataX layers + +In this tutorial, we will use a transistor curve tracer and temperature sensor +as example applications. The temperature sensor simply involves reading +temperature, doing some math to convert units if necessary, and displaying the +result. The curve tracer involves setting voltages and currents, reading +voltages and currents, doing some basic math, and displaying a result. Each +reading will be treated independently, no correlation to previous or future +readings. We will NOT be measuring AC Signal to Noise Ratio (SNR), Total +Harmonic Distortion (THD), nor measuring steps, wiggles, or any other situation +where precise timing is required. Rest assured, there are lots of very +interesting applications in this category; consider a vector network analyzer +(VNA) - set an excitation frequency, measure forward and reflected power and +phase, do some math, step, repeat, and when done, display the results. + +We will start with a Linux-based workflow, leveraging Linux device drivers +pre-built in ADI Kuiper Linux, Pyadi-iio. We'll then show how to migrate to +other languages (C, C#, MATLAB), other processing platforms (ARM-based +MAX32xxx, Raspberry Pi Pico), ecosystems (no-OS / bare metal, Zephyr), and +middleware layers (GNURadio, ROS). With ADI DataX, switching between these +layers is cheap - there is little to no barrier to getting a proof of concept up +and running in Linux, then switching to bare metal or Zephyr as development +continues. + +Complete written instructions follow, as well as a video guide and a slide deck +that can be used for delivering as a hands-on workshop. + +.. NOTE:: + What exactly does “Low Speed” mean? In the context of this tutorial, it means + that timing is not very critical. Signals are either completely static + or moving slowly such that it doesn't matter if the instant that an ADC samples + the signal wiggles around a bit relative to the previous sampling. While clock + jitter is one source of this uncertainty, software delays (such as the time + between a timer interrupt and the assertion of a “convert” edge) will likely be + dominant. Important parameters in low-speed applications are offset, gain error, + linearity, and temperature drift. “Noise” in a low-speed application is + typically synonymous with resolution, and can be roughly measured by applying a + quiet input signal (like a short circuit) and taking a histogram of the output + readings. AC performance metrics such as signal to noise ratio and total + harmonic distortion extracted from a Fourier transform of the data will not be + considered. In contrast - sample jitter is important in a “high speed” + application. If you are measuring signal to noise ratio, the Signal to Noise + ratio (SNR) can be no greater than: + + :math:`SNR <= -20 * log(2*\pi*f_{IN}*t_{j})` + + Where: + + :math:`f_{IN}` is the analog input frequency in Hz + + :math:`t_{j}` is the RMS jitter in seconds RMS + + Materials ~~~~~~~~~ From 58df09966b3acb7238d8845d602bda39e11bb96b Mon Sep 17 00:00:00 2001 From: Evelyn Plesca Date: Sat, 4 Jul 2026 00:40:56 +0300 Subject: [PATCH 2/5] learning/tools_for_ls: Add ROS2 integration section Signed-off-by: Evelyn Plesca --- docs/learning/tools_for_ls/index.rst | 20 + .../tools_for_ls/ros2_integration/index.rst | 400 ++++++++++++++++++ .../ros2_integration/ros2_architecture.png | 3 + .../ros2_integration/servo_feedback.png | 3 + .../ros2_integration/topic_echo.png | 3 + .../ros2_integration/topic_list.png | 3 + 6 files changed, 432 insertions(+) create mode 100644 docs/learning/tools_for_ls/ros2_integration/index.rst create mode 100644 docs/learning/tools_for_ls/ros2_integration/ros2_architecture.png create mode 100644 docs/learning/tools_for_ls/ros2_integration/servo_feedback.png create mode 100644 docs/learning/tools_for_ls/ros2_integration/topic_echo.png create mode 100644 docs/learning/tools_for_ls/ros2_integration/topic_list.png diff --git a/docs/learning/tools_for_ls/index.rst b/docs/learning/tools_for_ls/index.rst index ef78b3c355a..44218e74af6 100644 --- a/docs/learning/tools_for_ls/index.rst +++ b/docs/learning/tools_for_ls/index.rst @@ -239,6 +239,26 @@ Next Steps: Developing on a remote host Next Steps: Other languages (C++, C#, MATLAB, etc.) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Next Steps: ROS2 Integration +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +While the previous exercises used Python and pyadi-iio, the IIO framework can +also be integrated with **ROS2** (Robot Operating System 2) for robotics and +automation applications. The `adi_iio `__ +ROS2 package provides a bridge between IIO devices and the ROS2 ecosystem, +exposing device attributes as ROS2 topics and services. + +In this section, we will run a servo motor control demo that uses the +ADALM-LSMSPG to generate position commands and read feedback, demonstrating +how IIO devices can be integrated into a ROS2-based control system. + +:doc:`Continue to ROS2 Integration Tutorial ` + +.. toctree:: + :hidden: + + ros2_integration/index + IIO as a Tool for Migrating to an Embedded Implementation ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/docs/learning/tools_for_ls/ros2_integration/index.rst b/docs/learning/tools_for_ls/ros2_integration/index.rst new file mode 100644 index 00000000000..14ac6c668a2 --- /dev/null +++ b/docs/learning/tools_for_ls/ros2_integration/index.rst @@ -0,0 +1,400 @@ +.. _datax-ros2-integration: + +ROS2 Integration with IIO Devices +--------------------------------- + +This tutorial walks you through running a servo motor control demo using the +`adi_iio `__ ROS2 package. You +will use Docker to run the demo nodes, inspect the ROS2 system with standard +CLI tools, and explore how the code maps IIO attributes to ROS2 topics and +services. + +.. note:: + + The ``adi_iio`` package handles low-level IIO communication, while + application nodes interact with devices through standard ROS2 interfaces. + No direct libiio knowledge is required. + +Hardware Prerequisites +~~~~~~~~~~~~~~~~~~~~~~ + +- **Raspberry Pi 5** running ADI Kuiper Linux +- **ADALM-LSMSPG** board connected to the Raspberry Pi via the 40-pin ribbon cable + +.. note:: + + This demo simulates servo motor control using readings from the AD5592r and + AD5593r. No actual servo motor hardware is required — the demo generates + position commands and reads ADC feedback to demonstrate the ROS2/IIO + integration pattern. + +Software Prerequisites +~~~~~~~~~~~~~~~~~~~~~~ + +- **Docker** and **Docker Compose** installed on the Raspberry Pi +- Clone the `adi_ros2 `__ repository + and build the base Docker image: + +.. code-block:: bash + + analog@analog:~$ git clone https://github.com/analogdevicesinc/adi_ros2.git + analog@analog:~$ cd adi_ros2 + analog@analog:~/adi_ros2$ docker compose -f compose.build.yml build base + +- Clone the `iio_ros2 `__ repository + and checkout the ``adalm-lsmspg-example`` branch (contains the ADALM-LSMSPG + example): + +.. code-block:: bash + + analog@analog:~$ git clone -b adalm-lsmspg-example https://github.com/plescaevelyn/iio_ros2.git + +Architecture Overview +~~~~~~~~~~~~~~~~~~~~~ + +The ROS2 architecture separates device communication from application logic: + +.. figure:: ros2_architecture.png + :width: 40em + :align: center + + ROS2 ADALM-LSMSPG architecture + +The ``adi_iio_node`` acts as a bridge between the IIO subsystem and ROS2. It +connects to the ADALM-LSMSPG via the local IIO backend and exposes each device +attribute as either a ROS2 topic (for continuous streaming) or service (for +on-demand reads/writes). This allows application nodes to interact with the +hardware using standard ROS2 patterns — no direct IIO knowledge required. + +The demo simulates a servo control loop: ``sweep_generator`` publishes position +commands, ``servo_commander`` converts them to DAC values and writes to the +AD5592r, and ``servo_feedback`` reads ADC values to simulate position/current +sensing. + +Step 1: Verify the Hardware +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Before running ROS2, confirm that the ADALM-LSMSPG is properly connected and +the IIO devices are accessible. The Raspberry Pi should be running ADI Kuiper +Linux with the ADALM-LSMSPG overlay configured (as described in the earlier +sections of this tutorial). + +Run ``iio_info`` to verify the IIO context: + +.. code-block:: bash + + analog@analog:~$ iio_info -u local: + +You should see the ``ad5592r``, ``ad5593r``, and ``lm75`` devices listed. If +not, check that the device tree overlay is enabled and the ribbon cable is +properly connected. + +Step 2: Build the Docker Image +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The demo runs inside Docker containers, which bundle ROS2, the ``adi_iio`` +package, and all dependencies. This ensures a consistent environment without +needing to install ROS2 natively on the Raspberry Pi. + +Navigate to the example directory and build the image: + +.. code-block:: bash + + analog@analog:~$ cd iio_ros2/examples/adalm_lsmspg/docker + analog@analog:~/iio_ros2/examples/adalm_lsmspg/docker$ docker compose build + +This creates a Docker image containing: + +- The ``adi_iio`` ROS2 package — provides the IIO-to-ROS2 bridge node +- The ``adalm_lsmspg`` example package — contains the servo demo nodes +- Runtime dependencies — libiio, numpy, and scipy + +Step 3: Run the Demo +~~~~~~~~~~~~~~~~~~~~ + +Launch the demo using Docker Compose: + +.. code-block:: bash + + analog@analog:~/iio_ros2/examples/adalm_lsmspg/docker$ docker compose up + +This command reads the ``compose.yml`` file and starts two containers. Let's +look at what it does: + +.. code-block:: yaml + :caption: compose.yml — Docker Compose configuration + + services: + adi_iio: + # ... build configuration ... + command: ros2 run adi_iio adi_iio_node --ros-args -p uri:="ip:analog.local" + + demo: + # ... container configuration ... + depends_on: + - adi_iio + command: > + bash -c "sleep 3 && ros2 launch adalm_lsmspg adalm_lsmspg_bringup.launch.py" + + shell: + # ... interactive shell for debugging (profiles: [debug]) ... + +The ``adi_iio`` service starts first, launching the ``adi_iio_node`` which +connects to the IIO context at ``ip:analog.local``. The ``demo`` service waits +3 seconds for ``adi_iio_node`` to initialize, then launches the application +nodes via the bringup launch file. The ``shell`` service is only started when +using the debug profile (``docker compose --profile debug up``). + +Once running, you will see log output from all the nodes. The ``adi_iio_node`` +initializes first, connecting to the IIO context and discovering the devices. +Then the application nodes start: ``sweep_generator`` begins publishing position +commands, ``servo_commander`` writes DAC values, and ``servo_feedback`` reads +ADC values and publishes feedback. + +.. figure:: servo_feedback.png + :width: 45em + :align: center + + Docker compose output showing the running demo + +The demo runs continuously, sweeping the simulated servo position back and +forth. Leave this terminal running and open a new one for the next step. + +Step 4: Inspect the ROS2 System +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +With the demo running, we can use standard ROS2 command-line tools to inspect +the system. Open a new terminal and start a shell inside the Docker environment: + +.. code-block:: bash + + analog@analog:~/iio_ros2/examples/adalm_lsmspg/docker$ docker compose run --rm shell + +This drops you into a container with ROS2 tools available. First, list the +active nodes to see all the running components: + +.. code-block:: bash + + root@analog:/# ros2 node list + +You should see four nodes: ``/adi_iio_node`` (the IIO bridge) and the three +application nodes (``/servo_commander``, ``/servo_feedback``, ``/sweep_generator``). + +Next, list the available topics. The ``adi_iio_node`` creates topics for each +IIO attribute, and the application nodes create their own topics for the servo +control loop: + +.. code-block:: bash + + root@analog:/# ros2 topic list + +.. figure:: topic_list.png + :width: 35em + :align: center + + ROS2 topic list output + +Notice the IIO attribute topics like ``/ad5592r/input_voltage1/raw`` — these +are automatically generated by ``adi_iio_node`` for each channel. The +application topics like ``/servo/position_cmd`` and ``/servo/position_feedback`` +are created by the demo nodes. + +To see live data, echo one of the feedback topics. This shows the simulated +position values being published by ``servo_feedback``: + +.. code-block:: bash + + root@analog:/# ros2 topic echo /servo/position_feedback + +.. figure:: topic_echo.png + :width: 25em + :align: center + + Position feedback topic output + +You can also interact with IIO attributes directly using ROS2 services. For +example, read the temperature from the LM75 sensor: + +.. code-block:: bash + + root@analog:/# ros2 service call /adi_iio_node/AttrReadString adi_iio/srv/AttrReadString \ + "{attr_path: 'lm75/input_temp0/raw'}" + +This demonstrates that any ROS2 node can access IIO device attributes without +needing to know anything about libiio — the ``adi_iio_node`` handles all the +low-level communication. + +Step 5: Cleanup +~~~~~~~~~~~~~~~ + +When finished, stop the demo by pressing ``Ctrl+C`` in the terminal running +``docker compose up``, or run the following from another terminal: + +.. code-block:: bash + + analog@analog:~/iio_ros2/examples/adalm_lsmspg/docker$ docker compose down + +This stops and removes the containers. The Docker images remain cached for +faster startup next time. + +How the Code Works +~~~~~~~~~~~~~~~~~~ + +The servo demo consists of three application nodes, each implemented as a +Python ROS2 node. The source code is located in +`examples/adalm_lsmspg/adalm_lsmspg/ +`__. + +sweep_generator — Position Command Generation +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The ``sweep_generator`` node +(`sweep_generator.py +`__) +generates a sinusoidal position sweep from 0 to 180 degrees and publishes to +the ``/servo/position_cmd`` topic. The core logic computes the angle using a +sine wave: + +.. code-block:: python + :caption: sweep_generator.py — lines 68-73 + + def timer_callback(self): + self.time_elapsed += self.timer_period + + mid = (self.min_angle + self.max_angle) / 2.0 + amplitude = (self.max_angle - self.min_angle) / 2.0 + angle = mid + amplitude * math.sin(2 * math.pi * self.sweep_rate * self.time_elapsed) + +This produces smooth oscillation between the configured minimum and maximum +angles. The sweep rate (default 0.5 Hz) and update rate (default 10 Hz) are +configurable via ROS2 parameters. + +servo_commander — DAC Output Control +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The ``servo_commander`` node +(`servo_commander.py +`__) +subscribes to position commands and writes corresponding DAC values to the +AD5592r. It demonstrates two key IIO service interactions: + +**Reading the DAC scale factor** — Before writing values, the node reads the +scale attribute to convert millivolts to raw DAC counts: + +.. code-block:: python + :caption: servo_commander.py — lines 99-103 + + def read_scale(self): + request = AttrReadString.Request() + request.attr_path = self.get_parameter('dac_scale').value + future = self.attr_read_string_client.call_async(request) + future.add_done_callback(self.scale_response_callback) + +**Enabling topic-based writes** — The node enables a write topic for the DAC +raw attribute, allowing it to publish values directly: + +.. code-block:: python + :caption: servo_commander.py — lines 91-94 + + msg = AttrEnableTopic.Request() + msg.attr_path = self.get_parameter('dac_raw').value + msg.loop_rate = self.loop_rate + self.attr_enable_topic_client.call_async(msg) + +**Converting angle to DAC value** — When a position command arrives, the node +converts degrees to millivolts, then to raw DAC counts: + +.. code-block:: python + :caption: servo_commander.py — lines 113-122 + + def angle_to_voltage_mv(self, angle_deg: float) -> float: + """Convert angle (degrees) to voltage (mV).""" + normalized = (angle_deg - self.min_angle) / (self.max_angle - self.min_angle) + normalized = max(0.0, min(1.0, normalized)) + return normalized * self.max_voltage_mv + + def position_callback(self, msg: Float64): + # ... + voltage_mv = self.angle_to_voltage_mv(angle) + raw_value = min(4095, max(0, int(voltage_mv / self.scale))) + +servo_feedback — ADC Input Reading +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The ``servo_feedback`` node +(`servo_feedback.py +`__) +reads ADC values from the AD5592r to simulate position and current feedback. +It subscribes to IIO attribute topics for continuous streaming: + +.. code-block:: python + :caption: servo_feedback.py — lines 79-89 + + self.position_raw_sub = self.create_subscription( + String, + f"{self.get_parameter('position_adc_raw').value}/read", + self.position_raw_callback, + self.qos, + ) + self.current_raw_sub = self.create_subscription( + String, + f"{self.get_parameter('current_adc_raw').value}/read", + self.current_raw_callback, + self.qos, + ) + +The node converts raw ADC readings to physical units (degrees and milliamps) +and publishes them as ``JointState`` messages: + +.. code-block:: python + :caption: servo_feedback.py — lines 158-170 + + pos_voltage_mv = self.position_raw * self.position_scale + measured_angle = self.voltage_to_angle(pos_voltage_mv) + + cur_voltage_mv = self.current_raw * self.current_scale + measured_current = self.voltage_to_current(cur_voltage_mv) + + joint_msg = JointState() + joint_msg.header.stamp = self.get_clock().now().to_msg() + joint_msg.name = ['servo_joint'] + joint_msg.position = [measured_angle * 3.14159 / 180.0] + joint_msg.effort = [measured_current] + self.joint_pub.publish(joint_msg) + +IIO Service Interface +^^^^^^^^^^^^^^^^^^^^^ + +The key interaction with IIO happens through the ``adi_iio_node`` services: + +- ``AttrReadString`` — Read an attribute value (e.g., scale factors) +- ``AttrEnableTopic`` — Enable streaming for an attribute (creates a + ``/read`` topic for inputs or ``/write`` for outputs) +- ``AttrDisableTopic`` — Disable streaming for an attribute + +This pattern allows any ROS2 node to interact with IIO devices using standard +ROS2 communication patterns. The application nodes never call libiio directly — +they simply publish/subscribe to topics and call services, making it easy to +integrate precision analog hardware into robotic systems. + +Comparison: ROS2 vs. Python/MATLAB +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + ++----------------------+-------------------+-------------------+-------------------+ +| Aspect | Python (pyadi-iio)| MATLAB | ROS2 | ++======================+===================+===================+===================+ +| **Use case** | Scripting, testing| Analysis, plots | Robotics, control | ++----------------------+-------------------+-------------------+-------------------+ +| **Architecture** | Single process | Single process | Distributed nodes | ++----------------------+-------------------+-------------------+-------------------+ +| **Real-time** | No | No | Soft real-time | ++----------------------+-------------------+-------------------+-------------------+ +| **Deployment** | Direct | MATLAB runtime | Docker/native | ++----------------------+-------------------+-------------------+-------------------+ +| **Integration** | Python ecosystem | MATLAB toolboxes | ROS2 ecosystem | ++----------------------+-------------------+-------------------+-------------------+ + +ROS2 is the right choice when the IIO device is part of a larger robotic or +automation system that requires distributed processing, standardized +communication, or integration with other ROS2 packages (navigation, control, +perception, etc.). diff --git a/docs/learning/tools_for_ls/ros2_integration/ros2_architecture.png b/docs/learning/tools_for_ls/ros2_integration/ros2_architecture.png new file mode 100644 index 00000000000..ef843fef980 --- /dev/null +++ b/docs/learning/tools_for_ls/ros2_integration/ros2_architecture.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:61143c06dd4f4db5787ab98d2a68b5a44d9781ea9268d3f503b21dde34f3b30e +size 57132 diff --git a/docs/learning/tools_for_ls/ros2_integration/servo_feedback.png b/docs/learning/tools_for_ls/ros2_integration/servo_feedback.png new file mode 100644 index 00000000000..e5ea2a17a21 --- /dev/null +++ b/docs/learning/tools_for_ls/ros2_integration/servo_feedback.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:575a99e6a352011f9df6c0ad0c404825dbf5edddec2ca7222196f77be25ea4fe +size 358584 diff --git a/docs/learning/tools_for_ls/ros2_integration/topic_echo.png b/docs/learning/tools_for_ls/ros2_integration/topic_echo.png new file mode 100644 index 00000000000..b5e2630dc06 --- /dev/null +++ b/docs/learning/tools_for_ls/ros2_integration/topic_echo.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2cb45ff423aba0c288db4be4979a742f775cb932bf1015a490a6e9cd773e9d96 +size 71715 diff --git a/docs/learning/tools_for_ls/ros2_integration/topic_list.png b/docs/learning/tools_for_ls/ros2_integration/topic_list.png new file mode 100644 index 00000000000..b31da69151e --- /dev/null +++ b/docs/learning/tools_for_ls/ros2_integration/topic_list.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:711bba9972fe244f43e99dbe82aa3769dced464babb1ff1888aab26b24315a38 +size 46342 From c6aeb54154755b26362434f6534579ab0d6346e1 Mon Sep 17 00:00:00 2001 From: thorenscientific Date: Thu, 16 Jul 2026 14:27:03 -0700 Subject: [PATCH 3/5] Quite a bit of restructuring: Add child pages for matlab, native c, standalone no-OS, tinyiiod. --- .../learning/tools_for_ls/annotated_stack.png | 3 + docs/learning/tools_for_ls/index.rst | 472 +++++++++++------- .../tools_for_ls/matlab_example/index.rst | 24 + .../tools_for_ls/native_c_example/index.rst | 31 ++ .../standalone_no-os_example/index.rst | 99 ++++ .../tinyiiod_example/curvetraceroutput.png | 3 + .../tools_for_ls/tinyiiod_example/index.rst | 58 +++ 7 files changed, 502 insertions(+), 188 deletions(-) create mode 100644 docs/learning/tools_for_ls/annotated_stack.png create mode 100644 docs/learning/tools_for_ls/matlab_example/index.rst create mode 100644 docs/learning/tools_for_ls/native_c_example/index.rst create mode 100644 docs/learning/tools_for_ls/standalone_no-os_example/index.rst create mode 100644 docs/learning/tools_for_ls/tinyiiod_example/curvetraceroutput.png create mode 100644 docs/learning/tools_for_ls/tinyiiod_example/index.rst diff --git a/docs/learning/tools_for_ls/annotated_stack.png b/docs/learning/tools_for_ls/annotated_stack.png new file mode 100644 index 00000000000..de8c610d518 --- /dev/null +++ b/docs/learning/tools_for_ls/annotated_stack.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:cf402c0890b8ff2237e8b131382d7fcf4d6889fc74c8ae88c60eb44d7630d189 +size 96273 diff --git a/docs/learning/tools_for_ls/index.rst b/docs/learning/tools_for_ls/index.rst index 44218e74af6..51a84b0de79 100644 --- a/docs/learning/tools_for_ls/index.rst +++ b/docs/learning/tools_for_ls/index.rst @@ -42,18 +42,75 @@ diagram as shown in :numref:`fig-datax_diag_w_apps` Applications mappped onto ADI DataX layers -In this tutorial, we will use a transistor curve tracer and temperature sensor -as example applications. The temperature sensor simply involves reading -temperature, doing some math to convert units if necessary, and displaying the -result. The curve tracer involves setting voltages and currents, reading -voltages and currents, doing some basic math, and displaying a result. Each -reading will be treated independently, no correlation to previous or future -readings. We will NOT be measuring AC Signal to Noise Ratio (SNR), Total -Harmonic Distortion (THD), nor measuring steps, wiggles, or any other situation -where precise timing is required. Rest assured, there are lots of very -interesting applications in this category; consider a vector network analyzer -(VNA) - set an excitation frequency, measure forward and reflected power and -phase, do some math, step, repeat, and when done, display the results. +What does “Enabled by ADI DataX” mean? +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +An Analog Devices product, reference design, or application example is "Enabled +by ADI DataX" if you can follow one or more unbroken paths across +:numref:`fig-datax_diag`, where: + +- The compute platform is an easily available standard development board, or a + bespoke / custom board based on a standard platform +- The OS-specific device drivers are open-source, fully documented +- Language bindings and A simple "Hello, World!" example are written for the + Ecosystem, and are also open-source +- An application example either exists, or is trivial to derive from the "Hello, + World!" example. + +.. NOTE:: + + Not all paths make sense for all products. A good example is the + :adi:`ADM1266` sequencer -this device is used in large network + infrastructure and data center boards, which typically have a board + management controller running OpenBMC, a special-purpose embedded Linux. As + such, a Raspberry Pi can serve as a proxy for the SoCs typically used in BMC + applications, only a Linux driver is required, and the ecosystem and + application layers are Phosphor and Redfish. With a single path, this part is + "fully ADI DataX enabled". + +But wait, there's more! We also pre-build boot files for as many of these cases +as possible. This means you can bring up examples without having to install and +configure toolchains right away. This can be a huge timesaver when you just want +a quick proof of concept, and don't want the overhead of installing a piece of +software you may not be familiar with (FPGA tools, compilers for processors +you're not going to be using beyond initial development, etc.). + +The ADI :ref:`kuiper` Linux distribution is a big part of the "get up and +running quickly" philosophy. Kuiper is a specialized Debian-based Linux +distribution designed specifically for Analog Devices hardware and evaluation +boards. It provides a complete, ready-to-use environment with ADI libraries, +tools, and applications pre-configured for seamless hardware integration. + +Rather than manually installing and configuring individual ADI software +components, Kuiper delivers a cohesive development platform that eliminates +setup complexity and gets you running immediately. + +The no-OS framework is ADI's bare-metal device drivers, platform drivers, and +example projects, and it too shares the same philosophy. Projects are +automatically built as part of the continuous integration (CI) process, and boot +files for each project, often supporting several platforms, are available in the +releases section of the repository on GitHub. + +Developing a Product with ADI DataX +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +In this tutorial, we will help strategic and key customer Fred in the Shed +Instruments, Inc. develop their first products: + +- A temperature sensor with options for local display and network connectivity +- A handheld transistor curve tracer for the custom guitar pedal industry + +The temperature sensor simply involves reading temperature, doing some math to +convert units if necessary, and displaying the result. The curve tracer involves +setting voltages and currents, reading voltages and currents, doing some basic +math, and displaying a result. Each reading is considered independently, no +correlation to previous or future readings. We will NOT be measuring AC Signal +to Noise Ratio (SNR), Total Harmonic Distortion (THD), nor measuring steps, +wiggles, wavelets, or any other situation where precise timing is required. Rest +assured, there are lots of very interesting applications in this category; +consider a vector network analyzer (VNA) - set an excitation frequency, measure +forward and reflected power and phase, do some math, step, repeat, and when +done, display the results. We will start with a Linux-based workflow, leveraging Linux device drivers pre-built in ADI Kuiper Linux, Pyadi-iio. We'll then show how to migrate to @@ -68,6 +125,7 @@ Complete written instructions follow, as well as a video guide and a slide deck that can be used for delivering as a hands-on workshop. .. NOTE:: + What exactly does “Low Speed” mean? In the context of this tutorial, it means that timing is not very critical. Signals are either completely static or moving slowly such that it doesn't matter if the instant that an ADC samples @@ -97,8 +155,8 @@ that can be used for delivering as a hands-on workshop. Materials ~~~~~~~~~ -- Raspberry Pi 4 or 5; 2GB or greater RAM (for Linux examples). (Model 3B, 3B - Plus will work, but you will want a 4 or 5 :-) ) +- Raspberry Pi 4, 400, 5 or 500; 2GB or greater RAM (for Linux examples). (Model 3B, 3B + Plus will work, but you will want a 4, 400, 5, or 500 :-) ) - 5V USB-C wall adapter for Raspberry Pi (micro USB for model 3) - 16GB (or larger) Class 10 (or faster) micro-SD card, with :ref:`kuiper` installed - User interface setup (choose one): @@ -133,14 +191,7 @@ Materials :dokuwiki:`rpi-ad5592r-with_gpios-overlay source and compiled overlay <_media/university/labs/software/tools_for_low_speed_mix-sig_systems/rpi-ad5592r-with_gpios-overlay.zip>` -Background -~~~~~~~~~~ - -This tutorial builds on the concepts covered in the -:ref:`conv_connect_tutorial`. -It also serves as a preview to the :ref:`precision_adc_tutorial` that starts to -deal with analyzing time series data. Slide Deck and Video ~~~~~~~~~~~~~~~~~~~~ @@ -157,6 +208,7 @@ following the tutorial yourself, or to practice before presenting as a hands-on workshop. .. NOTE:: + This video is accurate, but uses the AD5592 Pmod and discretely built circuit. It will be re-done to target the ADALM-LSMSPG board. @@ -166,41 +218,107 @@ hands-on workshop. Preparation - a few resources for learning Python ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -A wonderful resource for learning Python is `learnpython.org -`__, runs right in your browser without needing to -install anything. +While this is not intended to be a Python-centric workshop, it sort of ends up +that way by default because Python is so easy to use and flexible, so we use it +as a tool througout. Even if you are not using Python in your end application, +it often still makes sense as an intermediate tool during development. If you're +not at least somewhat familiar with the language, A wonderful resource for +learning Python is `learnpython.org `__, runs right in +your browser without needing to install anything. We're not going to go super +deep into Python arcana and minutia by any means - the "Learn the Basics" +section will leave you more than prepared for what follows. And despite the name, `Python for Kids `__ is surprisingly good for adults, too! -What does “Just Enough Software” look like? -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Software Stack Background -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Introducing an exciting new product that we'll apply our skills -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Software Stack Background, and, To Deliver You from the Preliminary Terrors +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +A typical Linux-based software stack is shown in :numref:`fig-annotated_stack`. +It's pretty scary, even a relatively simple application exercises most of these +layers, and a full understanding of each and every layer is outside of the +skillset of most engineers - including most software engineers. **And that's +okay**. + +.. _fig-annotated_stack: + +.. figure:: annotated_stack.png + :width: 700px + :align: center + + Annotated Linux software stack + +For engineers that are bringing their brainstorms to life for the first time, +building proof of concept, and early prototypes, you don't need to understand +all of the layers. The goal is to operate at a point in the stack where you can +quickly add value - try out a couple of ADCs, DACs, IMUs, or other parts without +having to start from scratch each time. Build basic command line programs that +achieve proof of concept, deferring pretty, focus-group vetted GUIs for later. +The goal of ADI DataX is to expose this operating point as efficiently as +possible so you can get to work. + +Introducing the exciting new products to which we'll apply our skills +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The temperature sensor is intended as an "as simple as possible" application. +The temperature sensor IC itself is the ADT75, which has cross-references from +multiple manufacturers (all inferior to Analog Devices, of course!). The Linux +device driver has been in the kernel since at least version 2 (1998), and you +can buy a ten-pack of breakout boards for $15 USD. Component selection based on software support (vs. pure analog performance) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Talk about the importance of robust, long-term software support. Reference `Free +and Open-Source Software—An Analog Devices Perspective +`__ + +Links out to drivers on kernel.org + +**Hands-On!** Working through a simple, but complete case study +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Let's actually build up a working prototype of these devices. We are going to +start with an entirely Linux-based flow, with all software running on the Linux +machine itself. Does this make sense when our product will ultimately be +targeting a low-cost microcontroller running bare-metal C? You bet! Remember, +With ADI DataX, switching between ecosystem layers is cheap - Use Linux to get +up and running quickly, debug circuitry, verify analog performence. Then there +is little to no barrier to switching to bare metal or Zephyr as development +continues. + Hardware Setup ~~~~~~~~~~~~~~~~ +ADALM-LSMSPG overview, block diagram. Reference :ref:`ADALM-LSMSPG User Guide +` + Booting the system ~~~~~~~~~~~~~~~~~~~~~~~~ +Boot the system, run: + +.. code-block:: none + + iio_info + +You see the Raspberry Pi's cpu_thermal +sensor, undervoltage warning comparator, but nothing else. + Configuring the System (and rebooting!) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -The Raspberry Pi-based hardware and Linux setup mirrors that of the ADXL345 used -in the :ref:`conv_connect_tutorial`, including bringing up the -pyadi-iio example. Follow the instructions for downloading and installing ADI -Kuiper Linux, and editing config.txt. The only difference is the device tree -overlay to be added to config.txt. For this exercise, add the following lines to -config.txt: +<> + +Follow the instructions for downloading and installing ADI Kuiper +Linux, and editing config.txt. The only difference is the device tree overlay to +be added to config.txt. For this exercise, Prepare an SD card with ADI Kuiper +Linux following the instructions at :ref:`ADI Kuiper Linux Guide `. + +Add the following to the end of ``/boot/config.txt``: .. code-block:: none @@ -221,43 +339,121 @@ a shutdown when shorted to ground. Command Line Tools (Hello, AD5592r!) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Open a terminal and run the following command: + +.. code-block:: none + + iio_info + +again. If all goes well, you should see a few pages of information about the +AD5592r, AD5593r, LM75, and GPIOs. + IIO Oscilloscope ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +The ADI IIO Oscilloscope is a cross platform GUI application for basic +interaction with IIO contexts such as evaluation boards running on standard +platforms, standalone modules such as the ADALM-Pluto or AD-JUPITER-EBZ +software-defined radio. The application supports plotting of the captured data +in four different modes (time domain, frequency domain, constellation and +cross-correlation). The application also allows to view and modify IIO +Attributes and settings of the evaluation board’s devices. + +IIO Oscilloscope is a legacy application that is being slowly deprecated in +favor of Scopy, so we are only going to cover it briefly. + +<> + +Scopy +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Scopy is a multi-functional software toolset with full instrument support for +the ADALM2000 including oscilloscope, spectrum analyzer function generator, +network analyzer, and tools for digital debug. From Scopy version 2.0, it now +supports general-purpose interaction with IIO contexts, and largely supersedes +IIO Oscilloscope. + +Let's interact with the ADALM-LSMSPG board using Scopy... + +<> + + Device Trees: Telling Linux what's connected ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Examine device tree overlay, include annotated figure from presentation. + Pyadi-iio And examples ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -**Hands-On!** Working through a simple, but complete case study -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Open up Thonny, and: + +run lm75_example.py + +run ad5592r_curve_tracer.py + +run ad5592r_curve_tracer.py + + Next Steps: Developing on a remote host ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Next Steps: Other languages (C++, C#, MATLAB, etc.) -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +As wonderful as Thonny is, it's often advantageious (or essential) to develop on +a much more powerful machine. While the temperature sensor requires little to no +math, and the curve tracer requires a tolerable amount of math, high-bandwidth, +RF, and radar applications will push the Raspberry Pi's limits. And if the +application itself doesn't the development environment - VSCode, MATLAB, +PyCharm, etc. will. Luckily the IIO subsystem supports multiple physical +backends, including Serial, USB, and network. Kuiper Linux is configured to run +a program called "iiod" (IIO daemon) on startup. This process serves up local +IIO devices over a network connection that can be accessed from anywhere on the +network. Open up a terminal again and run: + +.. code-block:: none + + iio_info -u ip:localhost + +... same information as no argument! We've told iio_info to not look at locally +connected devices, rather, for devices on the network. It just so happens that +the network never left the machine, but it certainly could have. Here is a +screenshot of iio_info running on a Windows 11 machine: -Next Steps: ROS2 Integration +<> + +So now we can fire up our favorite bloated (oops - "full featured") Python, +MATLAB, C#, etc. development environment, and communicate with the target +hardware over a network connection. + +Language Support: C, C++ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -While the previous exercises used Python and pyadi-iio, the IIO framework can -also be integrated with **ROS2** (Robot Operating System 2) for robotics and -automation applications. The `adi_iio `__ -ROS2 package provides a bridge between IIO devices and the ROS2 ecosystem, -exposing device attributes as ROS2 topics and services. +Of course we're not limited to Python! The libiio is written natively in C, so +we can write a simple C program that runs natively in Linux, on the Raspberry +Pi. In this section, we'll go through this process. -In this section, we will run a servo motor control demo that uses the -ADALM-LSMSPG to generate position commands and read feedback, demonstrating -how IIO devices can be integrated into a ROS2-based control system. +:doc:`Continue to C, C++ Tutorial ` -:doc:`Continue to ROS2 Integration Tutorial ` +.. toctree:: + :hidden: + + native_c_example/index + +Language Support: MATLAB +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The LM75, AD5592r, and AD5593r are supported in ADI's MATLAB precision toolbox. +In this section, we'll work through porting the temperature sensor and curve +tracer to MATLAB. + +:doc:`Continue to MATLAB Tutorial ` .. toctree:: :hidden: - ros2_integration/index + matlab_example/index + IIO as a Tool for Migrating to an Embedded Implementation ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -282,59 +478,16 @@ exposed over the iio network backend using the "tinyiiod server". This allows you to run the same proof of concept Python (or C or MATLAB or C#) code that previously talked to the Raspberry Pi, to talk to your actual embedded target. -To see this in action, let's load up the pre-built ADALM-LSMSPG tinyiiod server. -Go to :git-no-os:`ADALM-LSMSPG firmware (no-OS releases) `, -download the adalm-lsmspg.zip file, and unzip to a convenient location. Shut -down your Raspberry Pi properly, then disconnect the 40-pin ribbon cable from the -ADALM-LSMSPG board. Install a MAX32666FTHR in the FTHR sockets, taking care to -align the pins properly. Connect the supplied MAX PICO board to the MAX32666FTHR -programming header. Connect both the MAX PICO and MAX32666FTHR to the host -computer via USB-A to Micro-B cables. Drag and drop the -adalm-lsmspg_maxim_iio.hex file into the DAPLINK DAPLINK mass storage device -(typically ``D:`` or ``E:`` on Windows systems). The DAPLINK drive will -auto-eject, and the heartbeat LED on the ADALM-LSMSPG will begin blinking. -(Almost done!) - -Unlike network and USB backends, the iio serial backend is not discoverable so -we will need to find out what serial port the MAX32666FTHR enumerates as. +To see this in action: -.. note:: - Back in "ye oldyn days" serial ports were dedicated D-SUB 9 or 25 pin - connectors on the host computer, assigned to a particular COM or TTY port. - Those days are mostly gone; "virtual" USB serial ports are incredibly - convenient as they allow the use of standard serial port software APIs, the - drawback is the port numbering can be somewhat arbitrary and inconsistent. - -There are various ways to find the serial port - Device Manager on Windows, and -looking for tty* ports in /dev on Linux, but we can also use IIO Oscilloscope or -Scopy from the previous experiments. - -Once the serial port is located, run the same curve tracer scripts as before, -but append the COM / tty port URI: - -.. code-block:: none - - ad5592r_curve_tracer.py -u serial:COMx - ad5593r_curve_tracer.py -u serial:COMx +:doc:`Continue to tinyiiod Tutorial ` -where "x" is the COM port number identified. The output should be identical to -previous runs using the local backend, as shown in :numref:`fig-ct_tinyiiod` - -.. _fig-ct_tinyiiod: +.. toctree:: + :hidden: -.. figure:: curvetraceroutput.png - :width: 700px - :height: 400px - :align: center + tinyiiod_example/index - Curve tracer plots, serial backend -At this point you can re-verify your top-level code, but on the actual target -hardware (vs. evaluation boards or crude prototypes). While the devices and -curve tracer application on the ADALM-LSMSPG are not terribly sensitive to -noise, more sensitive applications - precision instrumentation, communications, -sensing, etc. - will absolutely benefit from a quick check before beginning the -potentially long embedded firmware development process. Porting to a Fully Embedded System ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -348,96 +501,33 @@ designed to be easily portable to other platforms as well. Let's now migrate the curve tracer logic that until now ran in Python on a remote host into the embedded target, replacing the tinyiiod server entirely. -While the ultimate goal of the curve tracer is to have a local display, that's -another layer of both hardware and software development that we can defer a bit -longer with a little bit of creative thinking. Since there is a serial port -available, we can test out the logic by printing values to a terminal, formatted -as comma-separated variable (CSV) data for easy copy/paste into `LibreOffice -`__ or other spreadsheet for plotting. And for a -bit of `icing on the cake -`__ and -nostalgia, we can also make an ASCII-art plot! - -Go back to the zip file from the no-OS release, and drag-and-drop the curve -tracer example HEX file into the DAPLINK drive. Press the RESET button on the -ADALM-LSMSPG and observe the output. The CSV data and ASCII-art plots will be -printed to the terminal as shown in the figures below. - -.. code-block:: - :caption: ASCII-art NPN curve trace output - - === AD5592R (SPI) - NPN Curve Tracer (Ic vs Vc) === - Y-axis: Ic (0 to 7.16 mA) - X-axis: Vc (0 to 2.45 V) - - +------------------------------------------------------------+ - | ****** ***** ***** ***** ***** ***** ** * | - | * | - | * | - | * | - | | - | * ** ***** ***** ***** ***** ***** ***** ***** * | - | * * | - | * | - | ** | - | * | - | * *** ***** ***** ***** ***** ***** ***** ***** ** | - | *** | - | * | - | ** | - | ** | - | * ***** ***** ***** ***** ***** ***** ***** ***** *** | - | * * | - | *** | - |****** **** ***** ***** ***** ***** ***** ***** ***** **** *| - | | - +------------------------------------------------------------+ - 0.0 0.49 0.98 1.47 1.96 2.45 V - - ===== AD5592R Curve Trace Complete ===== - - -Similarly, you will see an ASCII-art PNP curve trace similar to the figure below. - -.. code-block:: - :caption: ASCII-art PNP curve trace output - - === AD5593R (I2C) - PNP Curve Tracer (Ic vs Vc) === - Y-axis: |Ic| (0 to 5.62 mA) - X-axis: Vc (0 to 2.50 V) - - +------------------------------------------------------------+ - | ***** ****** ***** ****** ***** ****** ***** ****** *******| - | * | - | ** | - | ** | - | ** ****** ***** ****** ****** ***** ****** ***** **** * | - | * | - | * | - | * | - | * * | - | | - | ***** ******* * | - | ***** ****** ****** ***** ****** * * | - | | - | * | - | * | - | | - | *** | - | * ** ****** **** | - | ** ****** ****** ****** ** * | - | * | - +------------------------------------------------------------+ - 0.0 0.50 1.00 1.50 2.00 2.50 V - - ===== AD5593R Curve Trace Complete ===== - -At this point all of the math, algorithms, and overall operation of the curve -tracer are running in the embedded target, and we're able to verify everything -is operating properly and with full (analog) performance. The next step can be -to connect a local display, or enable a server for display on a remote screen -such as a tablet or mobile device. +:doc:`Continue to tinyiiod Tutorial ` + +.. toctree:: + :hidden: + + standalone_no-os_example/index + +Ecosystem Support: ROS2 Integration +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +While the previous exercises used Python and pyadi-iio, the IIO framework can +also be integrated with **ROS2** (Robot Operating System 2) for robotics and +automation applications. The `adi_iio `__ +ROS2 package provides a bridge between IIO devices and the ROS2 ecosystem, +exposing device attributes as ROS2 topics and services. + +In this section, we will run a servo motor control demo that uses the +ADALM-LSMSPG to generate position commands and read feedback, demonstrating +how IIO devices can be integrated into a ROS2-based control system. + +:doc:`Continue to ROS2 Integration Tutorial ` + +.. toctree:: + :hidden: + + ros2_integration/index Next Steps: No-OS development on Linux? You bet! ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -475,3 +565,9 @@ Wrapup Additional References ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This tutorial builds on the concepts covered in the +:ref:`conv_connect_tutorial`. + +It also serves as a preview to the :ref:`precision_adc_tutorial` that starts to +deal with analyzing time series data. \ No newline at end of file diff --git a/docs/learning/tools_for_ls/matlab_example/index.rst b/docs/learning/tools_for_ls/matlab_example/index.rst new file mode 100644 index 00000000000..76dfa4560ec --- /dev/null +++ b/docs/learning/tools_for_ls/matlab_example/index.rst @@ -0,0 +1,24 @@ +.. _datax-matlab-example: + +Language Support: MATLAB +------------------------ + +.. note:: + + This is a work in progress. + +While the previous exercises used Python and pyadi-iio to communicate with +the AD5592r, the IIO framework is language-agnostic. Any language that can +call into the libiio C library (or use its command-line tools) can control the +hardware. In this section, we will recreate the NPN curve tracer example +in **MATLAB**, and instead of running on the Raspberry Pi, we will use the +**MAX32666FTHR** Feather board as a tinyiiod IIO server, connected to the +ADALM-LSMSPG over SPI and I2C, and controlled from a PC over USB serial. + +.. note:: + + This exercise demonstrates two key concepts: using MATLAB as an alternative + to Python for IIO device control, and using a bare-metal microcontroller + (MAX32666FTHR) as a portable alternative to the Raspberry Pi Linux host. + +<> \ No newline at end of file diff --git a/docs/learning/tools_for_ls/native_c_example/index.rst b/docs/learning/tools_for_ls/native_c_example/index.rst new file mode 100644 index 00000000000..b601c1d0fc5 --- /dev/null +++ b/docs/learning/tools_for_ls/native_c_example/index.rst @@ -0,0 +1,31 @@ +.. _datax-native-c-example: + +Language Support: C, C++ +------------------------ + +.. note:: + + This is a work in progress. + +Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor +incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis +nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. +Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu +fugiat nulla pariatur. + +Prerequisites +~~~~~~~~~~~~~ + +Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor +incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis +nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. + +Overview +~~~~~~~~ + +Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor +incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis +nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. +Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu +fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in +culpa qui officia deserunt mollit anim id est laborum. diff --git a/docs/learning/tools_for_ls/standalone_no-os_example/index.rst b/docs/learning/tools_for_ls/standalone_no-os_example/index.rst new file mode 100644 index 00000000000..938a8f8e5c6 --- /dev/null +++ b/docs/learning/tools_for_ls/standalone_no-os_example/index.rst @@ -0,0 +1,99 @@ +.. _datax-no-os-standalone: + +Porting to a Fully Embedded System +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. note:: + + This is a work in progress. + + +While the ultimate goal of the curve tracer is to have a local display, that's +another layer of both hardware and software development that we can defer a bit +longer with a little bit of creative thinking. Since there is a serial port +available, we can test out the logic by printing values to a terminal, formatted +as comma-separated variable (CSV) data for easy copy/paste into `LibreOffice +`__ or other spreadsheet for plotting. And for a +bit of `icing on the cake +`__ and +nostalgia, we can also make an ASCII-art plot! + +Go back to the zip file from the no-OS release, and drag-and-drop the curve +tracer example HEX file into the DAPLINK drive. Press the RESET button on the +ADALM-LSMSPG and observe the output. The CSV data and ASCII-art plots will be +printed to the terminal as shown in the figures below. + +.. code-block:: + :caption: ASCII-art NPN curve trace output + + === AD5592R (SPI) - NPN Curve Tracer (Ic vs Vc) === + Y-axis: Ic (0 to 7.16 mA) + X-axis: Vc (0 to 2.45 V) + + +------------------------------------------------------------+ + | ****** ***** ***** ***** ***** ***** ** * | + | * | + | * | + | * | + | | + | * ** ***** ***** ***** ***** ***** ***** ***** * | + | * * | + | * | + | ** | + | * | + | * *** ***** ***** ***** ***** ***** ***** ***** ** | + | *** | + | * | + | ** | + | ** | + | * ***** ***** ***** ***** ***** ***** ***** ***** *** | + | * * | + | *** | + |****** **** ***** ***** ***** ***** ***** ***** ***** **** *| + | | + +------------------------------------------------------------+ + 0.0 0.49 0.98 1.47 1.96 2.45 V + + ===== AD5592R Curve Trace Complete ===== + + +Similarly, you will see an ASCII-art PNP curve trace similar to the figure below. + +.. code-block:: + :caption: ASCII-art PNP curve trace output + + === AD5593R (I2C) - PNP Curve Tracer (Ic vs Vc) === + Y-axis: |Ic| (0 to 5.62 mA) + X-axis: Vc (0 to 2.50 V) + + +------------------------------------------------------------+ + | ***** ****** ***** ****** ***** ****** ***** ****** *******| + | * | + | ** | + | ** | + | ** ****** ***** ****** ****** ***** ****** ***** **** * | + | * | + | * | + | * | + | * * | + | | + | ***** ******* * | + | ***** ****** ****** ***** ****** * * | + | | + | * | + | * | + | | + | *** | + | * ** ****** **** | + | ** ****** ****** ****** ** * | + | * | + +------------------------------------------------------------+ + 0.0 0.50 1.00 1.50 2.00 2.50 V + + ===== AD5593R Curve Trace Complete ===== + +At this point all of the math, algorithms, and overall operation of the curve +tracer are running in the embedded target, and we're able to verify everything +is operating properly and with full (analog) performance. The next step can be +to connect a local display, or enable a server for display on a remote screen +such as a tablet or mobile device. diff --git a/docs/learning/tools_for_ls/tinyiiod_example/curvetraceroutput.png b/docs/learning/tools_for_ls/tinyiiod_example/curvetraceroutput.png new file mode 100644 index 00000000000..8c022108525 --- /dev/null +++ b/docs/learning/tools_for_ls/tinyiiod_example/curvetraceroutput.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:084bd5dcc141e30bed0aa0f7b1f56d11221b3655b0c583f7273403e9e3d67080 +size 100168 diff --git a/docs/learning/tools_for_ls/tinyiiod_example/index.rst b/docs/learning/tools_for_ls/tinyiiod_example/index.rst new file mode 100644 index 00000000000..4f317681c42 --- /dev/null +++ b/docs/learning/tools_for_ls/tinyiiod_example/index.rst @@ -0,0 +1,58 @@ +.. _datax-iio-for-migrating: + +IIO as a Tool for Migrating to an Embedded Implementation +--------------------------------------------------------- + +Let's load up the pre-built ADALM-LSMSPG tinyiiod server. +Go to :git-no-os:`ADALM-LSMSPG firmware (no-OS releases) `, +download the adalm-lsmspg.zip file, and unzip to a convenient location. Shut +down your Raspberry Pi properly, then disconnect the 40-pin ribbon cable from the +ADALM-LSMSPG board. Install a MAX32666FTHR in the FTHR sockets, taking care to +align the pins properly. Connect the supplied MAX PICO board to the MAX32666FTHR +programming header. Connect both the MAX PICO and MAX32666FTHR to the host +computer via USB-A to Micro-B cables. Drag and drop the +adalm-lsmspg_maxim_iio.hex file into the DAPLINK DAPLINK mass storage device +(typically ``D:`` or ``E:`` on Windows systems). The DAPLINK drive will +auto-eject, and the heartbeat LED on the ADALM-LSMSPG will begin blinking. +(Almost done!) + +Unlike network and USB backends, the iio serial backend is not discoverable so +we will need to find out what serial port the MAX32666FTHR enumerates as. + +.. note:: + Back in "ye oldyn days" serial ports were dedicated D-SUB 9 or 25 pin + connectors on the host computer, assigned to a particular COM or TTY port. + Those days are mostly gone; "virtual" USB serial ports are incredibly + convenient as they allow the use of standard serial port software APIs, the + drawback is the port numbering can be somewhat arbitrary and inconsistent. + +There are various ways to find the serial port - Device Manager on Windows, and +looking for tty* ports in /dev on Linux, but we can also use IIO Oscilloscope or +Scopy from the previous experiments. + +Once the serial port is located, run the same curve tracer scripts as before, +but append the COM / tty port URI: + +.. code-block:: none + + ad5592r_curve_tracer.py -u serial:COMx + ad5593r_curve_tracer.py -u serial:COMx + +where "x" is the COM port number identified. The output should be identical to +previous runs using the local backend, as shown in :numref:`fig-ct_tinyiiod` + +.. _fig-ct_tinyiiod: + +.. figure:: curvetraceroutput.png + :width: 700px + :height: 400px + :align: center + + Curve tracer plots, serial backend + +At this point you can re-verify your top-level code, but on the actual target +hardware (vs. evaluation boards or crude prototypes). While the devices and +curve tracer application on the ADALM-LSMSPG are not terribly sensitive to +noise, more sensitive applications - precision instrumentation, communications, +sensing, etc. - will absolutely benefit from a quick check before beginning the +potentially long embedded firmware development process. \ No newline at end of file From 0ac828acbfd04c0bdd64d7735213b23de7caea07 Mon Sep 17 00:00:00 2001 From: thorenscientific Date: Tue, 21 Jul 2026 20:03:10 -0700 Subject: [PATCH 4/5] Add child page for Zephyr. Some editing of the main page. --- docs/learning/tools_for_ls/index.rst | 119 ++++++++++++------ .../tools_for_ls/zephyr_example/index.rst | 14 +++ 2 files changed, 94 insertions(+), 39 deletions(-) create mode 100644 docs/learning/tools_for_ls/zephyr_example/index.rst diff --git a/docs/learning/tools_for_ls/index.rst b/docs/learning/tools_for_ls/index.rst index 51a84b0de79..0f65d36d056 100644 --- a/docs/learning/tools_for_ls/index.rst +++ b/docs/learning/tools_for_ls/index.rst @@ -103,23 +103,16 @@ Instruments, Inc. develop their first products: The temperature sensor simply involves reading temperature, doing some math to convert units if necessary, and displaying the result. The curve tracer involves setting voltages and currents, reading voltages and currents, doing some basic -math, and displaying a result. Each reading is considered independently, no -correlation to previous or future readings. We will NOT be measuring AC Signal -to Noise Ratio (SNR), Total Harmonic Distortion (THD), nor measuring steps, -wiggles, wavelets, or any other situation where precise timing is required. Rest -assured, there are lots of very interesting applications in this category; -consider a vector network analyzer (VNA) - set an excitation frequency, measure -forward and reflected power and phase, do some math, step, repeat, and when -done, display the results. - -We will start with a Linux-based workflow, leveraging Linux device drivers +math, and displaying a result. + +We will start with a Linux-based workflow because it's extremely convenient +(trust us!) using the ubiquitious Raspberry Pi, leveraging Linux device drivers pre-built in ADI Kuiper Linux, Pyadi-iio. We'll then show how to migrate to -other languages (C, C#, MATLAB), other processing platforms (ARM-based -MAX32xxx, Raspberry Pi Pico), ecosystems (no-OS / bare metal, Zephyr), and -middleware layers (GNURadio, ROS). With ADI DataX, switching between these -layers is cheap - there is little to no barrier to getting a proof of concept up -and running in Linux, then switching to bare metal or Zephyr as development -continues. +other languages (C, C#, MATLAB), other processing platforms (ARM-based MAX32xxx, +Raspberry Pi Pico), ecosystems (no-OS / bare metal, Zephyr), and middleware +layers (GNURadio, ROS). With ADI DataX, switching between these layers is cheap +- there is little to no barrier to getting a proof of concept up and running in +Linux, then switching to bare metal or Zephyr as development continues. Complete written instructions follow, as well as a video guide and a slide deck that can be used for delivering as a hands-on workshop. @@ -127,20 +120,16 @@ that can be used for delivering as a hands-on workshop. .. NOTE:: What exactly does “Low Speed” mean? In the context of this tutorial, it means - that timing is not very critical. Signals are either completely static - or moving slowly such that it doesn't matter if the instant that an ADC samples - the signal wiggles around a bit relative to the previous sampling. While clock - jitter is one source of this uncertainty, software delays (such as the time - between a timer interrupt and the assertion of a “convert” edge) will likely be - dominant. Important parameters in low-speed applications are offset, gain error, - linearity, and temperature drift. “Noise” in a low-speed application is - typically synonymous with resolution, and can be roughly measured by applying a - quiet input signal (like a short circuit) and taking a histogram of the output - readings. AC performance metrics such as signal to noise ratio and total - harmonic distortion extracted from a Fourier transform of the data will not be - considered. In contrast - sample jitter is important in a “high speed” - application. If you are measuring signal to noise ratio, the Signal to Noise - ratio (SNR) can be no greater than: + that timing is not very critical. Signals are either completely static or + moving slowly such that it doesn't matter if the instant that an ADC samples + the signal wiggles around a bit relative to the previous sampling. While + clock jitter is one source of this uncertainty, software delays (such as the + time between a timer interrupt and the assertion of a “convert” edge) will + likely be dominant. AC performance metrics such as signal to noise ratio + (SNR) and total harmonic distortion (THD) extracted from a Fourier transform + of the data will not be considered. In contrast - sample jitter is important + in a “high speed” application. If you are measuring signal to noise ratio, + the SNR can be no greater than: :math:`SNR <= -20 * log(2*\pi*f_{IN}*t_{j})` @@ -149,6 +138,16 @@ that can be used for delivering as a hands-on workshop. :math:`f_{IN}` is the analog input frequency in Hz :math:`t_{j}` is the RMS jitter in seconds RMS + + Important parameters in low-speed applications are typically offset, gain + error, linearity, and temperature drift. Each reading is considered + independently, no correlation to previous or future readings. We will NOT be + measuring AC SNR, THD, nor measuring steps, wiggles, wavelets, or any other + situation where precise timing is required. Rest assured, there are lots of + very interesting applications in this category; consider a vector network + analyzer (VNA) - set an excitation frequency, measure forward and reflected + power and phase, do some math, step, repeat, and when done, display the + results. @@ -165,7 +164,8 @@ Materials - :adi:`ADALM2000 ` (Optional, for observing signals.) -- :adi:`MAX32666FTHR` development board (for no-OS examples) +- :adi:`MAX32655FTHR` development board (for no-OS and Zephyr + examples) - Either: - :adi:`ADALM-LSMSPG` Low-Speed Mixed Signal Playground module - Or: @@ -263,11 +263,24 @@ possible so you can get to work. Introducing the exciting new products to which we'll apply our skills ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -The temperature sensor is intended as an "as simple as possible" application. -The temperature sensor IC itself is the ADT75, which has cross-references from -multiple manufacturers (all inferior to Analog Devices, of course!). The Linux -device driver has been in the kernel since at least version 2 (1998), and you -can buy a ten-pack of breakout boards for $15 USD. +As mentioned above, we're going to be building a prototype temperature sensor +and transistor curve tracer. The temperature sensor is intended as an "as simple +as possible" application. The temperature sensor IC itself is the ADT75, which +has cross-references from multiple manufacturers (all inferior to Analog +Devices, of course!). The Linux device driver has been in the kernel since at +least version 2 (1998), and you can buy a ten-pack of breakout boards for $15 +USD. + +The curve tracer is "more advanced" - it involves setting the current into +an NPN transistor's base (or out of a PNP's base), sweeping the collector +voltage, and measuring the resulting collector current. This example is intended +as the simplest possible application that exercises the following operations: + +- Set a couple of voltages and currents +- Measure a couple of voltages and currents +- Do some math +- Step and repeat +- Display results Component selection based on software support (vs. pure analog performance) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -426,6 +439,8 @@ So now we can fire up our favorite bloated (oops - "full featured") Python, MATLAB, C#, etc. development environment, and communicate with the target hardware over a network connection. +<> + Language Support: C, C++ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -509,10 +524,36 @@ remote host into the embedded target, replacing the tinyiiod server entirely. standalone_no-os_example/index -Ecosystem Support: ROS2 Integration -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +RTOS Support: Zephyr +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Zephyr is an open-source, scalable real-time operating system (RTOS) for +resource-constrained embedded devices, providing a small-footprint kernel along +with integrated drivers, networking, security, and application services across a +wide range of hardware architectures. Zephyr supports more than 1000 development +boards, and hundreds of shields - including... the ADALM-LSMSPG!: + +`Zephyr Shields: Analog Devices Low-Speed Mixed Signal Playground `__ + +And the MAX32655FTHR: + +`Zephyr Boards: Analog Devices MAX32655FTHR `__ + +In the Zephyr section of this workshop, we will run the tinyiiod server, a +few standalone examples, and the debug console. + +:doc:`Continue to the Zephyr examples ` + +.. toctree:: + :hidden: + + zephyr_example/index + + +Ecosystem / Framework Support: ROS2 Integration +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -While the previous exercises used Python and pyadi-iio, the IIO framework can +While the previous exercises used Python and pyadi-iio, the IIO subsystem can also be integrated with **ROS2** (Robot Operating System 2) for robotics and automation applications. The `adi_iio `__ ROS2 package provides a bridge between IIO devices and the ROS2 ecosystem, diff --git a/docs/learning/tools_for_ls/zephyr_example/index.rst b/docs/learning/tools_for_ls/zephyr_example/index.rst new file mode 100644 index 00000000000..bf8c8ee25da --- /dev/null +++ b/docs/learning/tools_for_ls/zephyr_example/index.rst @@ -0,0 +1,14 @@ +.. _datax-zephyr-example: + +RTOS Support: Zephyr +------------------------ + +.. note:: + + This is a work in progress. + + + +<> From b1212d8528d1ebc74eaa43f93c06032d71a09357 Mon Sep 17 00:00:00 2001 From: GanscaTudor Date: Sun, 26 Jul 2026 23:11:11 +0300 Subject: [PATCH 5/5] learning/tools_for_ls: Fill in Matlab and Zephyr sections (#551) Signed-off-by: Tudor Gansca --- docs/learning/tools_for_ls/index.rst | 12 +- .../ad5592r_npn_curve_tracer.png | 3 + .../tools_for_ls/matlab_example/index.rst | 417 ++++++++++++++++- .../tools_for_ls/zephyr_example/index.rst | 430 +++++++++++++++++- 4 files changed, 852 insertions(+), 10 deletions(-) create mode 100644 docs/learning/tools_for_ls/matlab_example/ad5592r_npn_curve_tracer.png diff --git a/docs/learning/tools_for_ls/index.rst b/docs/learning/tools_for_ls/index.rst index 0f65d36d056..b5faa831c19 100644 --- a/docs/learning/tools_for_ls/index.rst +++ b/docs/learning/tools_for_ls/index.rst @@ -448,7 +448,7 @@ Of course we're not limited to Python! The libiio is written natively in C, so we can write a simple C program that runs natively in Linux, on the Raspberry Pi. In this section, we'll go through this process. -:doc:`Continue to C, C++ Tutorial ` +:ref:`Continue to C, C++ Tutorial ` .. toctree:: :hidden: @@ -462,7 +462,7 @@ The LM75, AD5592r, and AD5593r are supported in ADI's MATLAB precision toolbox. In this section, we'll work through porting the temperature sensor and curve tracer to MATLAB. -:doc:`Continue to MATLAB Tutorial ` +:ref:`Continue to MATLAB Tutorial ` .. toctree:: :hidden: @@ -495,7 +495,7 @@ previously talked to the Raspberry Pi, to talk to your actual embedded target. To see this in action: -:doc:`Continue to tinyiiod Tutorial ` +:ref:`Continue to tinyiiod Tutorial ` .. toctree:: :hidden: @@ -517,7 +517,7 @@ designed to be easily portable to other platforms as well. Let's now migrate the curve tracer logic that until now ran in Python on a remote host into the embedded target, replacing the tinyiiod server entirely. -:doc:`Continue to tinyiiod Tutorial ` +:ref:`Continue to tinyiiod Tutorial ` .. toctree:: :hidden: @@ -542,7 +542,7 @@ And the MAX32655FTHR: In the Zephyr section of this workshop, we will run the tinyiiod server, a few standalone examples, and the debug console. -:doc:`Continue to the Zephyr examples ` +:ref:`Continue to the Zephyr examples ` .. toctree:: :hidden: @@ -563,7 +563,7 @@ In this section, we will run a servo motor control demo that uses the ADALM-LSMSPG to generate position commands and read feedback, demonstrating how IIO devices can be integrated into a ROS2-based control system. -:doc:`Continue to ROS2 Integration Tutorial ` +:ref:`Continue to ROS2 Integration Tutorial ` .. toctree:: :hidden: diff --git a/docs/learning/tools_for_ls/matlab_example/ad5592r_npn_curve_tracer.png b/docs/learning/tools_for_ls/matlab_example/ad5592r_npn_curve_tracer.png new file mode 100644 index 00000000000..5dd3e0cbf32 --- /dev/null +++ b/docs/learning/tools_for_ls/matlab_example/ad5592r_npn_curve_tracer.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:81d53e54b1db0e9674be194840dc8f06883a0daa99c2401a04548c0a8d978968 +size 61304 diff --git a/docs/learning/tools_for_ls/matlab_example/index.rst b/docs/learning/tools_for_ls/matlab_example/index.rst index 76dfa4560ec..d829e693e5f 100644 --- a/docs/learning/tools_for_ls/matlab_example/index.rst +++ b/docs/learning/tools_for_ls/matlab_example/index.rst @@ -21,4 +21,419 @@ ADALM-LSMSPG over SPI and I2C, and controlled from a PC over USB serial. to Python for IIO device control, and using a bare-metal microcontroller (MAX32666FTHR) as a portable alternative to the Raspberry Pi Linux host. -<> \ No newline at end of file +Hardware Prerequisites +^^^^^^^^^^^^^^^^^^^^^^ + +In addition to the ADALM-LSMSPG board, you will need: + +- **MAX32666FTHR** Feather development board +- Micro USB cable for the MAX32666FTHR + +Software Prerequisites +^^^^^^^^^^^^^^^^^^^^^^ + +- **MATLAB** installed on your PC (base MATLAB is sufficient, no additional + toolboxes required) +- **ADI Precision Toolbox** for MATLAB — clone or download from + `GitHub `__ and add + to the MATLAB path +- **libiio** installed on your PC (provides the ``iio_info`` and ``iio_attr`` + command-line tools, and the shared library used by PrecisionToolbox) + + - Windows: download the installer from the + `libiio GitHub releases `__ + - Linux: ``sudo apt install libiio-utils`` + +Architecture Overview +^^^^^^^^^^^^^^^^^^^^^ + +The architecture differs from the Raspberry Pi setup. Instead of running +Python directly on the Linux host that is physically connected to the +AD5592r, we now have a two-part system: + +:: + + ┌────────────────┐ USB Serial ┌─────────────────────┐ + │ PC (MATLAB) │ ◄────────────► │ MAX32666FTHR │ + │ │ iio_attr/ │ (tinyiiod server) │ + │ curve_tracer.m │ libiio │ │ + │ script │ │ AD5592r ◄── SPI │ + └────────────────┘ │ AD5593r ◄── I2C │ + │ LM75 ◄── I2C │ + └─────────────────────┘ + +The MAX32666FTHR runs a **tinyiiod** firmware — a bare-metal IIO daemon that +exposes the AD5592r, AD5593r, and LM75 as standard IIO devices over USB +serial. The MATLAB script on the PC sends IIO commands through the serial +link, exactly as if it were talking to a Linux IIO device over the network. + +Step 1: Flash the MAX32666FTHR +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Make sure the MAX32625PICO DAPLink and the MAX32666FTHR are flashed with the +correct firmware for the ADALM-LSMSPG tinyiiod example — see the +`ADALM-LSMSPG documentation `__ +for step-by-step instructions. + +Step 2: Connect the Hardware +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +1. Mount the MAX32666FTHR onto the ADALM-LSMSPG board using the Feather + headers **P1** (16-pin) and **P28** (12-pin), with the Feather's + components facing downward. + +2. Connect the USB cable to the MAX32666FTHR. + +3. The **heartbeat LED** (DS1) on the ADALM-LSMSPG should begin blinking + with a double-pulse pattern, indicating the tinyiiod server is running + and waiting for connections. + +Step 3: Verify the Connection +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +First, identify the COM port assigned to the MAX32666FTHR. On Windows, open +**Device Manager** and look under **Ports (COM & LPT)** for the USB serial +device. + +Then verify the IIO context from a terminal: + +.. code-block:: bash + + iio_info -u serial:COM11,115200,8n1n + +Replace ``COM11`` with your actual COM port. You should see output listing +four IIO devices: + +- ``lm75`` — temperature sensor +- ``ad5592r`` — 8-channel ADC/DAC over SPI (used for NPN curve tracer) +- ``ad5593r`` — 8-channel ADC/DAC over I2C (used for PNP curve tracer) +- ``one-bit-adc-dac`` — GPIO channels mapped as 1-bit ADC/DAC + +Confirm that the ``ad5592r`` device shows channels ``voltage0`` (output), +``voltage1`` (input), ``voltage2`` (input and output), and that the scale +attribute reads approximately ``0.61035156`` mV/LSB. + +Step 4a: Curve Tracer with ADI Precision Toolbox (Recommended) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The recommended approach uses the +`ADI Precision Toolbox `__, +which calls libiio directly from MATLAB in-process. This is significantly +faster than spawning subprocesses and mirrors how pyadi-iio works in Python. + +The Precision Toolbox provides the ``adi.AD5592r.Rx`` class, which inherits +attribute read/write methods from the ``matlabshared.libiio.base`` class. +The key methods used are: + +- ``getAttributeDouble(channel, attribute, isOutput)`` — read a channel + attribute as a double (e.g., the ``scale`` factor) +- ``getAttributeRAW(channel, attribute, isOutput)`` — read a channel + attribute as a string (e.g., ADC ``raw`` readings) +- ``setAttributeRAW(channel, attribute, value, isOutput)`` — write a channel + attribute (e.g., set a DAC ``raw`` output value) + +The ``isOutput`` flag selects between input (ADC) and output (DAC) channels, +which is important because channels like ``voltage2`` exist as both. + +.. collapsible:: ad5592r_curve_tracer.m — Precision Toolbox version (click to expand) + + .. code-block:: matlab + + %% AD5592r NPN Curve Tracer using PrecisionToolbox + %% Sweeps base and collector voltages on the ADALM-LSMSPG board + %% and plots Ic vs Vc family of curves. + clc + clear + + % Instantiate the system object and connect + rx = adi.AD5592r.Rx(); + rx.uri = 'serial:COM11,115200,8n1n'; + rx.EnabledChannels = 2; + rx.SamplesPerFrame = 1; + rx(); + + % Circuit constants (NPN curve tracer on ADALM-LSMSPG) + Rsense = 47.0; % 47 Ohms - collector sense resistor + Rbase = 47.0e3; % 47 kOhms - base resistor + Vbe = 0.7; % Approximate base-emitter voltage + + % Read scale (mV per LSB) - identical for all AD5592r channels + mV_per_lsb = rx.getAttributeDouble('voltage0', 'scale', true); + fprintf('Scale: %.6f mV/LSB\n', mV_per_lsb); + + % Initialize DAC outputs to a safe starting point + rx.setAttributeRAW('voltage0', 'raw', num2str(round(500 / mV_per_lsb)), true); + rx.setAttributeRAW('voltage2', 'raw', num2str(round(500 / mV_per_lsb)), true); + + % Sweep parameters + base_mv = 499:500:2499; + coll_mv = 0:50:2450; + n_base = length(base_mv); + n_coll = length(coll_mv); + + % Preallocate results + curves_vc = zeros(n_base, n_coll); + curves_ic = zeros(n_base, n_coll); + labels = cell(1, n_base); + + for bi = 1:n_base + vb_raw = round(base_mv(bi) / mV_per_lsb); + rx.setAttributeRAW('voltage0', 'raw', num2str(vb_raw), true); + + ib = ((vb_raw * mV_per_lsb / 1000) - Vbe) / Rbase; + fprintf('Base Drive: %.3f V, %.1f uA\n', vb_raw * mV_per_lsb / 1000, ib * 1e6); + labels{bi} = sprintf('I_b = %.1f \\muA', ib * 1e6); + + for ci = 1:n_coll + vc_raw = round(coll_mv(ci) / mV_per_lsb); + rx.setAttributeRAW('voltage2', 'raw', num2str(vc_raw), true); + + vc_drive_raw = str2double(rx.getAttributeRAW('voltage2', 'raw', false)); + vc_sense_raw = str2double(rx.getAttributeRAW('voltage1', 'raw', false)); + + ic = (vc_drive_raw - vc_sense_raw) * mV_per_lsb / Rsense; + vc = vc_sense_raw * mV_per_lsb / 1000.0; + + curves_vc(bi, ci) = vc; + curves_ic(bi, ci) = ic; + end + end + + % Plot + figure('Name', 'AD5592r NPN Curve Tracer'); + hold on; + for bi = 1:n_base + plot(curves_vc(bi, :), curves_ic(bi, :), 'LineWidth', 1.5); + end + hold off; + title('ADALM-LSMSPG NPN Curve Tracer (MATLAB)'); + xlabel('Collector Voltage (V)'); + ylabel('Collector Current (mA)'); + legend(labels, 'Location', 'northwest'); + grid on; + + % Cleanup + release(rx); + +The script structure mirrors the Python version: + +1. **Connect** to the AD5592r by creating an ``adi.AD5592r.Rx`` object with + the serial URI and calling ``rx()`` to initialize the IIO context. + ``EnabledChannels = 2`` selects ``voltage1`` (an ADC input channel) for + context initialization. ``SamplesPerFrame = 1`` since we only need + single-value attribute access, not buffered streaming. +2. **Read the scale** attribute using ``getAttributeDouble`` to get the + mV-per-LSB conversion factor (approximately 0.610 mV/LSB for the AD5592r + with internal reference). +3. **Outer loop** — sweep the base drive voltage (``voltage0``, DAC output) + through 5 steps from 499 mV to 2499 mV using ``setAttributeRAW``, setting + a different base current for each curve. +4. **Inner loop** — for each base current, sweep the collector drive voltage + (``voltage2``, DAC output) from 0 to 2450 mV in 50 mV steps. At each + step, read back the collector drive (``voltage2``, ADC input) and collector + sense (``voltage1``, ADC input) using ``getAttributeRAW`` to compute the + collector current through the 47 Ohm sense resistor. +5. **Plot** the family of I-V curves and release the device. + +Step 4b: Curve Tracer with Command-Line Tools (Alternative) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +As an alternative to the Precision Toolbox, you can use the ``iio_attr`` +command-line tool (provided by libiio) directly from MATLAB via the +``system()`` function. This approach is useful for quick debugging and +learning how IIO attributes work at the lowest level, but is significantly +slower because each read or write spawns a new subprocess. + +.. collapsible:: ad5592r_curve_tracer_cli.m — iio_attr version (click to expand) + + .. code-block:: matlab + + function ad5592r_curve_tracer_cli(uri) + if nargin < 1 + uri = 'serial:COM11,115200,8n1n'; + end + + device = 'ad5592r'; + fprintf('URI: %s\n', uri); + + % Circuit constants (NPN curve tracer on ADALM-LSMSPG) + Rsense = 47.0; % 47 Ohms - collector sense resistor + Rbase = 47.0e3; % 47 kOhms - base resistor + Vbe = 0.7; % Approximate base-emitter voltage + + % Read scale (mV per LSB) - identical for all AD5592r channels + mV_per_lsb = iio_read(uri, device, 'voltage0', true, 'scale'); + fprintf('Scale: %.6f mV/LSB\n', mV_per_lsb); + + % Initialize DAC outputs to a safe starting point + iio_write(uri, device, 'voltage0', true, 'raw', round(500 / mV_per_lsb)); + iio_write(uri, device, 'voltage2', true, 'raw', round(500 / mV_per_lsb)); + + % Sweep parameters (matching the Python example) + base_mv = 499:500:2499; + coll_mv = 0:50:2450; + n_base = length(base_mv); + n_coll = length(coll_mv); + + % Preallocate results + curves_vc = zeros(n_base, n_coll); + curves_ic = zeros(n_base, n_coll); + labels = cell(1, n_base); + + for bi = 1:n_base + vb_raw = round(base_mv(bi) / mV_per_lsb); + iio_write(uri, device, 'voltage0', true, 'raw', vb_raw); + + ib = ((vb_raw * mV_per_lsb / 1000) - Vbe) / Rbase; + fprintf('Base Drive: %.3f V, %.1f uA\n', ... + vb_raw * mV_per_lsb / 1000, ib * 1e6); + labels{bi} = sprintf('I_b = %.1f \\muA', ib * 1e6); + + for ci = 1:n_coll + vc_raw = round(coll_mv(ci) / mV_per_lsb); + iio_write(uri, device, 'voltage2', true, 'raw', vc_raw); + + vc_drive_raw = iio_read(uri, device, 'voltage2', false, 'raw'); + vc_sense_raw = iio_read(uri, device, 'voltage1', false, 'raw'); + + ic = (vc_drive_raw - vc_sense_raw) * mV_per_lsb / Rsense; + vc = vc_sense_raw * mV_per_lsb / 1000.0; + + curves_vc(bi, ci) = vc; + curves_ic(bi, ci) = ic; + end + end + + % Plot + figure('Name', 'AD5592r NPN Curve Tracer'); + hold on; + for bi = 1:n_base + plot(curves_vc(bi, :), curves_ic(bi, :), 'LineWidth', 1.5); + end + hold off; + title('ADALM-LSMSPG NPN Curve Tracer (MATLAB)'); + xlabel('Collector Voltage (V)'); + ylabel('Collector Current (mA)'); + legend(labels, 'Location', 'northwest'); + grid on; + end + + %% IIO helper functions using iio_attr command-line tool + + function val = iio_read(uri, device, channel, is_output, attr) + dir_flag = output_flag(is_output); + cmd = sprintf('iio_attr -u %s -c %s %s %s %s', ... + uri, dir_flag, device, channel, attr); + [status, result] = system(cmd); + if status ~= 0 + error('iio_attr read failed: %s', strtrim(result)); + end + tokens = regexp(result, '''([^'']+)''\s*$', 'tokens'); + if ~isempty(tokens) + val = str2double(tokens{1}{1}); + else + val = str2double(strtrim(result)); + end + if isnan(val) + error('Could not parse iio_attr output: %s', strtrim(result)); + end + end + + function iio_write(uri, device, channel, is_output, attr, value) + dir_flag = output_flag(is_output); + cmd = sprintf('iio_attr -u %s -c %s %s %s %s %d', ... + uri, dir_flag, device, channel, attr, value); + [status, result] = system(cmd); + if status ~= 0 + error('iio_attr write failed: %s', strtrim(result)); + end + end + + function flag = output_flag(is_output) + if is_output + flag = '-o'; + else + flag = '-i'; + end + end + +The helper functions ``iio_read`` and ``iio_write`` wrap calls to the +``iio_attr`` command-line tool. Each call spawns a subprocess that +connects to the tinyiiod server over serial, reads or writes the specified +channel attribute, and returns the result. + +.. note:: + + This approach is noticeably slower than the Precision Toolbox version + (Step 4a). The ``system()`` calls spawn a new ``iio_attr`` subprocess for + every read and write operation. For approximately 250 sweep points with + 4 IIO operations each, that is roughly 1000 subprocess launches. The + Precision Toolbox avoids this overhead by calling libiio directly + in-process, similar to how pyadi-iio wraps the libiio C library in Python. + +Step 5: Run the Curve Tracer +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +**Using the Precision Toolbox (Step 4a):** + +In MATLAB, ensure the PrecisionToolbox is on your path, update the URI in +the script to match your COM port, and run: + +.. code-block:: matlab + + ad5592r_curve_tracer + +**Using the command-line version (Step 4b):** + +.. code-block:: matlab + + ad5592r_curve_tracer_cli('serial:COM11,115200,8n1n') + +Replace ``COM11`` with your actual COM port. + +Both versions will: + +1. Read the scale from the AD5592r. +2. Sweep through 5 base voltage steps, each with 50 collector voltage steps. +3. Print progress to the MATLAB command window. +4. Display a figure with the NPN transistor I-V characteristic curves. + +The resulting plot should be comparable to the one produced by the Python +``ad5592r_curve_tracer.py`` script run on the Raspberry Pi. + +.. figure:: ad5592r_npn_curve_tracer.png + :width: 500px + + AD5592r NPN Curve Tracer output from MATLAB. + +Comparison: Raspberry Pi vs. MAX32666FTHR +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Both platforms produce the same curve tracer results, but the underlying +architecture is different: + +.. list-table:: + :header-rows: 1 + :widths: 30 35 35 + + * - + - **Raspberry Pi (Linux)** + - **MAX32666FTHR (Bare Metal)** + * - OS + - ADI Kuiper Linux + - No-OS (tinyiiod firmware) + * - IIO Framework + - Linux kernel IIO drivers + - no-OS IIO + tinyiiod + * - Connection to AD5592r + - SPI via device tree overlay + - SPI via no-OS SPI driver + * - Host Communication + - Network (``ip:analog.local``) + - USB Serial (``serial:COMx,115200,8n1n``) + * - Script Runs On + - Raspberry Pi or remote PC + - Remote PC only + * - Power + - 5V USB-C wall adapter + - USB bus power from PC \ No newline at end of file diff --git a/docs/learning/tools_for_ls/zephyr_example/index.rst b/docs/learning/tools_for_ls/zephyr_example/index.rst index bf8c8ee25da..95d17f003b5 100644 --- a/docs/learning/tools_for_ls/zephyr_example/index.rst +++ b/docs/learning/tools_for_ls/zephyr_example/index.rst @@ -9,6 +9,430 @@ RTOS Support: Zephyr -<> +The MATLAB example above used the MAX32666FTHR as a **tinyiiod server**, exposing +the ADALM-LSMSPG devices over serial for a host script to drive. In this section +we go a step further: the curve tracer application itself now runs **on the +MAX32666FTHR**, written against `Zephyr `__ — a +small, portable real-time OS. The PC becomes a passive terminal that only +displays results. + +.. note:: + + This exercise demonstrates using Zephyr as a fully embedded alternative to + Linux or bare-metal no-OS. Zephyr provides drivers for the shield's chips, + a POSIX-like shell over UART for interactive debugging, and a build system + that treats the ADALM-LSMSPG as a first-class device — no external host, + no IIO daemon, no Python or MATLAB. + +.. note:: + + The examples below target the **MAX32666FTHR**. The same steps apply to + the MAX32655FTHR (and any other Feather-form-factor Zephyr board) — swap + the ``-b max32666fthr/max32666/cpu0`` build target for the equivalent + board qualifier of your Feather. + +Hardware Prerequisites +^^^^^^^^^^^^^^^^^^^^^^ + +- **ADALM-LSMSPG** shield +- **MAX32666FTHR** Feather development board +- **MAX32625PICO** DAPLink debug adapter (comes with the FTHR kit) +- Two Micro USB cables — one for the FTHR (power), one for the DAPLink + (SWD + serial bridge) + +Software Prerequisites +^^^^^^^^^^^^^^^^^^^^^^ + +- **Analog Devices CodeFusion Studio (CFS)** 2.2.0 or later — ships an + integrated Zephyr 4.3.0 tree, the Zephyr SDK toolchain, and the ADI HAL + for the MAX32 family. Download from + `developer.analog.com `__. +- A serial terminal — **PuTTY**, `Tera Term `__, + or the built-in serial monitor of VS Code. +- (Optional) The full upstream Zephyr checkout via ``west init`` — for + users not on CFS. + +Architecture Overview +^^^^^^^^^^^^^^^^^^^^^ + +Unlike the tinyiiod approach, there is no host script and no IIO daemon. +Zephyr, the curve tracer logic, and the AD5592R / LM75 drivers all live in +a single firmware image running on the MAX32666FTHR: + +:: + + ┌────────────────┐ USB Serial ┌───────────────────────────┐ + │ PC (PuTTY) │ ◄──────────────► │ MAX32666FTHR │ + │ │ 115200 8N1 │ (Zephyr) │ + │ read-only │ │ │ + │ terminal │ │ Zephyr shell + main() │ + └────────────────┘ │ ┌────────────────────┐ │ + │ │ ad5592 curvetrace │ │ + │ └──────────┬─────────┘ │ + │ │ │ + │ Zephyr AD559X MFD │ + │ │ │ + │ SPI ◄──┴──► AD5592R │ + │ I2C ◄──────► AD5593R│ + │ I2C ◄──────► LM75 │ + └───────────────────────────┘ + +The **DAPLink** (MAX32625PICO) plays two roles at once: it programs the +FTHR over SWD, *and* it bridges the FTHR's UART1 to the PC as a USB CDC +serial port. That single COM port is where both flashing feedback and the +Zephyr shell prompt appear. + +Step 1: Create the Zephyr Project +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +From within CodeFusion Studio, generate a new project targeting +``max32666fthr / max32666 / cpu0``. Start from the **Blinky** template — it +gives us a working baseline (an LED that toggles) before we add anything. +The generated directory tree looks like: + +:: + + MAX32666_LSMSPG_Zephyr/ + └── m4-0/ + ├── CMakeLists.txt + ├── prj.conf + ├── boards/ + │ └── max32666fthr_max32666_cpu0.overlay + └── src/ + └── main.c + +The Blinky template targets the FTHR's on-board RGB LED via the standard +Zephyr ``led0`` alias — no shield references yet. + +Step 2: Configure the Drivers (``prj.conf``) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Zephyr uses a Kconfig-based build. The board's ``defconfig`` already +enables serial console, GPIO, and ``printk``; the ``adi_lsmspg`` shield +already ``select``\ s the SPI, I²C, and MFD subsystems in its +``Kconfig.shield``. On top of those defaults we only need to opt in to +the interactive shell and the AD559X chip driver: + +.. code-block:: none + + # Interactive shell over the console UART + CONFIG_SHELL=y + CONFIG_DEVICE_SHELL=y + CONFIG_I2C_SHELL=y + + # AD5592R / AD5593R chip driver + CONFIG_MFD_AD559X=y + +Step 3: The Curve Tracer Application +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The curve tracer is exposed as a Zephyr **shell command** — ``ad5592 +curvetrace`` — rather than running automatically at boot. This makes the +firmware into an interactive instrument: you can poke the DAC, read the +ADC, and rerun a sweep on demand from PuTTY. + +The C code mirrors the Python and MATLAB versions exactly: + +1. Sweep ``Vbase`` (CH0 DAC) from 499 mV to 2499 mV in 500 mV steps. +2. For each base voltage, sweep ``Vcollector`` (CH2 DAC) from 0 to 2450 mV + in 50 mV steps. +3. At each point, read back ``Vcdrive_meas`` (CH2 ADC) and ``Vcsense`` + (CH1 ADC), compute ``Ic = (Vcdrive_meas − Vcsense) / Rsense``, and + print one CSV-friendly line over UART. + +.. collapsible:: main.c — Zephyr curve tracer with shell integration (click to expand) + + .. code-block:: c + + /* + * AD5592R NPN BJT curve tracer on the ADALM-LSMSPG shield. + * Runs as a Zephyr shell command over the MAX32666FTHR's DAPLink + * USB-serial console. Uses the AD559X multi-function driver's + * raw write/read API to talk to the chip. + * + * ad5592 init One-time setup: enable ref + DAC pin mode. + * ad5592 dac Write 12-bit DAC code (0..4095). + * ad5592 adc Read one ADC channel. + * ad5592 curvetrace Run the NPN BJT curve trace. + * + * SPDX-License-Identifier: Apache-2.0 + */ + + #include + #include + #include + #include + #include + #include + #include + + #define VREF_MV 2500 + #define FS_CODE 4095U + + /* AD5592R 16-bit DAC write: [1 | ch[2:0] | data[11:0]] */ + #define AD559X_DAC_WR_MSB BIT(15) + #define AD559X_DAC_CH_SHIFT 12 + + /* Curve tracer circuit parameters (ADALM-LSMSPG NPN) */ + #define CT_RSENSE_OHM 47 + #define CT_RBASE_KOHM 47 + #define CT_VBE_MV 700 + #define CT_VB_START_MV 499 + #define CT_VB_STOP_MV 2500 + #define CT_VB_STEP_MV 500 + #define CT_VC_START_MV 0 + #define CT_VC_STOP_MV 2500 + #define CT_VC_STEP_MV 50 + + #define LED0_NODE DT_ALIAS(led0) + static const struct gpio_dt_spec led = + GPIO_DT_SPEC_GET(LED0_NODE, gpios); + + static const struct device *const mfd = + DEVICE_DT_GET(DT_PARENT(DT_NODELABEL(ad5592_dac))); + + static uint16_t dac_mask; + static uint16_t adc_mask; + static bool chip_initialized; + + static int ad5592_dac_write(uint8_t ch, uint16_t value) + { + uint16_t msg = sys_cpu_to_be16(AD559X_DAC_WR_MSB | + ((uint16_t)ch << AD559X_DAC_CH_SHIFT) | + (value & 0x0FFF)); + return mfd_ad559x_write_raw(mfd, + (uint8_t *)&msg, sizeof(msg)); + } + + static int ad5592_adc_read(uint8_t ch, uint16_t *out) + { + uint16_t raw = 0; + int ret = mfd_ad559x_read_reg(mfd, AD559X_REG_SEQ_ADC, + BIT(ch), &raw); + if (ret) return ret; + *out = raw & 0x0FFF; + return 0; + } + + static int cmd_init(const struct shell *sh, + size_t argc, char **argv) + { + int ret; + ret = mfd_ad559x_write_reg(mfd, AD559X_REG_PD_REF_CTRL, + AD559X_EN_REF); + if (ret) return ret; + dac_mask = 0xFF; + adc_mask = 0; + ret = mfd_ad559x_write_reg(mfd, AD559X_REG_LDAC_EN, + dac_mask); + if (ret) return ret; + chip_initialized = true; + shell_print(sh, "AD5592R initialized"); + return 0; + } + + static int cmd_curvetrace(const struct shell *sh, + size_t argc, char **argv) + { + if (!chip_initialized) { + shell_error(sh, "run 'ad5592 init' first"); + return -EINVAL; + } + adc_mask |= BIT(1) | BIT(2); + mfd_ad559x_write_reg(mfd, AD559X_REG_ADC_CONFIG, adc_mask); + + shell_print(sh, ""); + shell_print(sh, + "=== NPN Curve Tracer (Rsense=%dR Rbase=%dk) ===", + CT_RSENSE_OHM, CT_RBASE_KOHM); + + for (int vb = CT_VB_START_MV; vb < CT_VB_STOP_MV; + vb += CT_VB_STEP_MV) { + uint32_t vb_c = ((uint32_t)vb * FS_CODE) / VREF_MV; + ad5592_dac_write(0, vb_c); + k_msleep(50); + + int ib_ua = (vb > CT_VBE_MV) ? + (vb - CT_VBE_MV) / CT_RBASE_KOHM : 0; + shell_print(sh, + "\n-- Vb=%d mV, Ib~%d uA --", vb, ib_ua); + shell_print(sh, + "Vc_drive, Vc_actual, Ic (mV, mV, uA)"); + + for (int vc = CT_VC_START_MV; vc < CT_VC_STOP_MV; + vc += CT_VC_STEP_MV) { + uint32_t vc_c = ((uint32_t)vc * FS_CODE) / VREF_MV; + ad5592_dac_write(2, vc_c); + k_msleep(10); + + uint16_t vc_drive = 0, vc_sense = 0; + ad5592_adc_read(2, &vc_drive); + ad5592_adc_read(1, &vc_sense); + + int vc_drv_mv = (vc_drive * VREF_MV) / FS_CODE; + int vc_sns_mv = (vc_sense * VREF_MV) / FS_CODE; + int ic_ua = ((vc_drv_mv - vc_sns_mv) * 1000) / + CT_RSENSE_OHM; + + shell_print(sh, "%d, %d, %d", + vc, vc_sns_mv, ic_ua); + } + } + ad5592_dac_write(0, 0); + ad5592_dac_write(2, 0); + shell_print(sh, "\n=== done ==="); + return 0; + } + + SHELL_STATIC_SUBCMD_SET_CREATE(ad5592_cmds, + SHELL_CMD_ARG(init, NULL, "Init AD5592R", + cmd_init, 1, 0), + SHELL_CMD_ARG(curvetrace, NULL, "Run NPN curve trace", + cmd_curvetrace, 1, 0), + SHELL_SUBCMD_SET_END + ); + SHELL_CMD_REGISTER(ad5592, &ad5592_cmds, + "AD5592R shell commands", NULL); + + int main(void) + { + gpio_pin_configure_dt(&led, GPIO_OUTPUT_INACTIVE); + while (1) { + gpio_pin_toggle_dt(&led); + k_msleep(500); + } + } + +A few notes about the code: + +- ``main()`` only blinks the LED as a "firmware alive" heartbeat. All + real work happens in shell commands, which the Zephyr shell subsystem + runs on its own kernel thread. +- ``SHELL_CMD_REGISTER`` is Zephyr's macro for exposing a function as a + top-level shell command. ``SHELL_STATIC_SUBCMD_SET_CREATE`` groups + subcommands under a single command name (``ad5592``). +- The AD559X driver's ``mfd_ad559x_write_raw`` / ``mfd_ad559x_read_reg`` + functions handle SPI framing and chip-select for us. There is no + direct SPI code in the application. +- Output is CSV-shaped so you can copy the PuTTY buffer straight into + a spreadsheet for plotting. + +Step 4: Attach the Shield to the Build +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Zephyr ships an official shield definition for the ADALM-LSMSPG. To pull +its devicetree overlay into the build, pass ``--shield adi_lsmspg`` (as +a CMake variable ``-DSHIELD=adi_lsmspg``) to ``west build``. This binds +the AD5592R to the Feather SPI header and the AD5593R + LM75 to the +Feather I²C header automatically — no manual overlay edits required. + +.. note:: + + The shield definition lives at + ``/boards/shields/adi_lsmspg/``. Refer to the + `upstream Zephyr documentation + `__ + for its full description. + +Step 5: Build and Flash +^^^^^^^^^^^^^^^^^^^^^^^ + +From the project directory: + +.. code-block:: bash + + west build -p always -b max32666fthr/max32666/cpu0 . -- -DSHIELD=adi_lsmspg + west flash + +``west flash`` uses OpenOCD via the DAPLink to program the FTHR. If your +CFS install prefers drag-and-drop instead, the ``build/zephyr/zephyr.hex`` +file can be dragged onto the DAPLink mass-storage drive that appears in +Explorer. + +Step 6: Open the Serial Terminal +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Identify the COM port assigned to the DAPLink (Windows: **Device Manager +→ Ports (COM & LPT)** — look for the "USB Serial Device" entry that +appears when the DAPLink is plugged in). Open it in PuTTY at +**115200 8N1** with no flow control. + +Press the **reset** button on the FTHR. You should see: + +.. code-block:: none + + *** Booting Zephyr OS build v4.3.0 *** + + uart:~$ + +The ``uart:~$`` prompt is Zephyr's interactive shell. From here you can +type ``help`` for a list of built-in commands, ``device list`` to see +every device the kernel is aware of, or ``i2c scan i2c0@4001d000`` to +confirm the shield's I²C chips are alive. + +Step 7: Run the Curve Trace +^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +At the shell prompt: + +.. code-block:: none + + uart:~$ ad5592 init + AD5592R initialized + uart:~$ ad5592 curvetrace + + === NPN Curve Tracer (Rsense=47R Rbase=47k) === + + -- Vb=499 mV, Ib~0 uA -- + Vc_drive, Vc_actual, Ic (mV, mV, uA) + 0, 1, -21 + 50, 49, 21 + ... + -- Vb=999 mV, Ib~6 uA -- + ... + === done === + +Highlight the CSV block in PuTTY (Ctrl+A then right-click to copy on +most terminals) and paste it into a spreadsheet or the Python plotting +snippet from the Raspberry Pi section to render the I–V family. + +Comparison: MATLAB (tinyiiod) vs. Zephyr +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. list-table:: + :header-rows: 1 + :widths: 30 35 35 + + * - + - **MATLAB + tinyiiod** + - **Zephyr on FTHR** + * - OS on the FTHR + - no-OS (tinyiiod firmware) + - Zephyr RTOS + * - Where the sweep runs + - MATLAB on the PC + - On the FTHR itself + * - Host role + - Active — issues every I/O + - Passive — displays a shell + * - Framework used + - libiio + PrecisionToolbox + - Zephyr device drivers + * - Connection to devices + - IIO over USB serial + - Direct SPI / I²C on the FTHR + * - Latency per point + - ~ms (subprocess or in-proc) + - ~microseconds (direct SPI) + * - Extending the app + - Edit MATLAB, rerun + - Rebuild + reflash firmware + +.. note:: + + Zephyr trades the host-side flexibility of tinyiiod for **latency, + portability, and self-containedness**. A Zephyr firmware works with + only a serial terminal on the host — no libiio, no MATLAB, no Python. + That makes it a natural stepping-stone toward a *fully embedded* + product where the FTHR eventually drives a local display or wireless + link instead of a PC terminal.