Automatise the testing of SPIN's merge request (GEII - Toulouse)

Hello, we are working on a project to automatise the testing of any un-proven code from the Owntech repo.

So far we decided to only automatise a simple test sequence, by testing a functionnality in the platformIO editor (create PWMs with different phase), and then use a python script to auto-build/send it in the SPIN, and in that same script we will use pyvisa to access the instrument and make a selection of relevant measures (in the case of PWM, their vAmp, duty cycle and phase compared to eachother), then use that data to OK/KO the test.
If this works, this base could be easely expanded to a lot of functions from the SPIN, and tested in a single script.

We assembled our testbench already (1 spin connected with 3 mux, synchronising them, and all relevant outputs linked to a mux channel, for exemple three pwms output on each channel0 of each mux, with a measure probe in the mux output pin, that we can access via Pyvisa), and we made functions to set the mux channels we want, which was validated. PWM generation also works.

Our next step is to control our instrument via pyvisa. We made a code that we couldn’t test properly besides managing to connect to our device and preset it.

Here is our python script so far, as requested by Mr Villa :

import time
import pyvisa

def setup_scope_for_measurements(scope, averages=8, do_autoset=True):
    # Reset système (comme si on redémarrait)
    scope.write(":SYSTem:RESet")
    time.sleep(1.0)

    # Active les voies 1 et 2 (on test sans la 3 pour l'instant)
    scope.write(":CHANnel1:DISPlay ON")
    scope.write(":CHANnel2:DISPlay ON")

    # Couplage DC
    scope.write(":CHANnel1:COUPling DC")
    scope.write(":CHANnel2:COUPling DC")

    # Nettoie toutes les mesures actives
    scope.write(":MEASure:DELete")

    # Seuils par défaut
    scope.write(":MEASure:THReshold:DEFault")

    # Acquisition en moyenne
    scope.write(":ACQuire:TYPE AVERages")

    # Le guide indique un count entier de 1 Ă  16
    avg = int(max(1, min(16, averages)))
    scope.write(f":ACQuire:AVERages {avg}")

    # AUToset pour un trigger automatique
    if do_autoset:
        scope.write(":AUToset")
        time.sleep(1.0)

    time.sleep(0.5)

def _query_float(scope, cmd):
    resp = scope.query(cmd).strip()
    return float(resp)

def measure_ch1_ch2_and_phase(scope):
    # Amplitudes
    vamp_ch1 = _query_float(scope, ":MEASure:ITEM? VAMP,CHANnel1")
    vamp_ch2 = _query_float(scope, ":MEASure:ITEM? VAMP,CHANnel2")
    # Déphasage entre CH1 et CH2
    phase_rr = _query_float(scope, ":MEASure:ITEM? RRPHase,CHANnel1,CHANnel2")
    return vamp_ch1, vamp_ch2, phase_rr

if __name__ == "__main__":
    rm = pyvisa.ResourceManager()
    resources = rm.list_resources()
    print("Ressources VISA détectées :")
    print(resources)

    if not resources:
        raise RuntimeError(
            "Aucune ressource VISA détectée. Vérifie le câble USB, le driver VISA, "
            "et que l'oscillo est bien en mode remote/USB-TMC."
        )

    scope = rm.open_resource(resources[0])
    scope.timeout = 10000

    print("IDN =", scope.query("*IDN?").strip())

    setup_scope_for_measurements(scope, averages=8, do_autoset=True)
    v1, v2, ph = measure_ch1_ch2_and_phase(scope)

    print(f"Vamp CH1 = {v1} V")
    print(f"Vamp CH2 = {v2} V")
    print(f"RRPHase(CH1,CH2) = {ph} (unité selon l'oscillo, typiquement en degrés)")

Thanks for reading us :smiley:

End of project follow-up

We found something interesting, it seems that the PWM E channel (HRTIM1-CHE) has a 180° desync at his creation.
For exemple here :

The Pink PWM is generated with a phase shift of 240°, yet we can measure a shift of only 60°.

spin.pwm.setPhaseShift(PWMC, 240);

When accounting for a 180 differencial, it now behaves properly. We also tested every other PWM channel (A,C, D, F) and none other presents that issue. It could be worth investigating further, as potential issues could raise with anything exploiting this channel.

About our project itself, we realised our objectives. Our python script automatises measures and controls the instrument and has been validated.

We implemented manually a Vamp and phase shift tests, as specific measures have to be implemented based on the documentation containing each instructions, however we built a base structure with generic functions to execute the tests, so a tester would just have to refer himself to the doc to find the specific instructions, add them to a test function, but all the helpers and the feedback is implemented already.

About our PlateformIO project, we implemented simple functions to automatise the creation of test sequences, by creating a function to command our muxs (control which channel to output), and a function to create a PWM signal with custom phase shift or duty cycle.

So an automatic sequence to be tested could be to enable the desired mux channel, call the PWM function (or any that creates a specific behavior to test, it’s just that we only implemented PWM generation as that was the task we were asked to do), and the program would end there, instrument measures to validate the test being handled by the python script.

We created this testbench to ensure our design was usable and that we weren’t getting noise/attenuation by using muxs, but none was happening.

We tested the frequency we could use, and the signals remainted stable until > 1000kHz.

We imagined a standard test bench (and test sequence) :

  1. A design with two slots to put two spins, one to control muxes (via the functions we created) and another to test a specific functionnality from the SPIN (we implemented PWM but it can be any functionnality).
  2. Then link each channels to a specific mux channel, like all DAC to the channel 0, three PWMs to channel 1, the other three to channel 2 etc..
  3. Then you can use the python script to activate the mux channels you want via the first spin, load the sequence to be tested in the 2nd spin, and execute the test sequence on python. When it’s over, you can immediately check if anything was KO or not.

Long term, you could just make a static test for every functionnality and once it’s done, you can easely test any merge request by cloning it, build it with the test sequence, and run the py script, effectively fully automatising it.

The full py script and c program are detailed in our Readme that we pushed to the project repo on git and in the Moodle repo (from mr villa).

Great work @C-Prevot !
We’ll iterate on that to get more testing coverage.
It’s nice to see that the analog multiplexing actually does work without polluting the measurements.

1 Like