352 Mixer

352 : Mixer

Design render

How it works

Several inverting Schmitt triggers with different thresholds are connected to an internal DAC. The voltage produced by the DAC is controlled by the digital inputs ui_in[7:0]. Each Schmitt trigger presents its state on the corresponding uo_out[3:0] pin.

Three additional free-standing inverting Schmitt triggers are available on the bidirectional pins. With these and a few external RC components, simple oscillators can be built.

How it came to be

Thanks to SwissChips sponsorship, I was able to participate in the previous IHP26a run with an 8-bit floating-point multiplier. There I used everything the OSS tools offer to squeeze a near-perfect design out of very imperfect and lazy HDL code. Great.

But for this second run, IHP26b, I wanted to go a level deeper: to the physical world. No nice zeros and ones, only the raw analoginess of CMOS technology.

The initial idea was to again build a multiplier, but one that multiplies in the physical world, i.e. produces some voltages that by nature get multiplied together and are then converted back to digital. Easy! Well, not so much. The amount of work needed to make that last bit, the ADC, work is simply too much. Sure, others have built one. But I'm chronically late and the design is due in a month.

So what else can we do? Analog tiles are not available for this run, but nothing prevents us from putting analog circuitry behind a digital facade. So we have a digitally controlled voltage source, i.e. a DAC, feeding multiple Schmitt triggers, each with a different threshold. That way we can sort of gauge the voltage produced internally.

The project name Mixer simply stands for mixed-signal and has nothing to do with the classic dual-gate MOSFET RF mixer circuit.

The inner workings

All Schmitt trigger variants are built from the same basic circuit. At its core, it is just an inverter with the classic NMOS and PMOS transistors. However, the pull-up and pull-down transistors are each split in half, and the voltage of the resulting middle node is controlled by a third transistor. Depending on the current output state, these middle nodes are pulled towards VDD or GND, which shifts the input voltage at which the inverter trips.

CMOS Schmitt trigger circuit

Magic layout of the 2v1 variant{width=60%}

The circuit was designed and simulated in Xschem and laid out in Magic VLSI. The thresholds of the Schmitt trigger depend on the gate widths and lengths of M1, M2, M4, and M5. The layout is drawn so that the other variants can be derived from this basic layout simply by stretching the fingers of the two-finger MOSFETs, i.e. increasing their gate width.

(Also: I know, I know, the PMOS side should be ~2x bigger, but here we are.)

In the end, I included four variants:

  • 1v1: all gate widths are equal
  • 2v1: gate width of M1, M2, M4, and M5 is 2x that of M3 and M6
  • 4v1: gate width of M1, M2, M4, and M5 is 4x that of M3 and M6
  • 8v1: gate width of M1, M2, M4, and M5 is 8x that of M3 and M6

How to test

Voltage-controlled Schmitt triggers

Set the internal DAC voltage via the bits DAC[7:0] (ui_in[7:0]). A value of 0b00000000 corresponds to 0 V, whereas 0b11111111 corresponds to 1.2 V. The current state (on or off) of each Schmitt trigger is visible in the trigger* bits of uo_out[3:0].

Play around and try to find the on and off threshold voltages of the four Schmitt trigger variants. One approach is to start at 0 V, sweep slowly up to 1.2 V, and then back down to 0 V, noting the changes of the trigger* bits at each step. At first, all bits should be on (because the Schmitt triggers are inverting). Then the variants 8v1, 4v1, 2v1, and finally 1v1 should turn off, in that order. On the way down, they should turn back on in the same order: 8v1 first, 1v1 last.

Note: Because the DAC is built from a resistor ladder, the internally produced voltage is very sensitive to the relative timing of the individual DAC[7:0] bits, especially the MSBs. Take great care to change all bits to the new value at the same time. If, for example, the MSB changes first and the LSBs only later, the internal voltage immediately jumps to an unintended value and only afterwards settles at the desired one. This can cause all Schmitt triggers to, well, trigger, even though their threshold voltage was never actually reached.

Expected thresholds according to the simulation models:

Voff Von
1v1 0.77 0.43
2v1 0.72 0.47
4v1 0.67 0.51
8v1 0.62 0.53

Free-standing Schmitt triggers

Three additional free-standing Schmitt triggers are available on the bidirectional pins. Use the ST*_IN pins as inputs and the ST*_OUT pins as outputs. I don't expect the internal pin mux of the TT harness to pass analog voltages to these pins, but if it does, these Schmitt triggers can be characterized very easily through it. Alternatively, a simple oscillator can be built with a few external components: connect OUT to IN through a resistor of a few kΩ and tie IN to GND through a capacitor of a few µF.

IO

