Package: ad9546
ADI-AD9546Set of tools to interact & program AD9546/45 integrated circuits, by Analog Devices.Usethese toolsto interact with AD9548/47 older chipsets.These scripts are not Windows compatible.These scripts expect a/dev/i2c-Xentry, they do not manage the device
through SPI at the moment.Installpythonsetup.pyinstallDependenciespython-smbusInstall requirements withpip3install-rrequirements.txtAPIEach application comes with an-hhelp menu.Refer to help menu for specific information.i2cbus must always be specifiedi2cslave address must always be specified--flagis optionnal: action will not be performed if not requestedFor complex flag values (basically involving white spaces), for exampleref-input --coupling, don't forget to encapsulate with inverted commas:ref-input.py\00x48\# bus #0 slave address is 0x48--refa\# simple, one word--coupling"AC 1.2V"# 'complex' but meaningful valueref-input.py\10x4A\# bus #1 slave address is 0x4A--refaa\# simple, one word--coupling"internal pull-up"# 'complex' but meaningful valueFlag values are case sensitive and must be exactly matched.
It is not possible to pass a non supported / unknown flag value,
scripts will reject those with a runtime error.AD9545 / 46These scripts are developped and tested with an AD9546 chip.AD9545 is pin & register compatible, so it should work.It is up to the user to restrain to restricted operations in that scenario.Utilitiescalib.py: calibrates core portions of the clock. Typically required
when booting or a new setup has just been loaded.distrib.py: controls clock distribution and output signals.
Includes signal paths and output pins muting operations.irq.py: IRQ clearing & masking operationsmisc.py: miscellaneous operationsmx-pin.py: Mx programmable I/O managementpll.py: APLLx and DPLLx cores management. Includes
free running + holdover manual forcing operationpower-down.py: power saving and management utilityref-input.py: reference & input signals managementregmap.py: load or dump a register map presetregmap-diff.py: loaded / dumped regmap differentiator (debug tool)reset.py: device reset operationsstatus.py: status monitoring, includes IRQ flag reports and onboard temperature readingsysclk.py: sys clock control & management toolSee at the bottom of this page for typical configuration flows.Register mapregmap.pyallows the user to quickly load an exported
register map from the official A&D graphical tool.Input/output isjson--quietto disable the stdout progress barregmap.py-h# load a register map (on bus #0 @0x48)regmap.py00x48--loadtest.jsonExport current register map to open it in A&D graphical tools:regmap.py--dump/tmp/output.json00x48Register mapdiffIt is possible to use theregmap-diff.pytool
to differentiate (bitwise) an official A&D registermap (created with their GUI)
and a dumped one (--dumpedwith regmap.py).# order is always:#  1) official (from A&D GUi)#  2) then dumped fileregmap-diff.pyofficial_ad.json/tmp/output.jsonThis script is mainly used for debugging purposes.It is equivalent to adiff -q -Z official_ad.json /tmp/output.jsonfocused on the "RegisterMap" field.
That command being impossible to use, because --dump
does not replicate 100% of the official A&D file content (too complex),
and is not focused on the "RegisterMap" field.Status scriptstatus.pyis a read only tool to monitor the chipset status current status.
That includes IRQ status reports, calibration reports, integrated
sensors and measurement readings..status.py -hto figure all known keysOutput format isjsonand is streamed tostdout.
Each--flagcan be cumulated which increases the status report size/verbosity:# Grab general / high level info (bus=0, 0x4A):status.py00x4A\--info--serial# general info \--pll# pll core (timing general info)status.py10x48\--info\--pll--sysclk# timing cores info \--ref-input# input / ref. signals infostatus.py00x4A\--irq# IRQ status registerDump status report from stdout into a filestatus.py--info--serial--pll00x4A>/tmp/status.jsonOutput is ajsonstructure. That means it can be directly
interprated into another python script. Here's an example
on how to do that:importsubprocessargs=['status.py','--distrib','0','0x4A']# interprate filtered stdout content directlyret=subprocess.run(args)ifret.exitcode==0:# syscall OK# direct interpratationstruct=eval(ret.stdout.decode('utf-8'))print(struct["distrib"]["ch0"]["a"]["q-div"])Status report depicts a lot of information depending
on the targeted internal cores. Status.py supports
filtering operations, we we'll later describe how
an efficient filter can make things easier when
grabbing data from another scriptStatus report filteringFilters are described by comma separated values.
It is possible to cummulate filter of the same kind
and of different kind. Filters are applied in
order of appearance / description.
Identifier filter is applied priori Value filter.--filter-by-key: filters result by identification keyword.
This is useful to retain fields of interests# grab vendor fieldstatus.py00x48\--info--filter-by-keyvendor# single field filter# zoom in on temperature infostatus.py00x48\--misc--filter-by-keytemperature# single field filter# only care about CH0status.py00x48\--distrib--filter-by-keych0# single field filter# only care about AA path(s)# [CH0:AA ; CH1:AA] in this casestatus.py00x48\--distrib--filter-by-keyaa# single field filterExample of cummulated filters:# grab (vendor + chiptype) fieldsstatus.py00x48\--info--filter-by-keychip-type,vendor# comma separated# zoom in on temperature readingstatus.py00x48\--misc--filter-by-keytemperature,value# zoom in# Retain `aa` path from CH0# Filter by order of appearance,# specifying CH0 then AA ;)status.py00x48\--distrib--filter-by-keych0,aaBy default, if requested keyword is not found (non effective filter),
fulldata set is preserved.# non effective filter example:status.py--info--filter-by-keysomething00x48filter-by-value: it is possible to filter status reports
by matching values# Return `0x456` <=> vendor fieldstatus.py10x48\--info\--filter-by-value0x456# Return only deasserted valuesstatus.py10x48\--distrib\--filter-by-valuedisabled# Event better `deasserted` value filterstatus.py10x48\--distrib\--filter-by-valuedisabled,false,inactiveIt is possible to combinekeyandvaluefilters:# from CH0 return only deasserted valuesstatus.py10x48\--distrib\--filter-by-valuech0\--filter-by-valuedisabled,false,inactiveExtract raw data from status reportThe--unpackoption allows convenient
data reductionif the requested filter has reduced the dataset
to a single value, we expose the raw data:status.py00x4A\--info--filter-by-keyvendor# extract vendor info \--unpack# raw valuestatus.py00x4A\--misc--filter-by-keytemperature,value# extract t° reading \--unpack# raw value# extract temperature alarm bitstatus.py00x4A\`--misc--filter-by-keytemperature,alarm# extract t° alarm bit \--unpack# raw valueThis is very convenient when importing data into an external script.
Here's an example in python once again:importsubprocessargs=['status.py','0','0x4A','--misc','--filter-by-key','temperature,alarm'# extract raw bit]ret=subprocess.run(args)ifret.exitcode==0:# syscall OK# bool() direct casthas_alarm=bool(ret.stdout.decode('utf-8'))If the status report comprises several value,
then--unpacksimply reduces the structure to 1D.
That means we lose data because we can only have
a unique value per identifierstatus.py00x4A\--misc--filter-by-keytemperature# extract temperature fields \--unpackSys clockSysclock compensation is a new feature introduced in AD9546.sysclock.pyallows quick and easy access to these features.To determine currentsysclockrelated settings, use status.py with--sysclockoption.--freq: to program input frequency [Hz]--sel: to select the input path (internal crystal or external XOA/B pins)--div: set integer division ratio on input frequency--doubler: enables input frequency doublerCalibration scriptcalib.pyallows chipset (re)calibration.It is required to perform a calibration at boot time.It is required to perform an analog Pll (re)calibration anytime
we recover from a sys clock power down.Perform complete (re)calibrationcalib.py--all00x4APerform only a sys clock (re)calibration
(1st step in application note)calib.py--sysclk00x4AMonitor internal calibration process withstatus.py10x4A\-pll--sysclk--filter-by-keycalibrating
status.py10x4A\--sysclk--irq--filter-by-keycalibrationClock distributiondistrib.pyis an important utility.It helps configure the clock path, control output signals
and their behavior.To determine the chipset current configuration related to clock distribution,
one should use the status script with--distriboption.Control flags:--channel(optionnal) describes which targetted channel.
Defaults toall, meaning if--channelis not specified, both channels (CH0/CH1)
are assigned the same value.
This script only suppports a single--channelassignment.--path(optionnal) describes desired signal path.
Defaults toallmeaning, all paths are assigned the same value (if feasible).This script only suppports a single--pathassignment at a time.Refer to help menu for list of accepted values.--pin(optionnal) describes desired pin, when controlling an output pin.
Defaults toallmeaning, all pins (+ and -) are assigned the same value when feasible.Refer to help menu for list of accepted values.Action flags: the script supports as manyactionflags as desired, see the list down below.--modeset OUTxy output pin as single ended or differential--formatsets OUTxy current sink/source format--currentsets OUTxy pin output current [mA], where x = channel# set channel 0 as HCSL default formatdistrib.py--formathcsl--channel0# set channel 1 as CML formatdistrib.py--formathcsl--channel1# set channel 0+1 as HCSL default formatdistrib.py--formathcsl# set Q0A, Q0B as differntial outputdistrib.py--modediff--channel0# set Q1A, as single ended pindistrib.py--modese--channel1--pina# set Q0A Q0B to output 12.5 mA, default output currentdistrib.py--current12.5--channel0# set Q1A to output 7.5 mA, minimal currentdistrib.py--current7.5--channel1--pina--sync-all: sends a SYNC order to all distribution dividers.
It is required to run async-allin case the current output behavior
is not set toimmediate.# send a SYNC all# SYNC all is required depending on previous actions and current configurationdistrib.py--sync-all00x48--autosync: control given channel so called "autosync" behavior.# set both Pll CH0 & CH1 to "immediate" behaviordistrib.py--autosyncimmediate00x48# set both Pll CH0 to "immediate" behaviordistrib.py--autosyncimmediate--channel000x48#  and Pll CH1 to "manual" behaviordistrib.py--autosyncmanual--channel100x48In the previous example, CH1 is set to manual behavior.One must either perform async-alloperation,
aq-syncoperation on channel 1,
or an Mx-pin operation with dedicated script, to enable this output signal.--q-sync: initializes a Qxy Divider synchronization sequence manually.
When x is thechannelandyis desired path.# triggers Q0A Q0B Q1A Q1B SYNCdistrib.py--q-sync00x48# triggers Q0A Q0B SYNCdistrib.py--q-sync--channel000x48# triggers Q0B Q1B SYNC because --channel `all` is implieddistrib.py--q-sync--pathb00x48--unmute: controls QXY unmuting opmode,
where x is thechannelandydesired path.# Q0A Q0B + Q1A Q1B `immediate` unmutingdistrib.py--unmuteimmediate00x48# Q0A Q1A `phase locked` unmutingdistrib.py--unmutephase--patha00x48# Q0B Q1B `freq locked` unmutingdistrib.py--unmutefreq--pathb00x48# Q0A + Q1B `immediate` unmutingdistrib.py--unmuteimmediate--patha00x48
distrib.py--unmuteimmediate--pathb00x48--pwm-enableand--pwm-disable: constrols PWM modulator
for OUTxy where x is thechannelandythe desired path.--divider: control integer division ratio at Qxy stage# Sets R=48 division ratio,# for Q0A,AA,B,BB,C,CC and Q1A,AA,B,BB# because --channel=`all` and --path=`all` is implieddistrib.py--divider4800x48# Sets Q1A,AA,B,BB R=64 division ratio# because --path=`all` is implieddistrib.py--divider64--channel100x48# Q0A & Q0B R=23 division ratio# requires dual assignment, because --pin {a,b} is not feasible at oncedistrib.py--divider23--channel0--pina00x48
distrib.py--divider23--channel0--pinb00x48--half-divider: enables "half divider" feature @ QXY path--phase-offsetapplies instantaneous phase offset to desired
output path. Maximal value is 2*D-1 where D is previous--dividerratio
for given channel + pin.# Apply Q0A,AA,B,BB,C,CC + Q1A,AA,B,BB# TODO--unmuting: controls "unmuting" behavior, meaning,
output signal can be exposed automatically depending on clock state.--muteand--unmuteto manually enable/disable an output pinReset scriptTo quickly reset the device--soft: performs a soft reset--sans: same thing but maintains current registers value--watchdog: resets internal watchdog timer-hfor more infos# Resets (factory default)reset.py--soft10x48
regmap.py--loadsettings.json10x48reset.py--sans10x48# settings are maintainedRef input scriptref-input.pyto control the reference input signal,
signal quality constraints, switching mechanisms
and the general clock state.--freqset REFxy input frequency [Hz]--couplingcontrol REFx input couplinglockmust be previously acquired.freq-lock-thresh: frequency locking mechanism constraint.phase-lock-thresh: phase locking mechanism constraint.phase-step-thresh: inst. phase step thresholdphase-skew: phase skewPLL scriptpll.pyto control both analog and digital internal PLL cores.pll.pyalso allows to set the clock to free run or holdover state.--type: to specify whether we are targetting an Analog PLL (APLLx)
or a Digital PLL (APLLx). This field is only required
for operations where it is ambiguous (can be performed on both cores).allis the default value.--type alltargets both APLLx and DPLLx core(s).--channel: setxin DPLLx or APLLx targeted cores.--channel all: is the default behavior, targets both channel 0 and 1
of the desired type.--free-run: forces clock to free run state,--typeis disregarded
becausedigitalis implied.--holdover: forces clock to holdover state,--typeis disregarded
becausedigitalis implied.Power down scriptpower-down.pyperform and recover power down operations.Useful to power down non needed channels and internal cores.The--allflag addresses all internal cores.Otherwise, select internal units with related flagPower down device entirelypower-down.py00x4A--allRecover a complete power down operationpower-down.py00x4A--all--clearWakeAreference up and putAA,B,BBreferences to sleep:power-down.py00x4A--refb--refbb--refaapower-down.py00x4A--clear--refaCCDPLL : Digitized Clocking Common Clock SynchronizerCCDPLL status report:status.py--ccdpll10x48CCDPLL must be configured and monitored for UTS & IUTS related operationsUser Time Stamping coresUTS cores allow the user to timestamp input data against
a reference signal. UTS requires the CCDPPL that is
part of the Digitized clocking core to be configured.uts.pycontrols both the UTS core and the inverse UTS core.
This is controlled by the--type inverseoption.The default--typeis "normal" for UTS management by default.Therefore it is mandatory to specifyinversefor IUTS management.UTS and IUTS status reports are reported by the status.py script:status.py10x4A\--uts\--iuts

