
These are some notes I’ve taken when creating a circuit that takes a 10 MHz sine-wave input and outputs several copies of the same, with a minimum of added phase noise or distortion. First, select a topology and simulate it. Then, build the circuit and measure the key specs: noise, crosstalk, distortion.
The goal is simple, 10 MHz in, 10 MHz out. Many approaches have been explored:
Take a differential 10 MHz input signal, pass it through a difference amplifier, output a single ended signal.
Start with 20 MHz, pass it through a flip-flop to divide by 2, and filter the resulting square wave to kill the harmonics and obtain a sine wave.
Design a differential amplifier using discrete transistors to drive a signal transformer to lower the output impedance.
Emitter follower, with AC coupled output (series LC).
Inverting op-amp plus some filtering and the impedance transformer at the output.
Non-inverting op-amp output circuit.
Of these, I have chosen the version that I find easiest to explain to myself: an inverting buffer drives several non-inverting output drivers. This is shown in the image below.

A straightforward transient LTspice simulation (.tran 0 1.5u 0.5u 25p) shows
that the output amplitude is 1Vrms. In other words, the circuit should work as
shown.
In the simulation I used the spice model for the LMH6609 op-amp provided by
Texas Instruments (original model by National Semiconductor). It works just fine
in LTspice except for commenting out a comment. Apparently PSPICE supports the
/ symbol as comment in addition to the * used by LTspice.
A key spec on any multi-channel instrument is crosstalk: if a signal is injected in one output, does it show up in the other output?
Notice the V4 signal source in the LTspice schematic shown above. If we
disable the main signal source V3 to AC 0 and enable V4 as AC 1, then an
AC simulation (.ac dec 200 1k 1G) shows about 10μV of crosstalk at out1.
Including a rough estimate for layout-dependent capacitive coupling between two
outputs directly (e.g. 10fF at C7), this rises to 17μV, or about -95 dB.
Assuming the op-amp model is accurate, we can use this result to estimate the phase pulling between the two outputs. Assume one of the outputs is connected to an unterminated cable such that the full signal strength—all 1Vrms or +13dBm of it—comes back in quadrature. The peak amplitude is 2.82 × 17 μV = 48μV.
Adding a small phasor a at angle φ to a carrier A gives a resultant phase
shift Δφ ≈ (a/A)·sin φ. The angle φ is set by the cable’s round-trip delay
plus the coupling path’s fixed phase—and since the user can present any
length, the worst case is φ = 90° (quadrature), where the interferer is pure
phase: Δφ = 48 µV / 1.38 V = 35 µrad.
At 10MHz one period is 100ns spanning 2π rad, so Δt = Δφ/(2πf) = 34e-6 /
(6.28e7) ≈ 0.55 ps. The reflection on Ch-2 will cause Ch-1 to move in phase by
less than a picosecond. Pretty good!
There are many mechanisms that contribute to the phase noise at our outputs. Let us immediately ignore the noise of the 10 MHz source and instead focus on what adds to the source’s phase noise.
At large offsets away from carrier, the noise floor is set by op-amp voltage
noise, resistor Johnson noise, and current noise. The same LTspice model from
above (remember to disable V4 and re-enable V3!) can be used to calculate
the voltage noise density at the output, by means of a .noise V(out1) V3 lin
401 9.9Meg 10.1Meg simulation directive. At 10 MHz, it reads 9.7 nV/rtHz.
Relative to the 1 Vrms output amplitude, this is a phase noise floor of
L = 20 log10(9.7e-9 / 1.00) − 3.01 = −163 dBc/Hz.Note the 3 dB subtracted, due to the fact that the noise decomposes into components in phase and in quadrature with the carrier phasor. The in-phase part wiggles the amplitude; the quadrature part wiggles the phase. For additive noise these are equal in power, so exactly half the noise power becomes phase modulation.
Any air moving across the board, whether forced or natural convection, can cause the temperature of PCB components to fluctuate. Ferrite inductors, such as the 1.5 μH seen in our tank circuit, might have as much as 500 ppm/K of temperature coefficient. We can step the inductance value in the LTspice simulation to find about 0.45° of phase change due to 1% change in inductance.
Putting the numbers together, the phase sensitivity is 3.9e-4 rad/K, or, in time units, about 6.3 ps/K. If we estimate the inductors temperature noise at 1 Hz to be about 1.5 mK/rtHz, then the phase noise would be
L = 20 log10(3.9e-4 * 1.5e-3) - 3.01 = -127 dBc @ 1 Hz offset.That’s a significant amount of phase noise, but easily fixed by reducing the air
currents or increasing thermal insulation. The inductor temperature changes are
heavily low-pass filtered by means of the part’s thermal inertia. In other
words, above the thermal pole the response falls as f^{-2}, so lowering the
corner buys 20 dB per decade of shift.
Any sound or mechanical vibration modulates the electrical characteristics of the circuit. Non-NP0 capacitors are particularly affected, so it’s important to verify there’s none in the critical signal path.
Inductors are also prone to microphonics, via magnetostrictive modulation of inductance. The datasheet will most likely not specify it, so instead we take a wild guess, say 1.5e-4 inductance change per “g” of acceleration.
Reusing the 0.45° per 1% coefficient from the previous section, the phase sensitivity is 1.2e-4 rad/g, or about 1.9 ps/g. A fan blade-pass tone at 120 Hz depositing 0.01 g peak gives a peak phase deviation of 1.2 μrad, and a sinusoidal modulation of peak deviation Δφ produces sidebands at
20 log10(1.2e-6 / 2) = -124 dBc.
Disclaimer: I’m not a theologian, proceed at your own risk.
An astute reader of the Notes on Cassian noticed a wild claim of mine, that “being dead to the wold” means afterlife, when examining Cassian’s thoughts on divine contemplation and “seeing God”, in Conf. 1, Ch. XV. Let’s take a closer look.
I don’t think you can “see God”, no matter how “pure” or “dead to the world” you are. To be fair, Cassian only makes the converse claim: if, any carnal affections survive in you, then you cannot lastingly contemplate God. Am I going too far by assuming Cassian implied the reverse claim: you could lastingly contemplate God if only no carnal affections survive in you?
A parallel set of claims arises from his scriptural quote. Exodus states that if you see God, then you cannot live. Cassian elaborates: you cannot live to “this world and to earthly affection” (mundo huic affectibusque terrenis). The implied reverse statement in this case is, if you’re “dead to the world”, then you may be able to see God. Again, did Cassian intend this implication or am I reading into it too far?
There’s only two options, either he did mean it or he did not. If he did not mean it, then we could discuss whether carnal affections (carnalis affectus) prevent you from contemplating God “lastingly” (perpetuo), or from seeing God. Since I’m not at this point interested in studying perpetuity, i.e., eternity or afterlife, so let’s pass on to the other option: Cassian did mean the “reversed claim”: purify your heart and you’ll be able to see God now and forever.

