Post Go back to editing

Synchronizing ADALM-Pluto SDRs Using GPIO Pins and TDD Engine in MATLAB

Thread Summary

The user is seeking guidance on configuring GPIO pins for synchronization of four ADALM-Pluto SDRs and CN0566 Phasers in MATLAB. The final answer directs the user to a MathWorks example for TDD engine configuration and GPIO usage. The user's code for enabling the L10P pin as an output trigger is mostly correct, but the 'SyncSoft' attribute should not be used if an external pulse is applied to the L12N pin for synchronization. The TDD engine can be triggered either by an external pulse on L12N or by setting the 'SyncSoft' attribute to start the L10P pulses.
AI Generated Content
Category: Software
Software Version: v0.39 pluto firmware and matlab control with GPIO

I am working on a project involving four ADALM-Pluto SDRs and CN0566 Phasers, and I need to synchronize their receive operations using GPIO pins and the TDD engine. Specifically, I want to configure one Pluto SDR as the master device to trigger itself for reception and output a GPIO signal (e.g., on L10P - PL_GPIO_0) to the remaining three slave devices. The slave devices should use this GPIO signal (e.g., on L12N - PL_GPIO_1) to synchronize their reception.

I am using MATLAB for this setup and have successfully controlled the Phasers and Pluto SDRs for beamforming and data capture. However, I am unsure about the exact commands or attributes required to enable and configure GPIO pins for synchronization in MATLAB. For example, I’ve seen references to adi.one_bit_adc_dac in Python for enabling GPIO functionality, but I don’t know if there’s an equivalent in MATLAB. Additionally, I want to confirm the correct physical wiring (e.g., tying GND2 pins together) and whether the TDD engine can reliably trigger GPIO outputs.

Could anyone provide guidance or share their experience with GPIO-based synchronization for ADALM-Pluto SDRs in MATLAB? Any advice on the proper configuration, commands, or alternative approaches would be greatly appreciated!

Thanks.