status.py00x48\--uts\--filter-by-keyfifo,0It is useful to combine this status report to the digitized
clocking status report as they are closely relatedstatus.py10x4A\--ccdpll\--utsSome UTS/IUTS raw data are signed 24 or 48 bit values, this
portion of the status script should interprate those values correctly,
but it has to be confirmed / verified.It is not clear at the moment which UTSx core (8 cores) is fed
to the UTS FIFO (unique fifo).
Therefore it is not clear to me which scaling should apply
when interprating the data contained in the UTS FIFO.At the moment, I hardcoded Core #0 (1st one) as the frequency source
➜ to clarify and improve.Inverse UTS managementTODOIRQ eventsstatus.py --irqallows reading the current asserted IRQ flags.Clear them withirq.py:--all: clear all flags--pll: clear all PLL (PLL0 + PLL1 + digital + analog) related events--pll0: clear PLL0 (digital + analog) related events--pll1: clear PLL1 (digital + analog) related events--other: clear events that are not related to the pll subgroup--sysclk: clear all sysclock related events-h: for other known flagsMiscstatus.py --miscreturns (amongst other infos) the internal temperature sensor reading.Get current reading :status.py--misc10x48# Filter on field of interest like thisstatus.py--misc10x48--filter-by-keytemperature,value--unpack# Is temperature range currently exceededstatus.py--misc10x48--filter-by-keytemperature,alarm--unpackProgram a temperature range :misc.py--temp-thres-low-10# [°C]misc.py--temp-thres-high80# [°C]misc.py--temp-thres-low-30--temp-thres-high90status.py--temp00x48# current reading [°C]Related warning events are then retrieved with theirq.pyutility, refer to related section.Typical configuration flowsload a profile preset, calibrate and get startedregmap.py--loadprofile.json--quiet00x48
status.py--pll--distrib--filter-by-keych000x48
calib.py--all00x48
status.py--pll--distrib--filter-by-keych000x48distrib operation: mute / unmute + powerdown (TODO)using integrated signal quality monitoring (TODO)