Introduction
Here's a curious waveform. How do you think I did that?
At first glance it looks like the output of a DAC driven from an incrementing counter, but it's not.
Instead, I have a digital part (a CPLD), producing a simple stream of pulses, and an analogue part
that works as a 'charge pump', adding a set amount of charge to a capacitor each time one of the
control pulses arrives. There's also a reset pulse to bring the level back down close to zero.
Here's the waveform again with the control pulses from the CPLD below it.
The output changes in response to the pulses, so it is 'discrete time' in nature [like sampling], and
the steps are a fixed size [so like the quantization of digitising], yet the core of it is analogue
with not a gate in sight. Another way of thinking about it, is that it's a kind of analogue adder.
This is the circuit diagram of the analogue part that I drew before construction. The build was
similar, except that I added a 15R resistor between the MOSFET and the 68n.
When the 'step' transistor is off, the 2.2n capacitor charges via the 1k resistors to each rail. When
the transistor turns on, it lifts that end of the capacitor to the rail and the other end lifts above
the rail, turning on the second transistor and allowing the 2.2n capacitor to discharge into the 68n.
When the 'reset' waveform goes high, the MOSFET simply discharges the 68n capacitor. Obviously,
whatever is connected to the 68n capacitor needs to be a fairly high impedance or the capacitor will
just discharge via the load - the 10M 'scope probe suffices for the experiment.
This is the build on a little prototyping board [the MAX II CPLD board is underneath - it's not very
obvious, but there are headers going down to it].
CPLD Logic Design
Here is the VHDL that produces the 'step' and 'reset' waveforms. It's fairly straightforward. I chose
a basic timing interval of 10us [it doesn't want to be too fast or the capacitors won't charge and
discharge fully], so I have a prescaler that produces an enable for one clock every 10us and work from
there with a simple state machine, with three states, and a counter to count off the steps to give the
two waveforms. (Sorry I haven't quite got the hang of using _numeric and I'm still overloading the
addition with ieee.std_logic_unsigned)
--------------------------------------------------------------- --- Filename: CPLD-staircase-generator.vhd --- --- Target device: EPM240T100C5 --- --- --- --- control pulses for analogue staircase generator --- --- --- --- Jon Clift 7th November 2021 --- --- --- --------------------------------------------------------------- --- Rev Date Comments --- --- 1.0 07-Nov-21 --- --------------------------------------------------------------- library IEEE; use IEEE.std_logic_1164.all; use ieee.std_logic_arith.all; use ieee.std_logic_unsigned.all; entity CPLD_staircase_generator is port ( clk_i: in std_logic; --- input clock (50MHz osc). step_x: out std_logic; --- reset_x: out std_logic --- ); end CPLD_staircase_generator; architecture arch of CPLD_staircase_generator is constant STEP_X_STATE : std_logic_vector(1 downto 0) := "10"; constant PAUSE_X_STATE : std_logic_vector(1 downto 0) := "01"; constant RESET_X_STATE : std_logic_vector(1 downto 0) := "00"; constant NUMBER_OF_STEPS : std_logic_vector (3 downto 0):= "1001"; --- 9 steps constant STEP_INTERVAL : std_logic_vector (3 downto 0):= "1001"; --- 9 (x 10us) between step pulses signal ten_micro_en: std_logic; signal prescaler: std_logic_vector (8 downto 0) := "000000000"; signal interval_count: std_logic_vector (3 downto 0) := "0000"; signal step_count: std_logic_vector (3 downto 0) := "0000"; signal state: std_logic_vector (1 downto 0) := RESET_X_STATE; begin clocked_stuff: process (clk_i) begin if (clk_i'event and clk_i='1') then --- prescaler down to 10us period if (prescaler(8 downto 0) = "111110011") then --- if reached 499 prescaler(8 downto 0) <= "000000000"; --- reset back to zero ten_micro_en <= '1'; --- and set enable for one cycle else --- else count down prescaler <= prescaler + 1; ten_micro_en <= '0'; --- keeping enable low rest of time end if; --- state machine to generate the waveforms if (ten_micro_en = '1') then case state is when STEP_X_STATE => step_x <= '0'; reset_x <= '0'; interval_count <= STEP_INTERVAL; state <= PAUSE_X_STATE; when PAUSE_X_STATE => step_x <= '1'; reset_x <= '0'; if(interval_count = "0000") then if(step_count = "0000") then state <= RESET_X_STATE; else step_count <= step_count - 1; state <= STEP_X_STATE; end if; else interval_count <= interval_count - 1; end if; when RESET_X_STATE => step_x <= '1'; reset_x <= '1'; interval_count <= STEP_INTERVAL; step_count <= NUMBER_OF_STEPS; state <= PAUSE_X_STATE; when others => state <= RESET_X_STATE; end case; end if; end if; end process; end arch;
Inspiration
If you are interested in what my inspiration for this was, it came from this booklet published by the
British electronics company Ferranti in the mid-seventies (you can tell it's the 1970s by the groovy
fonts without capitals and the glorious orange colour: designers back in the 1960s and 1970s had a lot
of fun before the world got all corporate, safe, and bland again) to promote their E-line transistors
(ZTX... series parts, still in production, though now owned by Diodes Inc as Ferranti is long gone).
This was their version of the circuit
I turned it upside down and added the CPLD to generate the pulse stream, but other than that it's much
the same, with just a little tweaking of values.
One difference, though, is that their circuit self-resets when the capacitor voltage reaches a preset voltage.
I don't imagine there's anything you might use it for now that couldn't be done better in other ways,
but it was fun to experiment with, and switched-capacitor circuits are still relevant in some areas.
If you found this blog interesting, you might like to read some of the others I've written: jc2048-blog-index-new-version
References
[1] Application Report: E-Line Transistors. Ferranti. 1975.
Top Comments