Note: there are plenty of pretty pictures below the fold
My pie-in-the-sky goal for the clock speed of this computer was originally 10 MHz. The LS series chips should be capable of 16 MHz, but that's not accounting for the poorly engineered environment of a hobbyist's breadboard computer. I figured 10 MHz would offer enough head room for the chips to cope.
As it turns out, the limiting factor is the EEPROM, which takes 150ns for the data to be valid after changing the address. If I set the address on the rising edge of the clock and read the data on the falling edge, that would be a period of 300ns or a frequency of 3⅓ MHz. While that's only one third of my original goal, it's well within the range of early personal computers (not that the performance will be remotely comparable).
So now I actually have a realistic target frequency, which likely can be pushed a dozen or two percentage points beyond spec (hello, overclocking!). Unfortunately the trusty 555 just isn't up to the task.
First of all, most sources I've read say it's only good up to about 1 MHz. But as an easily adjustable variable frequency (i.e. a single dial), the range and resolution are extremely limited.
I'm using a 1 M potentiometer right now. In order to have a usable range between, say, 0.5 Hz and 32 KHz, I have to manually switch from a 10 μF capacitor to a 10 nF. I'd need to go down another two orders of magnitude on the capacitor or up two on the resistor to reach 3⅓ MHz, and as I mentioned earlier, that would push the 555 well beyond its limits.
The adjustment resolution is similarly frustrating. Even though the potentiometer changes resistance linearly, the effect on clock rate highly non-linear. At the low speed end of the dial, a tiny movement makes a large difference in the clock speed. At the high speed end, the duty cycle changes more than the frequency.
Duty Dilligence
Speaking of the duty cycle, in order to keep the time spent on as close as possible to the time spent off, the capacitors and resistors need to be in particular ratios. To get a variable 555 timer with an even duty cycle, you would need both a potentiometer and a variable capacitor, each with an abnormally wide range.
As I mentioned in a previous post, the uneven duty cycle means the chips had to respond as if the clock was around 600-700 KHz even though the clock period was only 32 KHz. If I had a 3⅓ MHz clock with an 88% duty cycle, the chips would be seeing a pulse 18ns wide, which is equivalent to ~28 MHz with a 50% duty cycle.
As a quick fix for the duty cycle issue, I switched the inverter on the clock for a 74LS73, using one of the J/K flip-flops in toggle mode as a single-bit counter. Since it changes with each pulse rather than at each clock edge, its output will have a duty cycle as even as the 555's period. However, the period of the flip-flop's output will be half that of the 555, so I replaced the 10 nF capacitor with a 4.7 nF to maintain the frequency range I was used to.
The blue line on the oscilloscope is the output of the 555 timer. You can see how it spends significantly more time on (up) than off (down). The yellow line is the output of the flip-flop. You can see how it rises or falls every time the clock signal falls. Since I'm using a "raw" flip-flop instead of a counter chip, I have access to both the Q and Q' outputs to use as clock and inverted clock. The white and yellow LEDs are connected to them, respectively.
The Crystal Method
One of my first toy projects when I got back into electronics was a slowly shifting RGB mood light on Arduino. The LED itself is on a tiny breadboard and attached to the arduino with 3 signals and ground. I wanted to put the code on an ATTiny on the same board as the LED for a truly minimalist design. The ATTiny requires an external crystal to run at full speed, so I got a crystal assortment from 4 MHz to 25 MHz. I haven't made much progress on that project, but I do have everything I need for a stable, high frequency clock for the BFCPU.
The metal can on the left is an 8.000 MHz crystal. When it's resonating, it generates a near sine wave at that frequency, but it doesn't provide much current. The nearest chip is a 74HC04 hex inverter. As a CMOS chip, its inputs respond to voltage rather than current, but its outputs can provide a wide range of current. This allows it to act as a gateway between the crystal and the TTL chips. Since the output of the first inverter is part of the crystal feedback circuit, it runs through another inverter to actually provide the 8 MHz clock signal for the rest of the system.
The other chips on the board are all 74LS93s, the ripple-carry cousins of the '193 counters that make up most of the computer so far. These act as frequency dividers, giving me a selectable clock speed for any power of ½ of 8.000 MHz (4 MHz, 2 MHz, 1 MHz, 500 KHz, etc.), down to 0.4768 Hz, or about one cycle every two seconds. I'm only interested in a single "bit" at a time, so the ripple carry isn't going to be an issue.
The two 22 pF capacitors on the left corner of the board are part of the crystal resonator. The bypass capacitors straddling the high frequency chips from near to far are 1 nF, 4.7 nF, 10 nF, and 47nF, chosen experimentally to minimize noise on the outputs. There are also a couple of 100 nF capacitors across the power rails closer to the low frequency chips for the same purpose.
With nothing attached to the clock I was getting some pretty significant ringing in the outputs, sometimes as much as +6 V to -1.5 V peak-to-peak. It turned out to mostly be inductance from the oscilloscope probes, and pretty much disappeared when the clock was attached to other parts of the circuit.
In this shot, the long yellow lead on the left is connected to the 8 MHz output of the CMOS chip, and into the count enable circuitry of the Data Pointer and Data Register. The blue lead/oscilloscope probe is connected to the same signal.
The Data Pointer is set to count down, as you can see by the red lead going to Vcc just to the left of the blue LEDs. The yellow oscilloscope probe at the top is connected to the low order bit of the Data Pointer, which should be changing at half the period of the clock. Here's the result:
The scope is triggering on the clock signal, and you can see the measurement of 8.00029 MHz in the lower right. As expected, the first counter stage is flipping with every pulse. The edges don't quite line up because of the propagation delay in the counters and the NAND gates combining the clock with the control lines. If I had measured the clock at the counter input, the edges would be much closer. I left this running for an hour or so with "infinite persistence" and there wasn't a single glitch. So far so good for pushing the limits of my components!
One interesting thing to note is that TTL considers anything above 2 V to be a high signal. You can see here that the counter's output reaches just above 3 V, with a slight peak before switching. At lower frequencies, the voltage has some time to build further due to capacitive effects, and generally tops out around 4-4.5 V. You can see the effect of this in the previous image, where the 3 left-most LEDs are noticeably dimmer than the rest. The second bit from the left is the one switching the fastest, and is also the dimmest. You can see the same effect when I enable counting on the data register:
This isn't just an artifact of the camera or variability in LED quality or resistor value (which is also noticeable). If the switching speed were instantaneous, the LED would be spending just as much time on as it is off, so the only reason the brightness would be different is if the amount of current flowing is different. Since the resistance of the LED (plus resistor) is essentially fixed, the only way the current can be different is if the voltage is different.
Switching speed is not instantaneous, and doesn't change very much with clock speed. At high frequencies, instead of 50% on 50% off, it's more like 40% on, 40% off, 20% somewhere in the middle. This amplifies the effect of the already lower voltage.
The Data Pointer's up/down signals are now connected to the clock and control lines via NAND gates, just like the Data Register. The only buttons left are Clear signals. The Data Pointer doesn't ever load data, the load lines are all tied high.
In a couple of the pictures above you can see the beginnings of the program side. From top to bottom is the Stack Pointer, Stack RAM, Program Pointer, and Program ROM. I'm in the process of wiring up the Program Pointer to the Program ROM.
The milestone I'm shooting for next is to have a program in ROM control the Data Pointer and Data Register counters. But first I need to work the new clock design into the computer.
Part 1 (first) - Part 7 (prev) - Part 9 (next)
The other chips on the board are all 74LS93s, the ripple-carry cousins of the '193 counters that make up most of the computer so far. These act as frequency dividers, giving me a selectable clock speed for any power of ½ of 8.000 MHz (4 MHz, 2 MHz, 1 MHz, 500 KHz, etc.), down to 0.4768 Hz, or about one cycle every two seconds. I'm only interested in a single "bit" at a time, so the ripple carry isn't going to be an issue.
The two 22 pF capacitors on the left corner of the board are part of the crystal resonator. The bypass capacitors straddling the high frequency chips from near to far are 1 nF, 4.7 nF, 10 nF, and 47nF, chosen experimentally to minimize noise on the outputs. There are also a couple of 100 nF capacitors across the power rails closer to the low frequency chips for the same purpose.
With nothing attached to the clock I was getting some pretty significant ringing in the outputs, sometimes as much as +6 V to -1.5 V peak-to-peak. It turned out to mostly be inductance from the oscilloscope probes, and pretty much disappeared when the clock was attached to other parts of the circuit.
Poor 555 clock, blinking away in solitude back there |
In this shot, the long yellow lead on the left is connected to the 8 MHz output of the CMOS chip, and into the count enable circuitry of the Data Pointer and Data Register. The blue lead/oscilloscope probe is connected to the same signal.
The Data Pointer is set to count down, as you can see by the red lead going to Vcc just to the left of the blue LEDs. The yellow oscilloscope probe at the top is connected to the low order bit of the Data Pointer, which should be changing at half the period of the clock. Here's the result:
The scope is triggering on the clock signal, and you can see the measurement of 8.00029 MHz in the lower right. As expected, the first counter stage is flipping with every pulse. The edges don't quite line up because of the propagation delay in the counters and the NAND gates combining the clock with the control lines. If I had measured the clock at the counter input, the edges would be much closer. I left this running for an hour or so with "infinite persistence" and there wasn't a single glitch. So far so good for pushing the limits of my components!
One interesting thing to note is that TTL considers anything above 2 V to be a high signal. You can see here that the counter's output reaches just above 3 V, with a slight peak before switching. At lower frequencies, the voltage has some time to build further due to capacitive effects, and generally tops out around 4-4.5 V. You can see the effect of this in the previous image, where the 3 left-most LEDs are noticeably dimmer than the rest. The second bit from the left is the one switching the fastest, and is also the dimmest. You can see the same effect when I enable counting on the data register:
Switching speed is not instantaneous, and doesn't change very much with clock speed. At high frequencies, instead of 50% on 50% off, it's more like 40% on, 40% off, 20% somewhere in the middle. This amplifies the effect of the already lower voltage.
Other Updates and Plans
The Data Pointer's up/down signals are now connected to the clock and control lines via NAND gates, just like the Data Register. The only buttons left are Clear signals. The Data Pointer doesn't ever load data, the load lines are all tied high.
In a couple of the pictures above you can see the beginnings of the program side. From top to bottom is the Stack Pointer, Stack RAM, Program Pointer, and Program ROM. I'm in the process of wiring up the Program Pointer to the Program ROM.
The milestone I'm shooting for next is to have a program in ROM control the Data Pointer and Data Register counters. But first I need to work the new clock design into the computer.
Part 1 (first) - Part 7 (prev) - Part 9 (next)