#InputOutputBidirectional
0DAC[0]trigger1v1
1DAC[1]trigger2v1
2DAC[2]trigger4v1ST1v1_IN
3DAC[3]trigger8v1ST1v1_OUT
4DAC[4]ST2v1_IN
5DAC[5]ST2v1_OUT
6DAC[6]ST4v1_IN
7DAC[7]ST4v1_OUT

Chip location

Controller Mux Mux Mux Mux Mux Mux Mux Mux Mux Mux Analog Mux Mux Mux Mux Mux Mux Mux Mux tt_um_chip_rom (Chip ROM) tt_um_factory_test (Tiny Tapeout Factory Test) tt_um_ieee_LDO (LDO) tt_um_chip_ieee_analog (IEEE Bandgap Reference) tt_um_snn_voice_calculator_mauro_ciccone (snn-voice-calculator) tt_um_hx2003_delay (4 Channel - 32 Tap Programmable Delay with Delay Locked Loop Calibration) tt_um_adxl362_test (tt_um_adxl362_test) tt_um_larsnit_cfar (1D CA/GO/SO CFAR radar detector) tt_um_abeccari_swsynth (Sine Wave Synthesizer) tt_um_dpi_adexp (AdExp DPI Neuron ) tt_um_140oo041_fpu130 (FPU-130) tt_um_blonghi_uart (uart) tt_um_directsgg_mini_proceo_8bit (Mini 8-bit Processor) tt_um_umaece1982_lfsr (Low-Power LFSR-Based Test Pattern Generator) tt_um_deploy_timer (launch deployment timer) tt_um_urish_simon (Simon Says memory game) tt_um_nimelli_kinematic_wave_engine (Kinematic Wave Engine) tt_um_multi_seg_monitor (Multi Segment Monitor) tt_um_UART_TX (project) tt_um_crc8_lfsr (CRC-8 Serial LFSR) tt_um_tinynpu4 (TinyNPU4) tt_um_alu_bns (6-bit multi function ALU ( eldawly_V2) ) tt_um_echoworld424_tpv (Timing-Prediction Test Vehicle) tt_um_gyro_lockin (Laser Gyro Lock-in Readout Core) tt_um_josue_olivos_sar_adc (4-Bit Charge-Redistribution SAR ADC Controller) tt_um_flower (VGA Flower) tt_um_vperumal_l1_fabric (Scalable Banked L1 Memory Fabric for Edge AI) tt_um_preinception_top (Preinception: Simple Compute Accelerator) tt_um_italu (iTALU: Interactive Testable Arithmetic Logic Unit) tt_um_neuron (4-Input Signed Neuron / Perceptron) tt_um_4tap_mac (4-Tap Signed MAC Unit) tt_um_mac_engine (DSP MAC Engine) tt_um_crypto_led_demo (QAMER CryptoUART: Encrypted UART with LED Status) tt_um_layernorm (LayerNorm) tt_um_ez130_8t_mystery (EZ130 8T Mystery Circuit) tt_um_sent2spi (SENT Receiver with SPI Interface) tt_um_llr_hepiarisc (Hepiarisc with SPI flash) tt_um_rebeccargb_vga_pride (VGA Pride) tt_um_hasi_ising (Oscillator Ising Machine) tt_um_c061618g2 (Circuitli C061618G2) tt_um_tiny_dram_pim (Tiny Dual-Channel DRAM-PIM Controller + PU) tt_um_Tbilisi_CORDIC_Engine (Tbilisi CORDIC Engine) tt_um_rahulmascarenhas_folded_nn (Frozen ternary backbone + loadable head) tt_um_miniMAC (miniMAC_IHP26b) tt_um_rumcajs (IEEE DOORSH) tt_um_sg13g2_mystery (SG13G2 Mystery Circuit) tt_um_ULSR88 (ULSR demo) tt_um_ez130_7t_mystery (EZ130 7T Mystery Circuit) tt_um_tinyopt4 (ieee_tt_tinyopt4) tt_um_vga_example (IEEE VGA Animated Beach) tt_um_hyphen133_drone_detection (IEEE Acoustic Drone Detector) tt_um_nuatlabs_fifo_pwm (Async FIFO with CDC + PWM Peripheral) tt_um_nuatlabs_uart (8N1 UART Transceiver) tt_um_eeg_threshold_detector (IEEE Digital EEG Threshold Event Detector) tt_um_smart_traffic (Smart Traffic Light Controller) tt_um_94442024_mini_cpu (Mini 8-bit Accumulator CPU) tt_um_wokwi_475369131246576641 (IEEE_UPB_TT_1) tt_um_aion (AION) tt_um_rebeccargb_hardware_utf8 (Hardware UTF Encoder/Decoder) tt_um_rebeccargb_universal_decoder (Universal Binary to Segment Decoder) tt_um_rebeccargb_intercal_alu (INTERCAL ALU) tt_um_flappy_bird (IEEE Flappy Bird VGA Game) tt_um_oryan01_alu (ALU CASS PUCV) tt_um_S4xU4 (S4xU4) tt_um_vga_ca (Space CA) tt_um_llr_simplenpu (simple SPI flash streaming NPU) tt_um_pucv_pspwm (3LFCC PS-PWM Modulator) tt_um_yuri_fpga (Tiny FPGA) tt_um_mikailgedik_inverted_inverters (Inverted inverters) tt_um_esauqch_hamming74 (Hamming(7,4) encoder/decoder (IEEE)) tt_um_hackin7_analog_experiments (TinyAnalogExperiments) tt_um_snake (snake game) tt_um_mini_kraken (Kraken IO Subprocessor) tt_um_fabien_pio (AstraPIO) tt_um_chiplab (ChipLab) tt_um_wokwi_475490677474407425 (Tiny_Divider) tt_um_c061618g2tr (Circuitli C061618G2TR) tt_um_catalinlazar_nanopio (nanoPIO) tt_um_catalinlazar_uart_spi_i2c_bridge (UART-SPI-I2C Bridge) tt_um_enzonappi_sent_i2c (SENT to I2C bridge) tt_um_kush1434_proof (Proof) tt_um_schwallsunk_signal_discriminator (Highspeed voltage discriminator) tt_um_tiarinix_ttihp_verilog_template (8-bit educational SAP-style CPU) tt_um_vga_glyph_mode (BOOTCAMP) tt_um_GiulioGirelli_packet_processor (Configurable Low-Latency Match-Action Packet Processor) tt_um_vga_tictactoe (Tic Tac Toe) tt_um_vga_dvd_player (DVD player) tt_um_clea_katseye_rain (KATSEYE) tt_um_romd_uart_hello (UART Hello World) tt_um_vga_snake (CDM PYTHON GAME) tt_um_vga_slot_machine (tt_um_vga_slot_machine) tt_um_jet_seq8b (SEQ8 Programmable Sequencer) tt_um_kibo_leak_inspect (KIBO Leak-Inspection Target Controller (VGA)) tt_um_endless_runner (Endless Runner) tt_um_omega_infinity_kaoru (OMEGA INFINITY KAORU 3D Metal Grid Processor) tt_um_nikleberg_mixer (Mixer) tt_um_lahnb_sgdma (TinyDMA: A Descriptor-Based Dual-PSRAM Memory Mover) tt_um_gstj_lockin (Digital IQ Lock-in (IEEE)) tt_um_benpayne_ps2_decoder (PS/2 Keyboard Decoder for 68k) tt_um_cass_s_ui_neuron_lif (Neurona LIF con Aprendizaje STDP Dinamico (IEEE)) tt_um_vga_glyph_mode_CDM_Matrix (CDM Matrix) tt_um_qd39l_xor_stream (Fixed-ROM XOR Stream Engine) tt_um_conv3x3 (3x3 Clock Rate Streaming Input Convolution Engine) tt_um_mc14500b_soc_extended (MC14500B Extended 1-bit Microcontroller SoC) tt_um_vga_hypno_spiral (tt_um_vga_hypno_spiral) tt_um_mattizen_morse_tree (Morse Tree LED Decoder) tt_um_CDM (Colegio de Muntinlupa DVD-like Display) tt_um_romd_uart_loader (UART SPI RAM Loader) tt_um_TscherterJunior_stapel_geraet (stapel gerät) tt_um_das2225_dna_accel (DNA_Accel) tt_um_tinysoc (TinySoC) tt_um_barrel_shifter (Barrel Shifter) tt_um_approx_mac_coprocessor (Approximate DSP: Time-Multiplexed MAC Coprocessor) tt_um_joesagents_market_split_oracle (Market-split oracle) tt_um_mgpauly1458_ringmeter (Ring oscillator frequency meter) tt_um_pettit_prism_lite (PRISM with Risc-V (TinyQV) SoC) tt_um_workshop_cpu (IEEE Workshop Simple CPU) tt_um_algofoogle_analog_junk (Simple comparator + 2 DACs analog layout in a 1x1 tile) tt_um_lkhanh_cordic (TinyQV SoC (Dual Memory Backend)) tt_um_4x4npu (4x4NPU: Dual-Lane INT4 Neural Accelerator) tt_um_abiaselli_izh_bridge_3x2 (Izhikevich event bridge (4 contexts)) tt_um_fabulous_ihp_26b (Tiny FABulous FPGA) tt_um_zanderivo_voronoi (Four-Metric VGA Nearest-Prototype Visualizer)