On 26/05/09 06:42PM, David Lechner wrote:
> On 5/8/26 12:00 PM, Rodrigo Alencar via B4 Relay wrote:
> > From: Rodrigo Alencar <[email protected]>
> >
> > Add documentation for the AD9910 DDS IIO driver, which describes channels,
> > DDS modes, attributes and ABI usage examples.
...
> > +Channel hierarchy
> > +=================
> > +
> > +The driver exposes the following IIO output channels, each identified by a
> > +unique channel number and a human-readable label:
> > +
>
> Can we format this as a table with a header to make it clear what each item
> is?
> I'm guessing that the second `` is the label?
>
> And perhaps provide a link to the sections below that describe the common
> attributes
> of each channel type?
Yes, that is a label. A table is better indeed.
> > +* ``out_altvoltage100``: ``phy``: Physical output: system clock and
> > profile control
>
> Any attributes on this one?
>
> > +
> > + * ``out_altvoltage101``: ``profile[0]``: Single tone control for profile
> > 0:
>
> Why not just ``profile0``?
>
> Also, why not ``out_altvoltage110`` so that the last digit matches the profile
> index? It looks like we are skipping by 10s later anyway.
Yeah, that can be done. I thought of out_altvoltage110 being a channel to hold
common
things between profiles, but it ended up empty so I left the spot as a
placeholder.
> > + frequency, phase, amplitude
> > +
> > + * ``out_altvoltage102``: ``profile[1]``: Single tone control for profile
> > 1:
> > + frequency, phase, amplitude
> > +
> > + * ``out_altvoltage103``: ``profile[2]``: Single tone control for profile
> > 2:
> > + frequency, phase, amplitude
> > +
> > + * ``out_altvoltage104``: ``profile[3]``: Single tone control for profile
> > 3:
> > + frequency, phase, amplitude
> > +
> > + * ``out_altvoltage105``: ``profile[4]``: Single tone control for profile
> > 4:
> > + frequency, phase, amplitude
> > +
> > + * ``out_altvoltage106``: ``profile[5]``: Single tone control for profile
> > 5:
> > + frequency, phase, amplitude
> > +
> > + * ``out_altvoltage107``: ``profile[6]``: Single tone control for profile
> > 6:
> > + frequency, phase, amplitude
> > +
> > + * ``out_altvoltage108``: ``profile[7]``: Single tone control for profile
> > 7:
> > + frequency, phase, amplitude
> > +
> > + * ``out_altvoltage110``: ``parallel_port``: Parallel port modulation
> > channel
>
> I guess no attributes on this one yet since implementation is deferred?
Only basic knobs will be exposed, proper implementation will come with a later
backend
support.
> > +
> > + * ``out_altvoltage120``: ``digital_ramp_generator``: DRG control: enable
> > +
> > + * ``out_altvoltage121``: ``digital_ramp_up``: DRG ramp-up parameters:
> > + dwell enable, limits, rate of change, ramp rate
> > + * ``out_altvoltage122``: ``digital_ramp_down``: DRG ramp-down
> > parameters:
> > + dwell enable, limits, rate of change, ramp rate
>
> Oh, I guess these are just the general "control knob" name, not the actual
> sysfs attribute name.
Correct, just a description.
>
> > +
> > + * ``out_altvoltage130``: ``ram_control``: RAM playback: enable,
> > frequency,
> > + phase and sampling frequency for active profile. Other configurations
> > are
> > + provided through a firmware upload interface.
> > +
> > + * ``out_altvoltage150``: ``output_shift_keying``: OSK: enable, amplitude
> > + scale, ramp rate, rate of change control
> > +
> > +The ``phy`` channel is the root of the hierarchy. Changing its
> > +``sampling_frequency`` reconfigures the system clock (SYSCLK) which
> > affects all
> > +other channels.
> > +
> > +Most of the mode-specific channels (single-tone, DRG, RAM, OSK) have an
> > +``enable`` attribute that turns the mode on/off.
> > +
...
> > +Parallel Port mode
> > +------------------
> > +
> > +The parallel port allows real-time modulation of DDS parameters through a
> > +16-bit external data bus.
> > +
> > +.. flat-table::
> > + :header-rows: 1
> > +
> > + * - Attribute
> > + - Unit
> > + - Description
> > +
> > + * - ``frequency_scale``
> > + - power-of-2
> > + - FM gain multiplier applied to 16-bit parallel input. Range
> > :math:`[1, 32768]`,
>
> General comment for the whole doc. Can you spell out the acronyms the
> first time they are used for us noobs.
>
> > + must be a power of 2.
> > +
> > + * - ``frequency_offset``
> > + - Hz
> > + - Base FTW to which scaled parallel data is added. Range :math:`[0,
> > f_{SYSCLK}/2)`.
> > +
> > + * - ``phase_offset``
> > + - rad
> > + - Base phase for polar modulation. Lower 8 bits of POW register.
> > + Range :math:`[0, 2\pi/256)`.
> > +
> > + * - ``scale_offset``
> > + - fractional
> > + - Base amplitude for polar modulation. Lower 6 bits of ASF register.
> > + Range :math:`[0, 1/256)`.
> > +
>
> I guess there was some discussion on these attributes. I see some of these in
> the
> ad9832 driver in staging, but I'm guessing they are new ABI. It isn't clear to
> me from the documentation here what they actually do though. I guess they are
> just basic transformations on the input signal?
Not sure how the ABI is not clear:
For a channel that allows amplitude control through buffers, this
represents the value for a base amplitude scale. The actual output
amplitude scale is a result with the sum of this value.
So yes, it is a basic transformation.
>
> And a practical note, they should be "frequencyscale". I don't like that it is
> harder to read, but it is easier for a machine to parse.
Parsers like the ones in libiio is not having problems with that.
> > +Usage examples
> > +^^^^^^^^^^^^^^
> > +
> > +Set parallel port frequency modulation with a scale of 16 and a 50 MHz
> > +offset:
> > +
> > +.. code-block:: bash
> > +
> > + echo 16 >
> > /sys/bus/iio/devices/iio:device0/out_altvoltage113_frequency_scale
> > + echo 50000000 >
> > /sys/bus/iio/devices/iio:device0/out_altvoltage113_frequency_offset
> > +
> > +Digital ramp generator (DRG)
> > +----------------------------
> > +
> > +The DRG produces linear frequency, phase or amplitude sweeps using
> > dedicated
> > +hardware. It is controlled through three channels: a parent control channel
> > +(``digital_ramp_generator``) and two child ramp channels
> > +(``digital_ramp_up``, ``digital_ramp_down``). DRG destination is set when
> > +ramp attributes are written, i.e. writing to ``frequency`` or
> > ``frequency_roc``
> > +sets the destination to frequency.
>
> Would it be better to say that the destination is set when the the
> value is non-zero? Otherwise, how would one change the destination
> once set?
Destination is only one, so you just need to write phase or phase_roc, if you
want
to target phase then. Does that not sound intuitive?
Zero is a valid value to be written.
>
> > +
> > +Control channel attributes
> > +^^^^^^^^^^^^^^^^^^^^^^^^^^
> > +
> > +.. flat-table::
> > + :header-rows: 1
> > +
> > + * - Attribute
> > + - Unit
> > + - Description
> > +
> > + * - ``en``
> > + - boolean
> > + - Enable/disable the DRG.
> > +
> > +Ramp channel attributes
> > +^^^^^^^^^^^^^^^^^^^^^^^^
> > +
> > +The ``digital_ramp_up`` and ``digital_ramp_down`` channels share the same
> > +attribute set but configure ascending and descending ramp parameters
> > +independently:
> > +
> > +.. flat-table::
> > + :header-rows: 1
> > +
> > + * - Attribute
> > + - Unit
> > + - Description
> > +
> > + * - ``dwell_en``
> > + - boolean
> > + - Enable dwell at the ramp limit. When disabled, the ramp
> > auto-transitions
> > + at this limit without waiting for the DRCTL pin. Disabling both
> > creates a
> > + bidirectional continuous ramp (Triangular pattern). Other
> > configurations
> > + create a single-shot ramp at the transition of the DRCTL pin:
> > ramp-up
> > + only, ramp-down only or bidirectional with dwell at the limits.
> > +
> > + * - ``frequency``
> > + - Hz
> > + - Frequency ramp limit. Range: :math:`[0, f_{SYSCLK}/2)`. Writing a
> > value
> > + sets the ramp destination to frequency. Reading back returns the
> > + currently active frequency limit or -EBUSY if other destination is
> > + active (phase or amplitude).
> > +
> > + * - ``phase``
> > + - rad
> > + - Phase ramp limit. Range: :math:`[0, 2\pi)`. Writing a value sets the
> > + ramp destination to phase. Reading back returns the currently active
> > + phase limit or -EBUSY if other destination is active (frequency or
> > + amplitude).
> > +
> > + * - ``scale``
> > + - fractional
> > + - Amplitude scale ramp limit. Range: :math:`[0, 1)`. Writing a value
> > sets
> > + the ramp destination to amplitude. Reading back returns the
> > currently
> > + active scale limit or -EBUSY if other destination is active
> > (frequency
> > + or phase).
> > +
> > + * - ``sampling_frequency``
> > + - Hz
> > + - Ramp clock rate. It is controlled by an integer divider so the
> > requested
> > + value will adjust to nearest supported value.
> > +
> > + * - ``frequency_roc``
> > + - Hz/s
> > + - Frequency rate of change. Sets the per-tick frequency
> > increment/decrement
> > + based on the current ramp clock rate.
> > +
> > + * - ``phase_roc``
> > + - rad/s
> > + - Phase rate of change. Sets the per-tick phase increment/decrement
> > based
> > + on the current ramp clock rate.
> > +
> > + * - ``scale_roc``
> > + - 1/s
> > + - Amplitude scale rate of change. Sets the per-tick amplitude scale
> > + increment/decrement based on the current ramp clock rate.
> > +
> > +Usage examples
> > +^^^^^^^^^^^^^^
> > +
> > +Configure a frequency sweep from 40 MHz to 60 MHz with a rate of change of
> > +25 GHz/s:
> > +
> > +.. code-block:: bash
> > +
> > + # Disable dwell on both limits for a bidirectional continuous ramp
> > + echo 0 > /sys/bus/iio/devices/iio:device0/out_altvoltage121_dwell_en
> > + echo 0 > /sys/bus/iio/devices/iio:device0/out_altvoltage122_dwell_en
> > +
> > + # Set ramp limits
> > + echo 60000000 >
> > /sys/bus/iio/devices/iio:device0/out_altvoltage121_frequency
> > + echo 40000000 >
> > /sys/bus/iio/devices/iio:device0/out_altvoltage122_frequency
> > +
> > + # Set ramp rate
> > + echo 25000000 >
> > /sys/bus/iio/devices/iio:device0/out_altvoltage121_sampling_frequency
> > + echo 25000000 >
> > /sys/bus/iio/devices/iio:device0/out_altvoltage122_sampling_frequency
> > +
> > + # Set frequency rate of change (Hz/s)
> > + echo 25000000000 >
> > /sys/bus/iio/devices/iio:device0/out_altvoltage121_frequency_roc
> > + echo 25000000000 >
> > /sys/bus/iio/devices/iio:device0/out_altvoltage122_frequency_roc
> > +
> > + # Enable the DRG
> > + echo 1 > /sys/bus/iio/devices/iio:device0/out_altvoltage120_en
> > +
> > +RAM mode
> > +--------
> > +
> > +The AD9910 contains a 1024 x 32-bit RAM that can be loaded with waveform
> > data
> > +and played back to modulate frequency, phase, amplitude, or polar (phase +
> > +amplitude) parameters.
> > +
> > +RAM control channel attributes
> > +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
> > +
> > +.. flat-table::
> > + :header-rows: 1
> > +
> > + * - Attribute
> > + - Unit
> > + - Description
> > +
> > + * - ``en``
> > + - boolean
> > + - Enable/disable RAM playback. Toggling swaps profile registers
> > between
> > + single tone and RAM configurations across all 8 profiles.
> > +
> > + * - ``frequency``
> > + - Hz
> > + - Frequency tuning word used as the single tone frequency when
> > + RAM destination is not ``frequency``. Range: :math:`[0,
> > f_{SYSCLK}/2)`.
> > +
> > + * - ``phase``
> > + - rad
> > + - Phase offset word used as the single tone phase when RAM destination
> > + is not ``phase``. Range: :math:`[0, 2\pi)`.
> > +
> > + * - ``sampling_frequency``
> > + - Hz
> > + - RAM playback step rate of the active profile, which controls how
> > fast the
> > + address counter advances. It is controlled by an integer divider so
> > the
> > + requested value will adjust to nearest supported value.
> > +
> > +Loading RAM data
> > +^^^^^^^^^^^^^^^^
> > +
> > +RAM data is loaded through the firmware upload framework. The driver
> > registers
> > +a firmware upload sysfs entry named ``iio_deviceX:ram``. The FW data
> > follows
> > +a simple binary format:
> > +
> > +- 80-byte header:
> > +
> > + - 4-byte big-endian magic word: 0x00AD9910;
> > + - 4-byte big-endian CFR1 value: configuration for the CFR1 register. Only
> > + bits relevant to RAM mode (data destination and internal profile
> > control)
> > + are considered. Other bits are ignored and have no effect:
> > +
> > + - Bits [30:29]: RAM data destination:
> > +
> > + - 00: frequency;
> > + - 01: phase;
> > + - 10: amplitude;
> > + - 11: polar;
> > +
> > + - Bits [20:17]: Internal profile control (see Table 14 of the
> > datasheet);
> > +
> > + - 8 sets of 8-byte big-endian profile data for profiles 0-7. Each set
> > contains:
> > +
> > + - Bits [55:40]: Address step rate value;
> > + - Bits [39:30]: End address for the profile;
> > + - Bits [23:14]: Start address for the profile;
> > + - Bit [5]: no-dwell high for ramp-up mode;
> > + - Bit [3]: zero-crossing for direct-switch mode;
> > + - Bits [2:0]: operating mode:
> > +
> > + - 000: direct switch;
> > + - 001: ramp-up;
> > + - 010: bidirectional;
> > + - 011: bidirectional continuous;
> > + - 100: ramp-up continuous;
> > +
> > + - 4-byte big-endian reserved word: set to 0;
>
> Will it be enough? :-)
>
> Another option could be to include a file format version field.
Yeah, maybe a CRC and a version as you pointed out. In terms of RAM
functionality,
that would be all. Maybe a table for this one too...
> > + - 4-byte big-endian word count: number of 32-bit words to be loaded
> > (0-1024);
> > +
> > +- Followed by the specified number of 32-bit big-endian data words.
> > +
> > +Usage examples
> > +^^^^^^^^^^^^^^
> > +
> > +Configure RAM mode with firmware data and enable it:
> > +
> > +.. code-block:: bash
> > +
> > + # Load RAM data via firmware upload
> > + echo 1 > /sys/class/firmware/iio\:device0\:ram/loading
> > + cat ad9910-ram.bin > /sys/class/firmware/iio\:device0\:ram/data
> > + echo 0 > /sys/class/firmware/iio\:device0\:ram/loading
> > +
> > + # Enable RAM mode
> > + echo 1 > /sys/bus/iio/devices/iio:device0/out_altvoltage130_en
> > +
...
> > +Physical channel
> > +================
> > +
> > +The ``phy`` channel provides device-level control:
> > +
> > +.. flat-table::
> > + :header-rows: 1
> > +
> > + * - Attribute
> > + - Unit
> > + - Description
> > +
> > + * - ``sampling_frequency``
> > + - Hz
> > + - System clock (SYSCLK) frequency. With PLL enabled, configures the
> > PLL
> > + multiplier (range 420-1000 MHz). Without PLL, ref clock can only be
> > + divided by 2.
>
> What controls the PLL?
It gets enabled in the device-tree. One would want that when feeding a lower
clock rate
source as a reference clock. It would also need a loop-filter connected to the
device.
This property can be used to configure the desired sysclk frequency, the PLL
divider/multiplier
and VCO configs will be derived from that.
> > +
> > + * - ``powerdown``
> > + - boolean (0 or 1)
> > + - Software power-down. Writing 1 powers down the digital core, DAC,
> > + reference clock input and auxiliary DAC simultaneously.
> > +
...
>
> I like the direction this is going. Looks sensible to me.
>
> I didn't have time to read the code, so just going off of the docs for now.
Thanks for the review. The code would need some cleanup after the ABI is mature.
Also, sashiko is pointing out a lot of issues already.. so those I suppose I can
handle on my own for now.
--
Kind regards,
Rodrigo Alencar