qNimble Quarto

website·Indexed 31 days ago

https://qnimble.com

A multi-function data acquisition platform described as a 'Digital Brain for the Analog World'. The platform includes qControl, a web application for interaction, and supports features such as ADC configuration, non-volatile memory (NVM) access, SD card interfacing, and a variant of Protothreads called qProtothreads for parallel function execution.

Tokens
32.5K
Snippets
164
Records
224
Agent score
46%

What's inside Quarto

  1. Overview of qControl

    qControl is a web application (available at qcontrol.qnimble.com) used to read, set, or graph variables on a Quarto device. It provides a custom user interface via widgets for mapped variables, eliminating the need to program a dedicated UI. Variables configured with qCommand are accessible within qControl. Layout configurations can be stored directly in the Quarto's code so that the UI remains consistent regardless of the computer accessing the device.
  2. Overview of qControl for Quarto

    qControl is a web application designed for interacting with the Quarto system. It allows users to design interfaces for plotting data and reading/writing variables without the need for GUI programming. Common use cases include rapid data plotting, displaying internal variables for debugging and troubleshooting, and creating full user interfaces for real-time adjustments, such as tuning servo PID parameters.
  3. Use qCommand library for dynamic variable control on Quarto

    The Quarto board software package version 1.5 introduces the qCommand library. This library allows developers to change variables on the Quarto board using text commands sent over either of its two serial communication ports.
  4. Understand qNimble Quarto low-latency architecture

    The Quarto architecture combines a powerful CPU with an FPGA to minimize latency. The FPGA handles all communication with the 16-bit DACs and ADCs, while a proprietary technology called InstaWrite™ allows the CPU to read from or write to the FPGA immediately without slowing down the CPU. This results in a signal chain latency of ~1μs and a total round-trip latency of ~5μs.
  5. Implement parallel execution using Protothreads in Quarto

    Quarto uses Protothreads to simulate concurrency. Unlike standard functions that execute sequentially from start to finish, a threaded function can stop executing (return) in the middle of its logic and resume from that exact point when called again. This allows multiple functions to appear to run at the same time by breaking them into smaller segments and calling them repeatedly within the main loop().
    void loop() {
        Function1();
        Function2();
    }
  6. Achieve low-latency analog control with Quarto

    Quarto allows reading from the ADC, writing to the DAC, and performing floating-point math with a latency of only a few microseconds. This performance enables servo bandwidths of up to 100kHz, providing FPGA-like speed without the associated complexity.
  7. Instantiate and use IntervalTimer on Quarto

    The IntervalTimer class allows a function to be called via an interrupt at a precisely timed interval. The Quarto supports a maximum of 4 active IntervalTimer objects at any given time. These should be instantiated as global objects.
    IntervalTimer someTimer;
  8. Enable multi-threading on Quarto board

    Starting with version 1.8 of the Quarto board software package, a new library is included that enables threading. This allows the Quarto board to execute multiple functions concurrently.
  9. Initialize and use SmartData objects

    SmartData is a data class used for storing and controlling data. It acts as an enhanced version of underlying types and is particularly useful when using qControl, as it automatically updates the qControl view when a value changes programmatically. It supports types such as float, double, int, uint, short, unsigned short, uint8_t, int8_t, and bool.
    #include "smartData.h"
    
    SmartData<double> someDouble;
    SmartData<uint16_t> someUint16 = 5;
    SmartData<bool> someBool = false;
    
    // SmartData objects can be used like normal types
    someUint16++;
    if (someBool) {
        someDouble *= 1.2 + 3 * someUint16;
    }
  10. Map variables to commands using assignVariable

    Use assignVariable in the setup() function to link a global variable to a command string. This allows the variable to be read or modified via serial commands or qControl.

    Supported types include pointers to bool, int, uint, float, double, arrays of these types, or SmartData objects.

    Parameters:

    • command: The string identifier for the variable.
    • variable: A pointer to the global variable.
    • read_only (optional): If true, the variable can only be viewed in qControl, not edited. Note: arrays and const variables are read-only by default.
    #include "qCommand.h"
    qCommand qC;
    
    double Jupiter = 1.234;
    bool Mars = false;
    uint16_t Saturn[4];
    
    void setup() {
        qC.assignVariable("Jupiter", &Jupiter);       // Read/Write
        qC.assignVariable("Mars", &Mars, true);        // Read-only in qControl
        qC.assignVariable("Sat", &Saturn);            // Array (automatically read-only)
    }
  11. Measure Quarto system phase-delay using Lock-in setup

    The Quarto introduces a phase shift due to the time required for reading, writing, and filtering analog data. To measure this delay:

    1. Set an aggressive (low) filter frequency to stabilize the output voltage.
    2. Use the phase command to find the value that results in a zero-voltage output (the zero crossing).
    3. Compare the measured zero-crossing phase to the ideal 90° shift. The difference represents the system's phase-delay.

    For example, at 10 kHz, a zero crossing at 72.1° indicates a phase shift of approximately 18° from the expected 90°.

    >> filter 10
    << The filter frequency is 10.000000 (and alpha=0.000126)
    >> phase 72.1
    << phase is 7.210000e+01
    >> output
    << output is -8.996903e-04
  12. Handle command arguments in qCommand

    Arguments are passed after the command string separated by spaces (e.g., command arg1 arg2). Use qC.next() to move to the next argument; it returns NULL if no further arguments exist. Use qC.current() to retrieve the value of the current argument as a string. To convert these strings to numbers, use atof() for doubles or atoi() for integers.
    void multiply(qCommand& qC, Stream& S) {
        double a;
        int b;
    
        if (qC.next() == NULL) {
            S.println("Missing arguments");
            return;
        }
        a = atof(qC.current());
    
        if (qC.next() == NULL) {
            S.println("Missing second argument");
            return;
        }
        b = atoi(qC.current());
    
        S.printf("%e times %d is %e\n", a, b, a * b);
    }