Parents
  • Yes, there is an excellent example from MathWorks here:

    https://github.com/mathworks/Phaser-Control-with-MATLAB/tree/main

    For example, follow the FMCW_Range_Doppler_Lab.mlx in the Workshop folder.  It shows how the tddn properties are used for Phaser and Pluto.  Beyond that, there is more information on the GPIO pins here:

    https://www.youtube.com/live/PVlWK-39cCw?si=wh6pSJMfWwiJrJxQ&t=26965

  • Hi Jon,

    Thanks for your reply. I saw the setupLabRadar.m script where it has a sequence of commands to use the TDD engine via MATLAB. Specifically the following:

    % Setup the TDD engine
    bf_TDD = setupTddEngine();
    tStartRamp = 0;
    tStartCollection = 0;
    bf_TDD.PhaserEnable = 1;
    bf_TDD.Enable = 0;
    bf_TDD.EnSyncExternal = 1;
    bf_TDD.StartupDelay = 0;
    bf_TDD.SyncReset = 0;
    bf_TDD.FrameLength = tpulse*1e3;
    bf_TDD.BurstCount = nPulses;
    bf_TDD.Ch0Enable = 1;
    bf_TDD.Ch0Polarity = 0;
    bf_TDD.Ch0On = tStartRamp;
    bf_TDD.Ch0Off = tStartRamp+0.1;
    bf_TDD.Ch1Enable = 1;
    bf_TDD.Ch1Polarity = 0;
    bf_TDD.Ch1On = tStartCollection;
    bf_TDD.Ch1Off = tStartCollection+0.1;
    bf_TDD.Ch2Enable = 1;
    bf_TDD.Ch2Polarity = 0;
    bf_TDD.Ch2On = 0;
    bf_TDD.Ch2Off = 0.1;
    bf_TDD.Enable = 1;

    My question is how can I make the Pluto SDR at the header pin L10P (PL_GPIO_0) output a trigger? I hooked up an oscilloscope to L10P and did not observe any square wave with the following code I wrote.

    % Define the URI for the Pluto SDR
    plutoURI = 'ip:pluto1'; % Replace with the URI of your Pluto SDR

    % Create the TDD engine object
    bf_TDD = adi.PlutoTDD('uri', plutoURI);

    % Disable the TDD engine to make changes
    bf_TDD.Enable = 0;

    % Configure GPIO pins for output
    bf_TDD.Ch0Enable = 1; % Enable output trigger on L10P
    bf_TDD.Ch0On = 10; % Pulse on duration (in milliseconds)
    bf_TDD.Ch0Off = 10; % Pulse off duration (in milliseconds)

    % Set burst count for pulse generation on L10P
    bf_TDD.BurstCount = 0; % Example: repeat continually

    % Enable external synchronization
    bf_TDD.EnSyncExternal = 1;

    % Re-enable the TDD engine after making changes
    bf_TDD.Enable = 1;

    % Trigger the TDD engine programmatically
    bf_TDD.SyncSoft = 1; % Soft-sync the TDD engine

    Any help would be great. I want to verify the trigger pulse coming out of L10P this way I can daisy chain it to L12N - PL_GPIO_1 on the other CN0566 + Pluto SDR's I have.


    Thanks.


    Thomas

  • I believe all of that is correct, except that you need to delete "bf_TDD.SyncSoft = 1;

    Then apply an external GPIO pulse to the L12N pin.  You should see the number of pulses that you programmed coming out of the L10p pin

  • Thanks, for your replies, Jon. They are much appreciated!

    However, just to get something straight, I was under the impression that the L10P pin outputs a trigger on its own? What it sounds like you are saying is no, I have to supply my own pulse from a separate signal generator at the GPIO L12N pin in order to see a pulse coming out of the L10P pin?

    Thanks for the clarification here.


    Thomas

  • Yes, you can trigger pulses to be generated on L10P in one of two ways:
    1. Apply a external signal pulse to L12N.  This pulse will then be time aligned with the start of the L10P output pulses.

    2.  Use the "SyncSoft" attribute.  This will also start the L10P pulses, but without using the L12N pin.  

  • Unfortunately with these changes you describe above, following 2.) from your response and with the code adjustments you suggested prior, I could not observe pulses on L10P while using SyncSoft with an o-scope on L10P. I even verified that I had the correct parameters set in the TDD engine. I must be doing something incorrect here... Thanks for all the help.

     

  • Try to follow the example here:
    https://github.com/mathworks/Phaser-Control-with-MATLAB/blob/main/workshop/helpers/setupLabRadar.m

    So EnSyncExternal and PhaserEnable need to be 1, even for SyncSoft. And FrameLength is in ms, so probably set that to 1, instead of 10000, and try increasing burst count to 5. That should give 5 pulses, spaced 1ms apart. And also program CH0, Chan1, and CH2. All 3 need to be set.  So use the parameters from that example and you’ll get something like this:

    bf_TDD = adi.PlutoTDD('uri', plutoURI);
    bf_TDD.PhaserEnable = 1;
    bf_TDD.Enable = 0;
    bf_TDD.EnSyncExternal = 1;
    bf_TDD.StartupDelay = 0;
    bf_TDD.SyncReset = 0;
    bf_TDD.FrameLength = 1;
    bf_TDD.BurstCount = 5;
    bf_TDD.Ch0Enable = 1;
    bf_TDD.Ch0Polarity = 0;
    bf_TDD.Ch0On = 0;
    bf_TDD.Ch0Off = 0.1;
    bf_TDD.Ch1Enable = 1;
    bf_TDD.Ch1Polarity = 0;
    bf_TDD.Ch1On = 0;
    bf_TDD.Ch1Off = 0.1;
    bf_TDD.Ch2Enable = 1;
    bf_TDD.Ch2Polarity = 0;
    bf_TDD.Ch2On = 0;
    bf_TDD.Ch2Off = 0.1;
    bf_TDD.Enable = 1;

    % Set transmit waveform
    tx(txWaveform);

    % Trigger burst pulses
    bf_TDD.SyncSoft = 1;

    % Capture pulses
    data = rx();

  • Hi Jon,


    Thanks for this! I was able to get it working where the L10P output pulses according to my settings. My next question is the following: Can I use the output trigger pulse from L10P to self trigger the same Pluto by feeding the L10P pulse back into the L12N pin?

    Thanks, 


    Thomas

    ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

    Below is reference code that I used to based on the above code you supplied but I made removed many settings to see what was the least amount of code I needed for it to work as I wanted. Your code above did not work for me right away, I had to first call bff_TDD(); before changing bf_TDD values, else in my bf_TDD all values would be NaN, doing this first ensured I properly set bf_TDD values.

    bf_TDD = adi.PlutoTDD('uri', plutoURI);
    bf_TDD(); % Must be here to properly set bf_TDD values, else bf_TDD will be filled with NaNs

    Ch0On = 1; % Pulse width in ms
    DutyCycle = 20; % Desired duty cycle in percentage (e.g., 20%)

    % Calculate FrameLength based on Ch0On and DutyCycle
    FrameLength = (Ch0On / DutyCycle) * 100; % FrameLength in ms

    % Configure Pluto SDR
    bf_TDD.Enable = 0;
    bf_TDD.FrameLength = FrameLength; % Automatically calculated
    bf_TDD.BurstCount = 0;
    bf_TDD.Ch0Enable = 1;
    bf_TDD.Ch0On = Ch0On; % Pulse width in ms
    bf_TDD.Ch0Off = 0; % Not used in this case
    bf_TDD.Enable = 1;

    % Set transmit waveform
    % tx(txWaveform);

    % Trigger burst pulses
    bf_TDD.SyncSoft = 1;

    % Capture pulses
    % data = bf_TDD.rx(); 

  • Hi Jon, just following up once again to my question from 11/05/25 above, let me know if it is possible.


    Thanks.


    Thomas

  • Hi Jon, just following up once again to my question from 11/05/25 above, let me know if it is possible. See below additional question related to all this.


    Thanks.


    Thomas

Reply Children
No Data