Some time ago, models used to take a widely variable time to complete a task, ususally between ten seconds and ten minutes. This kept me glued to the screen, mostly just waiting for it to be done. Then I got the idea to tell Claude that when it’s done, it should print a big “DONE” banner so I can see it from the other side of the room. I ended up collecting several different versions of this banner as they came out of the model.
██████ ██████ ███ ██ ███████
██ ██ ██ ██ ████ ██ ██
██ ██ ██ ██ ██ ██ ██ █████
██ ██ ██ ██ ██ ██ ██ ██
██████ ██████ ██ ████ ████████████ ██████ ███ ██ ███████
██ ██ ██ ██ ██ ██ ██
██ ██ ██ ██ ██ ██ ██ █████
██ ██ ██ ██ ██ ██ ██ ██
█████ ██████ ██ ████ ████████████ ██████ ███ ██ ███████
█ ██ ██ ██ ██ ██ ██
█ ██ ██ ██ ██ ██ ██ █████
█ ██ ██ ██ ██ ██ ██ ██
████ ██████ ██ ████ ████████████ ██████ ███ ██ ███████
██ ██ ██ ██ ███ ██ ██
██ ██ ██ ██ ██ ██ ██ █████
██ ██ ██ ██ ██ ██ ██ ██
█████ ██████ ██ ████ ████████████ ██████ ███ ██ ███████
██ ██ ██ ██ ██ ██ ██
██ ██ ██ ██ ██ ██ ██ █████
██ ██ ██ ██ ██ ██ ██ ██
█████ ██████ ██ ████ ████████████ ██████ █ █ █████
█ █ █ █ ██ █ █
█ █ █ █ █ █ █ █████
█ █ █ █ █ █ █ █████
█ █ █ █ █ █ █ █
█████ ██████ █ █ ██████████ ██████ █ █ █████
█ █ █ █ ██ █ █
█ █ █ █ █ █ █ █████
█ █ █ █ █ █ █ █
█ █ █ █ █ ██ █
█████ ██████ █ █ ██████████ █████ █ █ █████
█ █ █ █ ██ █ █
█ █ █ █ █ █ █ ████
█ █ █ █ █ ██ █
█████ █████ █ █ ██████████ ████ █ █ █████
█ █ █ █ ██ █ █
█ █ █ █ █ █ █ ███
█ █ █ █ █ ██ █
█████ ████ █ █ █████████ ████ █ █ █████
█ █ █ █ ██ █ █
█ █ █ █ █ █ █ ███
█ █ █ █ █ ██ █
████ ████ █ █ █████████ ████ █ █ █████
█ █ █ █ ██ █ █
█ █ █ █ █ █ █ ███
█ █ █ █ █ ██ █
████ ████ █ █ ████████ ███ ██ █ █ ████
█ █ █ █ █ █ ██ █
█ █ █ █ █ █ ██ ███
█ █ █ █ █ █ █ █ █
███ ███ █ █ █ █ ████
The ADSP-21569, as demonstrated on the EV-21569-SOM and EV-SOMCRR-EZLITE boards, appears to be optimized for streaming lots of audio channels. What if we instead need to stream fewer channels at faster sample rates? In this article, we will try out several possible pathways.
The first step after “blink” works is to have a debug input/output and UART is always the easiest. Of course we already had to set it out previously to enable automated agentic code development and testing.
We can test mass data ingestion without any additional wiring via the QSPI
interface, since the EZLITE board includes a USB-to-SPI adapter
FT4222HQ-D-T. (Make sure to follow the QSPI setup instructions in the
previous article to make sure that
FT4222-as-master works.)
With DSP in slave mode, we can write a little test program that ingests the data using DMA into two buffers, “ping-ponging” between them: DMA writes into one buffer while we read from the other, and when the first one is full, DMA starts to write into the second one. If we process the data fast enough, this guarantees there’ll be no contention between the CPU and DMA without requiring any other synchronization.
In this case, all we are interested in is whether the data is received correctly. As a simple test, we can write a couple bytes and then read them out via UART, but then we cannot test the data transfer speed. Instead, we can tell the CPU to consume the data when DMA buffer fills up and calculate a running checksum (e.g., XOR all words into a single accumulator).
The data rates from USB into FT4222 and thence into the DSP are as shown in the table:
| Lanes | SCK | Mbps actual | Mbps theoretical | % peak |
|---|---|---|---|---|
| 1 | 10 MHz | 4.4 | 10 | 44 % |
| 1 | 20 MHz | 5.8 | 20 | 29 % |
| 1 | 40 MHz | 6.8 | 40 | 17 % |
| 2 | 10 MHz | 16.1 | 20 | 81 % |
| 2 | 20 MHz | 27.1 | 40 | 68 % |
| 2 | 40 MHz | 40.7 | 80 | 51 % |
| 4 | 10 MHz | 27.1 | 40 | 68 % |
| 4 | 20 MHz | 41.1 | 80 | 51 % |
| 4 | 40 MHz | 53.9 | 160 | 34 % |
“Up to 53.8Mbps data transfer rate in SPI master with quad mode transfer” says the bullet point on FT4222 datasheet front page. Later on, in Table 4.1 on page 11, the “Max Throughput” is stated as 52.8Mbps. “It also depends on the USB bus transfer condition.”
The quad-lane theoretical maximum takes into account that at most 64K bytes can be transmitted at once, the clock rate is 40 MHz, and there’s an extra 6.65 ms (or is it 6.47 ms?) of library/USB overhead.
Using SPI2 in the 1-lane mode (regular four-wire SPI), the transfer works as
expected. In Python, simply import ft4222 and then make use of the
spiMaster_SingleWrite() function to write the data.
The dual and quad SPI modes, however, are more tricky. First of all, the
spiMaster_SingleWrite() refuses to send data outside the single-lane mode.
The library provides spiMaster_MultiReadWrite() which does transmit data but
sometimes all but the first byte is transmitted incorrectly: the bit
corresponding to D1 stays stuck at 0.
There’s a hint in the “User Guide for LibFT4222” (FTDI App Note AN_329), in a
section on using the FT4222 in slave mode:
For some reasons, support lib will append a dummy byte (0x00) at the first byte automatically.
We’re using the FT4222 in master mode, but it seems that the library author knew something that the app note writer did not: the chip has a quirk, or perhaps an undocumented in-band command depending on the contents of the first byte transmitted.
For example, if the first word transmitted is 0x0d4416c4, then all subsequent data will be corrupted. However, many other first words do not trigger the bug (e.g. 0x00000000, 0xFFFFFFFF, 0xc8ad14e5).
The workaround is as indicated in the above quote: always send 0x00 as the first byte. Annoying, but irrelevant in this instance since all we care about is to measure what is the maximum reliable data rate.
I have not been able to find this bug documented either in the datasheet or in
the Technical Note TN_161, “FT4222H Errata”.
Getting the data output of the DSP is just a little bit more tricky. We do not want to switch the FT4222 into slave mode, because then we need to physically move the S5 jumper on the EZLITE board, which would be annoying to automate. Moreover, the FT4222 only supports the single-bit data transfer in slave mode, while the master supports all three bit widths, both data directions.
Some of the tests in the future will require wiring SPI and SPORT ports between each other as “external loopback”. To verify wiring continuity, it is helpful to set up a GPIO example code that verifies which pins are connected to which pins.
On the EZLITE board, connector P13 breaks out the DAI pins that are used for the SPORT interface. Note that the pins’ presence on the board does not mean they are connected to anything! (They may be used with other SOM boards.)
| P13 pin | P13 signal | Notes |
|---|---|---|
| 7 | DAI0_PIN13 | absent both packages |
| 9 | DAI0_PIN14 | absent both packages |
| 19 | DAI0_PIN15 | absent both packages |
| 21 | DAI0_PIN16 | absent both packages |
| 31 | DAI0_PIN17 | absent both packages |
| 33 | DAI0_PIN18 | absent both packages |
| 2 | DAI1_PIN01 | |
| 4 | DAI1_PIN02 | |
| 6 | DAI1_PIN03 | |
| 8 | DAI1_PIN04 | |
| 10 | DAI1_PIN05 | |
| 12 | DAI1_PIN06 | |
| 14 | DAI1_PIN07 | |
| 16 | DAI1_PIN08 | |
| 18 | DAI1_PIN09 | |
| 20 | DAI1_PIN10 | |
| 22 | DAI1_PIN11 | absent 120-lead LQFP |
| 24 | DAI1_PIN12 | absent 120-lead LQFP |
| 26 | DAI1_PIN13 | absent both packages |
| 28 | DAI1_PIN14 | absent both packages |
| 30 | DAI1_PIN15 | absent both packages |
| 32 | DAI1_PIN16 | absent both packages |
| 34 | DAI1_PIN17 | absent both packages |
| 36 | DAI1_PIN18 | absent both packages |
| 38 | DAI1_PIN19 | |
| 40 | DAI1_PIN20 |
On the P14 header, we get access to the I2C and two SPI ports. These are highly
multiplexed. For example, the PA_06 and PA_07 are UART0_TX and UART0_RX,
respectively.
| P14 pin | P14 signal | P14 function | Multiplexed |
|---|---|---|---|
| 25 | PA_14 | TWI2_SCL | Fn 0 |
| 27 | PA_15 | TWI2_SDA | Fn 0 |
| 2 | PA_06 | SPI0_CLK | Fn 0 |
| 4 | PA_07 | SPI0_MISO | Fn 0 |
| 6 | PA_08 | SPI0_MOSI | Fn 0 |
| 8 | PA_09 | SPI0_SSB | Input Tap |
| 10 | PB_05 | SPI0_SEL2* | Fn 2 |
| 12 | PA_10 | SPI1_CLK | Fn 1 |
| 14 | PA_11 | SPI1_MISO | Fn 1 |
| 16 | PA_12 | SPI1_MOSI | Fn 1 |
| 18 | PA_13 | SPI1_SEL1* | Fn 1 |
| 20 | PB_10 | SPI1_SEL2* | Fn 1 |

Consciously, I can only focus on one thing at a time, and hold only a few in working memory. But the unconscious part of the psyche can hold a tremendous amount of memories, skills, goals, and intentions.
When a lot needs to be done, it’s best to banish it all from the conscious mind and merely set unconscious intentions, then let things arise one by one as appropriate until the goal is achieved. Holding awareness of multiple tasks is like carrying ten full cups of tea: I’d get nowhere or spill them all.
By trusting your unconscious, you free your conscious attention for the one action in front of you.