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/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 5596583016e..b5faa831c19 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,50 +10,152 @@ 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 + +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. + +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. + +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. 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})` + + Where: + + :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. + + 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): @@ -62,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: @@ -88,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 ~~~~~~~~~~~~~~~~~~~~ @@ -112,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. @@ -121,41 +218,120 @@ 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 +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +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) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +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 @@ -176,24 +352,124 @@ 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: + +<> + +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++ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +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. + +:ref:`Continue to C, C++ 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. + +:ref:`Continue to MATLAB Tutorial ` + +.. toctree:: + :hidden: + + matlab_example/index + + IIO as a Tool for Migrating to an Embedded Implementation ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -217,59 +493,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. +:ref:`Continue to tinyiiod Tutorial ` -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. +.. toctree:: + :hidden: -Once the serial port is located, run the same curve tracer scripts as before, -but append the COM / tty port URI: + tinyiiod_example/index -.. 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. Porting to a Fully Embedded System ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -283,96 +516,59 @@ 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. +:ref:`Continue to tinyiiod Tutorial ` + +.. toctree:: + :hidden: + + standalone_no-os_example/index + +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. + +:ref:`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 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, +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. + +:ref:`Continue to ROS2 Integration Tutorial ` + +.. toctree:: + :hidden: + + ros2_integration/index Next Steps: No-OS development on Linux? You bet! ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -410,3 +606,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/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 new file mode 100644 index 00000000000..d829e693e5f --- /dev/null +++ b/docs/learning/tools_for_ls/matlab_example/index.rst @@ -0,0 +1,439 @@ +.. _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. + +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/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/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 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 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..95d17f003b5 --- /dev/null +++ b/docs/learning/tools_for_ls/zephyr_example/index.rst @@ -0,0 +1,438 @@ +.. _datax-zephyr-example: + +RTOS Support: Zephyr +------------------------ + +.. note:: + + This is a work in progress. + + + +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.