10/20/2015 at 16:31 •
Technology has this weird way of messing with you ! You expect something dumb to be easy and you find out it's the contrary...
Board One of this project is a manual/user bus controller : a HEX keypad lets you enter data and a few rows of hexadecimal 7 segment digits show the results. That is so DUMB that I was shocked it couldn't be made out of dirt-cheap, easy-to-use SOIC chips, like "one chip per digit" to keep timings and routing simple.
To be fair, you can find CD4511 in SOIC for $0.1.
Some 74xx4X chips work similarly and are covered extensively on web tutorials. But they are "BCD" converters, not "binary" or "hexadecimal". So this is the mess you get :
You can probably find hexadecimal-compatible drivers : DM9368 or another hard-to-find vintage DIP driver, that consumes space, money and current.
Let me put this in perspective : the boards will use SMD devices on flexible Kapton PCB, should be pretty compact, cheap and energy-conscious (because one board is nice but the power budget could be largely exceeded when all the boards run together, I hope it to run off a USB port...).
The first board will have at least 15 hex digits, and more if possible !
- 1 digit : SND address
- 4 digits : SND data
- 1 digit : SI4 address
- 4 digits : SI4 data
- 1 digit : Result address
- 4 digits : Result data
If possible :
- 4 digits for PC address
- 4 digits for NPC address
- 4 digits for current instruction
Did I mention that I couldn't find ultra-flat LED 7-segments displays ? Should I use 0603 SMD LEDs ? (They cost 10$ for 1Kpc so it's in the project's spirit, "a ton of dirt cheap parts to do fun things" and they can be driven by a HT1632 matrix controller)
I don't want to have to use a microcontroller but it looks like it is a necessary evil :-( I can't use a fistful of TIL311, they are expensive, obsolete, through-hole, power-hungry, thick and large...
A MCU will also solve the issue of timings, keypad input, sending the keypad data to the right output... But it will spoil the magic of not needing ANY program to drive/run the rest of the boards :-/
Edit (2016) : solved ;-) see #DYPLED
10/20/2015 at 19:12 •
Now that I look at it, it feels oddly familiar... https://en.wikipedia.org/wiki/Apollo_Guidance_Computer ?
Several HEX 7 segments displays show the current values on the busses and the current state of the processor.
Some values can be changed :
- press on the corresponding "select" button
- input the desired value on the hex keypad (the decimal dot will show which digit is about to change)
- press the "valid" button to update the value
- you can abort by re-selecting, or selecting a different field instead of validating.
You can examine the processor's contents by changing the address fields of SI4 and SND. The 16 listed registers can have side-effects.
"jump" to a given address :
- Select Result address, enter value 0 (PC), valid
- select Result value, enter the jump destination address, valid
"Read memory" in one memory bank :
- Select Result address, enter 6 (A1, bank 1 address register), valid
- Select Result value, enter memory address, valid
- Select SI4 address, enter 7 (D1, bank 1 data register), valid
- Read the hex value in the SI4 data field
"Write memory" is similar :
- Select Result address, enter 6 (A1, bank 1 address register), valid
- Select Result value, enter memory address, valid
- Select Result address, enter 7 (D1, bank 1 data register), valid
- Select Result value, enter de data to write, valid
Condition flags are still missing. There should be enough surface on the 200x160mm board for them as well as condition status.
Instruction execution can be controlled and examined with the instruction field and address displays, as well as a few buttons (reset, start, pause, step).
My initial goal to have one cheap 7-segments driver IC per digit is shattered.
The display will be multiplexed, probably with something like a HTC1632C driver chip, through SPI.
Some "intelligent chip" is required to manage the buttons, the digital inputs and outputs, and the display.
At least 26 buttons are required. A capacitive sensor would be ideal but I have no idea how to implement it reliably. The task could be relegated to a secondary MCU.
Data must be read from the busses and sent back. It's not possible to attach a 4->7 converter to all the digits so the data must be multiplexed somehow.
An internal 8-bits bus can poll the signals off the 74HC245 that spy on the bus. Two hex digits can be converted to 7 segments each time, the segment data are fed to the matrix in real time.
I need to refine this first draft, which has several shortcomings, stay tuned for the version 2.
10/20/2015 at 19:59 •
(Obsolete but interesting anyway)
The second board is the simplest and the illustration of many of the principles of this project.
Here is a more-or-less 1:1 scale layout :
It's "simply" a bunch (20) of 74HC573 8-bits D-FlipFlops.
In the YASEP architecture, registers R1 to R5 are "simple", just like in most RISC designs. They have no side effect : they can be read and overwritten like any memory cell.
They are "materialised" by these 8-bits SOIC chips and provide a physical sense of where data reside.
Each register is 16-bits wide so 2 SOIC chips are required per read bus.
There are 2 read busses (SI4 and SND) so the chips are duplicated (the data are stored redundantly). This is actually a compromise to reduce chip count. Each SOIC chip will drive its read bus only when selected, its output remains in high impedance otherwise. Other methods of 2reads-1write would instead use 1 DFF chip and 2 multiplexing chip (either a 8->1 MUX or a 74HC245).
A normal MUX is the preferred method for high-speed designs but the YASEP's register set is not homogenous and it would make the board too complex.
Three 74HC138 select one of the 5 registers for read and write. Outputs 0, 6 and 7 are left open on this board but other boards (memory) use them.
10/20/2015 at 23:07 •
The first description of the first board gave the intended functions (data entry and display) but suffers from several problems. The most obvious is that it is too complex and it stems, I found, from mixing data input with display.
When these functions are separated, things become easier and clearer. So we'll have a second board ("page 1A") on the left, that is dedicated to data entry, and the data display ("page 1B") is on the right.
The display system is considerably simplified. It's just a matrix display, the inputs are constantly scanned, byte per byte, 8 bits are translated to 2x7 segments during each cycle and there is no button to make it more complex.
The matrix approach reduces the current in the LEDs so they draw less power. Further power saving is possible by turning off the digits that display leading 0s. The required logic is manageable, though I might have to use some basic programmable logic here and there, to keep cost and complexity low. SOIC versions of 74HC families are often more expensive than some tiny FPGAs or a PIC...
The other cool consequence of this better, split structure is that the scan of the bus can also be used to send data for remote monitoring. There is an internal bus of 8 bits that gets consecutive values from here and there, these values can be sent to a UART (or USB converter).
The "Page 1B" display is made of 3 parts :
- the input bus latch&scan logic, that selects consecutive bytes
- the UART that receives the stream of bytes from the bus and serialises them to the host computer
- the matrix control that converts to 7 segments, removes leading 0s and drives the columns and lines.
Those parts can work with the same clock, possibly a UART clock. Delays between scans can be inserted to reduce the display luminosity. 500 to 1000 scans per second are desired to avoid visual fatigue and keep the host computer up to date of the processor state.
To increase the turn-on ratio of the LEDs, bytes from the scan bus are grouped into 16-bits words to provide a 1/8 duty cycle instead of 1/16. Only two 7-segment decoding chips are needed. This makes the leading zero detection a bit simpler too. 74HC573 are cheap when sourced by the 1000s.
With a 115200bps serial rate, the interface can send 11520 bytes per second (1 start, 8 data, 1 stop). When transmitting 16-bytes packets, 720 packets can be sent every second.
115200Hz is obtained with a 1.8432MHz oscillator divided by 2^4=16. Since we also need to scan the keys and LEDs, a further ÷16 counter/divider is required. This is the perfect job for a CD4060.
We have overlooked the start and stop bits. At the same time, I have a whole lot of 3.6864MHz crystals. A 74HC165D shift register can load the byte from the bus and serialise it to the output at the desired frequency, to emulate a UART. But the CD4060's missing "Output n°10" is sorely missing, a CD4040 comes to the rescue.
The CD4040 doesn't have an integrated crystal oscillator but it fits perfectly. From out point of view, it provides two cascaded 4-bits counters that we use in several parts on this "page".
The slowest counter/nibble provides 4 wires to scan the keyboard and the bus, 900 times per second.
The 16 bytes need 7200 bytes per second. This is multiplied by 16 again and sent to a shift register, so we can send bytes faster than they are scanned from the input bus :
The circuit has not been tested but this is how it should work :
(Correction : the 7200 should be ANDed too, no ?)
The data entry "page" is split into 4 parts :
- Bus buffer/driver
The UART can also receive commands from the host. Those commands should be in the same format as the user's input on the keypad, to keep the complexity low.
Thus the rest of the input logic can receive byte streams that must be interpreted, the source is not differentiated - the commands are simply ORed.
Some commands are "data" commands : the input of a hex digit. The data nibble is sent to a sort of FIFO of 4 nibbles, to queue the values (MSB first).
The other commands trigger a "transfer" of the FIFO's contents to another register and/or the bus output, which can trigger bus activity.
Side effects and commands will also include a FIFO clear and a serial dump during the next display scan cycle. Pointer auto-increment should be handled too... I keep some free room for later.
The host sends commands as a stream of individual bytes (which is perfect for a serial port). The "data" and "action" commands are made of two nibbles. The lower nibble is actual data (the hex nibble sent to the FIFO, or the number of the register to write).
low nibble high nibble Data packet hex data 0x1 Command Reg. number 0x2
Higher bits might be used as "options" for the commands, such as enabling auto-inc of pointers, I have "reserved" the remaining MSB for now.
A host computer will control the system by sending a stream of 0x1? and 0x2? bytes. For example, to load the value 0xABCD in the regiser R2:
12 ; register 2 22 ; write FIFO to ARES 1A ; fill the FIFO with ABCD 1B 1C 1D 23 ; write FIFO to DRESThis sequence of bytes is the same as a user would type on the board. See below "User Interface".
The keyboard scan logic shares some signals with the display's logic and work at the same speed to avoid redundancy. I have not figured out everything yet...
The new system saves the press of the "valid" key so it is a bit more convenient as well. The order of the commands is a bit modified though :
- Input 1 to 4 hex digits on the keypad
- Press one of the command keys to send the data from the FIFO to the specified bus.
To read a normal register:
- Input the register's address on the keypad (1 digit)
- Press the ASI4 or ASND key
- The value appears on the corresponding LED display on page 1B.
To write a value to a register:
- Input the destination register's address on the keypad (1 digit)
- Press the ARES key
- Input the register's new value on the keypad (1 to 4 digits)
- Press the DRES key
(both values should be displayed on page 1B)
10/21/2015 at 01:36 •
Page 1A has a sort of FIFO, actually a shift register, that I'm happy I solved with a reduced component count :-)
The FIFO accepts 4 input bits and queues them until another command latches them in a different buffer on the main bus.
The input nibble (that comes from the keypad or the UART) is latched by the lower half of a 74HC273. The higher half's input comes from the lower half. This is chained further into a second '273.
Each latched nibble is sent to an individual TIL311 hexadecimal display. It's a bit expensive but
- it does not need external parts (ie for decoding)
- only 4 are needed
- it adds a classy retro touch
- I got a nice deal on eBay
- the digits are pretty, clear and look cool !
The "not-7-segment-y" look won my heart. However these modules draw quite some power (it's vintage 1972 technology, 60mA for the decoding logic plus as much for the LEDs !) and some logic is required to disable leading 0s. A 5-inputs OR and a 3rd '273 should do the trick. The three '273 will get cleared (low pulse) when a command is sent (tbd).
More power might be saved, maybe by synching the digits' output enables with the keyboard scan, so only one TIL311 is turned on at a time. Cost : 4 AND2.
I have not found a use for the 2 decimal points so far.
Except for the TIL311, all parts are fixed-function, surface-mounted, low-profile and low power, so the design goals are reached for this part.
10/21/2015 at 18:36 •
Some of the boards need a 3.6864MHz source. This frequency must be magic because I often end up using it !
For another project, I gathered all the parts (in ample quantity) that make a discrete oscillator :
- 20pf cap
- 6-20pf adjustable cap
- 1M Ohms feedback resistor
- Fairchild NC7ST04 inverter gate
- Abracom 3.6864 MHz Xtal
This project does not need an extremely accurate clock, asynchronous serial links can accept up to 1% drift, so the adjustable cap is not used here. I'll just make sure it oscillates in the expected frequency range, determined by my not so sophisticated tools' precision.
The NC7ST04 is similar to HCMOS and draws less than 10µA (1µA typical) so it's "low power" though it is rated for 5V supplies. Will it still work at 3.3V ?
I'll use the standard Pierce topology https://en.wikipedia.org/wiki/Pierce_oscillator with help from Fairchild's application note www.fairchildsemi.com/an/AN/AN-340.pdf A tl;dr version is also found at http://www.z80.info/uexosc.htm
(Note: I should probably have used a HCU part instead, such as TI's special single-gates with 2 outputs, however I have to adapt to "eBay luck": I got a whole reel of this low-power inverter for a very good price so it's like I have a lifetime supply of this part for a marginal cost, unlike TI's more expensive parts)
My bias resistor is 1M instead of the Fairchild-recommended 10M but the above picture says it's not important (it might just increase the startup time, I suppose).
The series resistor would be in the 10K Ohms range, since the following design uses an unbuffered gate, R2 can be increased (this further shields the loop from external capacitances and transients).
So Rf=1M, R2=24K, Ca=Cb=20pf... Let's see how it works in practice :-)
The parts are not very visible but they are all there :
The oscilloscope shows that it works but the waveform should not be considered accurate (lousy probes, lousy scope bandwidth...)
Some measurements :
- The circuit resonates (catches the fundamental) at around 1.8V (2V is safe).
- My crude frequency meter says "3.69MH" so it is well in the 1% ballpark.
- Current @3.3V : 1.6mA, 5V: 2.6mA (10× better than more expensive canned oscillators)
Conclusion : success !
Bonus points : cheap, no black box, surface mount, easy sourcing of the parts...
I added a couple of buffers to totally decouple the ocillator and keep it undisturbed. More buffers might be added if/when needed, probably one per board.
It seems that the output resistor R2 is too high, or something like that. I reduced it to 200 Ohms to get a half-decent waveform. I don't know if it's my 'scope or my probes or the resistors ?
OK it was the probe. It turns out, X10 mode gives a much better waveform. 2K2 is fine as long as the output is very lightly loaded.
This little experience shows again that clock buffers are really required. Given the higher value of R3, R2 might even be useless if the buffers are less than one cm away.
By the way here is the circuit before I soldered the supplies and the quartz.
10/22/2015 at 01:15 •
October 22nd (2015), the project is on track :-)
In 2016 I expect to prototype the 3 "pages" that I have already presented (1A, 1B and 2). The 3 memory pages should follow, they are very similar, though the up/down increment will be another challenge. I'll test the schematics and parts on prototype boards before doing the kapton layout and fabrication.
The clock and the 7 segments display questions are solved. However other questions remain unanswered... I'm not sure yet how I will implement the keypad.
Another burning question : how do I implement some of the arbitrary logic with cheap and surface-mount devices ?
The original idea was to use DIP devices, diodes and other discrete stuff, I would use E(E)PROMs for logic blocks... Now, even something as simple as the lookup table of the 7 segments LED display is a headache !
Aren't there SOIC PALs ? (22V10 are in DIP AFAIK) Lattice has some interesting products (TQFP, low price, 3.3V compatible, ...) but isn't it overkill for the LED decoding application ?
ATF16V8 and ATF22V10 are available in PLCC20 and PLCC28 but I don't have any software or programming adapter (what's the protocol by the way ?)
What other solutions are out there ?
10/22/2015 at 04:28 •
(Note: Interesting read but superseded)
(note 2, 20151030 : a similar idea is implemented at http://josephknowles.com/2014/10/09/z-80-homebrew-io-board/ but with a 16->1 multiplexer)
It does not seem reasonable to implement capacitive keys (yet).
I have to stick to dumb logic and smart ideas.
There are not many keys so the required logic will not be too hard. There is the hex keypad and the command keys, overall 32 keys or less. It does not seem necessary to use an array for the scan, particularly because the "priority encoder" logic could become tricky. (Update: later, I found the 74HC148 priority encoder in a local store...)
Fortunately the user interface does not need simultaneous key presses. The keys count could even be lowered if the "command" keys are "folded" into or "shared" with the hex keys. But I'm not making one of those electronic music instruments with weird "modes" and hidden/obscure combinations to access menus... I know that some love minimalism like #Unhappy Hacking Keyboard but I can live with more keys, the more the better. Where is the "homebrew appeal" or the "physical computing charm" otherwise ? Give me keys !
So the challenge is to 1) scan all the keys 2) provide a reliable information when more than one key is pressed 3) get the timings right.
The starting point is the scan of the keys. We can use the running counters from the display board's CD4040 or even generate a local lower frequency with another one (so there is only one signal to send from P1B to P1A).
OK now we have a 5-bits free-running counter that wraps around at least 100 times per second. The output goes to several 74HC138, each output is connected to a single key. The 3->8 decoders can be scattered across the PCB, we are not constrained by the geometry of an array.
The 74HC138 outputs are normally held high. One output goes low at a time. So when the four 74HC138 are connected to the 5-bits counter, all the outputs will go low in sequence, one after another.
Then the main "trick" is to make a big "wired OR" circuit with all the outputs. Each output is followed by a diode in series with one of the keys. The other terminal of all the keys is connected to a common "sense" signal, pulled-up by a 10K resistor.
- When no key is pressed, each decoder output is pulsed low but there is no connection, the circuit is broken by all the open keys. Nothing happens.
- When a key is pressed, there is a connection between the driving decoder and the common signal. Most of the time, the decoder's output is high, while the common signal is pulled high, so nothing happens. But when the 138's output is pulled low, current can start flowing through the diode and the common signal goes low (actually, about 0.8V, if we count the output impedance and the diode forward voltage).
- When more than one key is pressed, the diodes prevent shorting the decoders outputs when one of the keys is selected (there would be a direct connection between high and low logic levels).
Now we get a low pulse on the common signal, each time a key is pressed and it is being probed. The next step is to sample this signal.
The common signal is combined with the input frequency to create a rising edge in the middle of the current cycle, so the counter's value can be stored in a 74HC273. This value is updated each time a pressed key is probed so the '273 could oscillate between two or more values.
The priority encoder is implemented by sampling the '273 at the end of a scan cycle. If several keys are pressed simultaneously, only the key with the highest scan code will be considered.
A more compact version is possible if the scan counter's clock can be inhibited (let's indulge in clock-gating). The CD4040's clock input is ANDed with the pulled-up common signal:
- When no key is pressed, the counter roams freely.
- When the count reaches the position of the pressed key, the common signal is pulled low, the AND stays low, which inhibits the counter's clock. The counter's value is frozen as long as this key is held down.
Prioritisation of the scan code is inherent and "first press first serve". The code is send on press, not release.
The other hidden advantage is the ease of implementing a debounce circuit: a simple capacitor (10µF alu ?) between the common signal and 0V, to delay the rising edge. The common signal should be buffered with a Schmitt Trigger circuit to prevent parasites. The output of this buffer can then send a strobe to the other circuits, telling them to sample the counter's value.
It's not very complex :-) The only drawback is we can't use this easily to control the TIL311's blanking to reduce the current and luminosity.
PS: I just found 20years old scraps from an even older keyboard that I completely took apart (I think I wanted to make a MC6809 SBC as a teen). The keys are bulky but they contain a diode ! The first prototype will be awesome and clicky :-D
10/22/2015 at 18:26 •
This project is a crazy goofball but there is one major problem : it is expensive (and potentially fragile).
How can I fulfill the educational purpose if only "a select few" can afford it ?
Honestly, there are small and cheap FPGA discovery boards, and people can get microcontrollers for a few coins these days. But it misses the point of having a living anatomical chart under your eyes, with which you can interact
There is yet another problem I face. Some people would like to play with it and provide feedback but I have no physical demo yet and I can't send several units across the world. And what if I want to update the unit that is already sent ?
The answer is simple: create a software version that can run on people's computers. Obviously, it will be written with HTML5, just like the YASEP framework, and both should be able to interact ;-)
So I just created a subdomain : http://discrete.yasep.org/
10/22/2015 at 21:07 •
Guys, this post is going to be fun. Like, a lot of fun.
If you have read the past logs you know that I include a UART interface for input-output with a host computer. This host can contain software to assemble or disassemble code, and whatever fancy softwary stuff you dare program.
But what if (what if ?) you could actually directly send commands to the board without a fancy software package that runs a GUI in your browser ? Who has the time to develop a GUI these days anyway ?
The word for the magic feature is "console".
Let's look at the setup:
- The Discrete YASEP is complete and working
- It provides an asynchronous seria port (115200bps)
- The serial port is connected to a USB-serial converter dongle
- That USB dongle is connected to your POSIX compatible computer, hopefully loaded with basic GNU packages.
- You open a terminal with a bash shell and can send and receive data through /dev/ttyS0 for example.
Now it becomes easy to control the board with a few keystrokes, just type "cat > /dev/ttyS0" !
But what keystrokes ?
ASCII codes for letter 0 to 9 map to 0x30-0x39 so we can directly extract the lower nibble but the letters A to F map to something totally different ! Why don't I code in octal, why ?
From here, I see where this could be going to : write software. But wait! If you got POSIX, you got tr !
[yg@localhost]$ man tr NAME tr - translate or delete characters SYNOPSIS tr [OPTION]... SET1 [SET2] DESCRIPTION Translate, squeeze, and/or delete characters from standard input, writing to standard output.Why write a program when you can use an existing filter ?
[yg@localhost]$ tr a-z A-z plop PLOP
The rest is pretty easy!
[yg@localhost]$ tr A-Fa-f '\072\073\074\075\076\077\072\073\074\075\076\077' |od -w1 -t x1 0123456789ABCDEF 0123456789abcdef 0000000 30 0000001 31 0000002 32 0000003 33 ... 0000010 38 0000011 39 0000012 3a 0000013 3b 0000014 3c 0000015 3d 0000016 3e 0000017 3f <-- yay ! 0000020 0a <-- new line 0000021 30 0000022 31 ... 0000031 38 0000032 39 0000033 3a <-- yay again ! 0000034 3b 0000035 3c 0000036 3d 0000037 3e 0000040 3f 0000041 0aThis can be saved as a script that you can invoke to send data to the board.
[yg@localhost]$ tr.sh > /dev/ttyS0 1234w 4WThis sends the value 0x1234 to the register R4. This supposes that
- 'w' is mapped to writing to the result data bus
- 'W' maps to writing the result bus address (and triggering a bus cycle)
- 'r' writes the register address of SI4
- 'R' writes the register address of SND
Unrecognised characters are discarded or ignored by the board. This is important because the terminal buffers lines, so you have to press the ENTER key to send the line over to the serial port.
Then you can save all these commands, copy, paste, translate, sed, hawk, python, perl, and maybe, at a higher level, interface with GDB ?...
This also removes the need to record keystrokes directly on the board for the purpose of replaying them later.