-
BLANK
03/18/2018 at 12:02 • 0 commentsThe PROM has 1 extra input pin and 1 extra output pin. There is one clever way to use it !
- Extra Input Pin : BLANK if input number is 0
- Extra Output Pin : active if input number is 0
This way, the decoders can be chained and leading 0s can be blank'ed.
A simple switch tied to the MSB will select if leading 0s are blank'ed. Just like #DYPLED !
-
Firing up an old PROM Programmer
08/21/2017 at 15:06 • 1 commentGuest Post
This is a guest post for Yann.
Firing up an old PROM Programmer
I built a PROM Programmer for my Weird CPU a year or two ago:
My PROMs were the 74S571 rather than the 74188 that Yann is consisdering, but really that is not material for this post.
Programming Guides
I have looked at the programming guides for the various PROMs, although the programming guides are sometimes quite different (surprising!), I feel safe to say that if the PROM technology is the same and the programming voltage is the same, then the programming guides would be interchangeable.
The programming guides however do suggest problems with the technology which really do need to be managed. The main one is over heating of the chip during programming cycle. The second one is the programming voltage rise time.
The main conclusion is that you should drive your PROM Programmer with an Arduino or similar if you want to follow a programming guide. Even if you don't follow the programming guide exactly you are still better off with an Arduino managing the programming cycle.
For Ti-W technology (Yann's and my device) the voltage (10.5v) pulse rise time needs to be between 1 us to 10 us (i.e. between 10V/us and 1V/us).
The nominal programming duty cycle for both devices is 25% (i.e. no more than 25%).
Generating the Voltage Pulse
The easiest way to do this is to use a 12.5v or higher voltage supply (but it must be able to supply 1A) and a voltage regulator. All that needs to be done to the voltage regulator is to adjust the feed voltage to switch the voltage. We can do this with a transistor. In order to control the voltage pulse rise time we just control feedback voltage rise time. Here is my design:
The 2k2 resistor between the power supply input and the Vccp input is designed to ensure the output voltage stays at 5v if the Vccp connection (now call VPP) is broken. The 4.7n capacitor controls the pulse rise time. The 4.7k and the 220R resistors are for fine tuning of the 10.5v voltage output. Here is the voltage pulse signal:
The pulse rise time needs to be in the order of 1 us to 10 us (check it is!).
Programming the Bits
To limit current into the PROM output, the bit programmer (yes the device is programmed one bit at a time) needs to be able to go tri-state when off. Here is my design using common transistors:
I used transistors because they can handle the current with low voltage loss. The BC328 is perfect for this application. The BC547 just needs to be high gain.
Yann asked about the 10k emittor resistor? It increases the transistor input impedance and limits the transistor current.
Sensing the output of the PROM
The final version is a little slow (~2us) but works well:
I redrew the schematic just to make things clearer:
As you can see the 74S571 is a 4 bit data word while Yann's PROM is an 8 bit data word.
Here is my strip-board design for the PROM Programmer:
Note the Arduino Pin assignments will change for the published PROM Programmer code.
The top voltage regulator is for the 5v logic, the bottom regulator is for the programming voltage pulse. The green links are for different PROM pages, as only 128 bytes are (currently) programmable at a time.
The main problems with this design is the voltage regulators get hot if the programmer is left plugged into the power supply. The second problem is the need to connect (i.e. wire up) the programmer to an Arduino each time it is used. Better is a Nano was integrated into the design.
The Programmer Code
I rewrote the PROM Programmer code. It is pretty hard to write code that has to work the first time! But this code is better. It reads the PROM code first and they you have the option to burn either the high or low nimble:
// PROM Programmer: // This code programs the LOW nibble of "ROM" data to the 74S571 PROM. // The "ROM" data is in the source code. // A factory PROM is all LOWs and the Programmer writes HIGHs on bit at a time. // The programmer has pull up resistors on VPP and /CS for safety. // After the PROM has been programmed the LED will blink slowly if successful (1s on/1s off). // If if unsuccessful the the LED will blink quickly (0.1s on/0.1s off). // // Programmer connections: // D0 <-> TX // D1 <-> RX // D2 <-> PROM A0 // D3 <-> PROM A1 // D4 <-> PROM A2 // D5 <-> PROM A3 // D6 <-> PROM A4 // D7 <-> PROM A5 // D8 <-> PROM D0 // D9 <-> PROM D1 // D10 <-> PROM D2 // D11 <-> PROM D3 // D12 <-> PROM A6 // D13 <-> D13 (LED) // A0 <-> PROM Sense D0 // A1 <-> PROM Sense D1 // A2 <-> PROM Sense D2 // A3 <-> PROM Sense D3 // A4 <-> PROM VPP (MUST STAY HIGH FOR 5V) // A5 <-> PROM /CS (ACTIVE LOW) // A6 <-> A6 (NANO ONLY - ANALOG READ ONLY) // A7 <-> A7 (NANO ONLY - ANALOG READ ONLY) // Set bytes (nibbles) to read const int bytes=128; #include <avr/pgmspace.h> // Here is the "ROM" data (only the low nibble is used) const byte PROGMEM ROM[bytes] = { 0XDD, 0XFF, 0X8D, 0X9D, 0XDD, 0X00, 0X7D, 0X8D, 0X9D, 0XA7, 0XB8, 0XC9, 0X2A, 0X3B, 0X4C, 0X0A, 0X1B, 0X00, 0X1C, 0X00, 0XDD, 0XFF, 0X1D, 0XDD, 0X0F, 0XED, 0XDD, 0X0A, 0X5D, 0XDD, 0XF9, 0X0D, 0XDD, 0XFF, 0X1D, 0X1D, 0X00, 0XDD, 0X20, 0XED, 0X05, 0X50, 0X00, 0XDD, 0X1D, 0XED, 0X07, 0X12, 0X11, 0X51, 0X02, 0X11, 0X05, 0X71, 0XA7, 0X08, 0X13, 0X11, 0X51, 0X03, 0X11, 0X05, 0X81, 0XB8, 0X09, 0X14, 0X11, 0X51, 0X04, 0X11, 0X05, 0X91, 0XC9, 0XDD, 0X09, 0XFD, 0X21, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00 }; void ReadPROM(byte bytes) { byte Data; byte Addr; // Make sure controls are set for read PORTC|= B00010000; // Set VPP HIGH PORTC&= B11010000; // Set /CS LOW and D0-3 LOW for (Addr=0;Addr<bytes;Addr++) { // Set Address PORTD=(PORTD&B00000011)|(Addr<<2); PORTB=(PORTB&B11101111)|((Addr>>2)&B00010000); delayMicroseconds(5); // Wait for data to settle (>3 us) // Read the PROM Data=PINC&B00001111; if (Addr%16==0) { Serial.println(); if (Addr==0) { Serial.print("00:"); } else { Serial.print(Addr,HEX); Serial.print(":"); } } Serial.print(" "); Serial.print(Data,HEX); delay(5); // enough time for 4 characters per loop } // Make sure controls are set to off PORTC|= B00110000; // Set VPP HIGH (5V) and /CS HIGH (deselected) } void setup() { // INITIALISE PORTS // PortC XX/VSSSS // XXCP3210 // XXSP PORTC|= B00110000; // Set VPP and /CS HIGH DDRC &= B11110000; // Set S0-3 as inputs DDRC |= B00110000; // Set VPP and /CS as outputs // Bit 76543210 // PortD AAAAAART // 543210XX DDRD |= B11111100; // Set A0-5 as outputs PORTD&= B00000011; // Set A0-5 LOW // PortB XXLADDDD // XXE63210 // XXD DDRB |= B00111111; // Set LED, A6 and D3-0 as outputs PORTB&= B11000000; // Set LED, A6 and D3-0 LOW // Set Serial Serial.begin(9600); } int Delay=1000; void loop() { byte CPort; byte Data; byte Addr; byte Nibble=0; byte BitNo; byte Pass; byte Verify; char Ans; delay(100); Serial.println("Welcome to the 74S571 PROM Programmer."); delay(100); Serial.println("Please power up the PROM Programmer now."); delay(100); // Wait for output buffer to clear Serial.print("First read the PROM (y/n)?"); // Message while (Serial.available()) Serial.read(); // Flush input buffer while (!Serial.available()); // Wait for response Ans=Serial.read(); // Get answer if ((Ans=='y')||(Ans=='Y')) { // Read PROM ReadPROM(bytes); delay(100); Serial.println(); Serial.println("PROM read done."); } else { delay(100); Serial.println(); Serial.println("PROM read aborted."); } // PROM Programmer delay(100); Serial.println(); Serial.print("Ready to program the PROM (y/n)?"); while (Serial.available()) Serial.read(); while (!Serial.available()); Ans=Serial.read(); if ((Ans=='y')||(Ans=='Y')) { delay(100); Serial.println(); Serial.print("Write high or low nimble of ROM data (h/l)?"); while (Serial.available()) Serial.read(); while (!Serial.available()); Ans=Serial.read(); if ((Ans=='H')||(Ans=='h')) Nibble=4; // Make sure controls are set off (VPP and /CS HIGH) PORTC|=B00110000; for (Addr=0;Addr<bytes;Addr++) { // Read the data to be programmed Data=pgm_read_byte(ROM+Addr); PORTD=(PORTD&B00000011)|(Addr<<2); PORTB=(PORTB&B11101111)|((Addr>>2)&B00010000); delayMicroseconds(1); for (BitNo=Nibble;BitNo<Nibble+4;BitNo++) { if (((Data>>BitNo)&B00000001)==1) { // Set Data bit PORTB=(PORTB&B11110000)|(B00000001<<(BitNo-Nibble)); delayMicroseconds(1); // Write bit cycle for (Verify=0;Verify<2;Verify++) { // Write the bit for (Pass=0;Pass<10;Pass++) { PORTC&=B11101111; // Bring up VPP to 10.5v (active low) delayMicroseconds(1); PORTC&=B11011111; // Select chip (active low) delayMicroseconds(10); PORTC|=B00100000; // Unselect chip PORTC|=B00010000; // Bring down VPP to 5v delayMicroseconds(33); // Maximum duty cycle is 25% } // Verify PORTB&=B11110000; // Set D0-3 LOW (off) PORTC&=B11011111; // Make /CS low (select) delayMicroseconds(5); // Wait for data to settle // Read the PROM CPort=PINC; if ((Data&(B00000001<<BitNo+Nibble))==(CPort&(B00000001<<BitNo+Nibble))) break; } // Post verify bit write PORTB=(PORTB&B11110000)|(B00000001<<(BitNo-Nibble)); delayMicroseconds(1); for (Pass=0;Pass<5;Pass++) { PORTC&=B11101111; // Bring up VPP to 10.5v (active low) delayMicroseconds(1); PORTC&=B11011111; // Select chip (active low) delayMicroseconds(10); PORTC|=B00100000; // Unselect chip PORTC|=B00010000; // Bring down VPP to 5v delayMicroseconds(33); // Maximum duty cycle is 25% } } } } // Check Read PROM delay(100); Serial.println(); Serial.print("Post programmed PROM read"); ReadPROM(bytes); // Make sure controls are set to off PORTC|= B00110000; // VPP HIGH (5V) and /CS HIGH (deselected) delay(100); Serial.println(); Serial.println("PROM write done."); } else { delay(100); Serial.println(); Serial.print("PROM write aborted."); } delay(100); Serial.println(); Serial.println("PROM Programmer done."); while(true) { digitalWrite(13,HIGH); delay(Delay); digitalWrite(13,LOW); delay(Delay); } }
Here are two runs changing the nimble 0x4C:
Welcome to the 74S571 PROM Programmer. Please power up the PROM Programmer now. First read the PROM (y/n)? y 00: D F D D D 0 F D D F B D A B C A 10: B 0 D 0 D F D D F F D A D D F D 20: D F D D 0 D 2 F 5 5 0 D D F 7 3 30: 1 5 2 1 5 7 F 8 3 1 5 3 1 5 9 B 40: 9 5 1 5 4 1 5 9 D D 9 F 0 0 0 0 50: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 60: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 70: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 F PROM read done. Ready to program the PROM (y/n)? y Write high or low nimble of ROM data (h/l)? l Post programmed PROM read 00: D F D D D 0 F D D F B D A B C A 10: B 0 D 0 D F D D F F D A D D F D 20: D F D D 0 D 2 F 5 5 0 D D F 7 3 30: 1 5 2 1 5 7 F 8 3 1 5 3 1 5 9 B 40: 9 5 1 5 4 1 5 9 D D 9 F 1 0 0 0 50: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 60: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 70: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 F PROM write done. PROM Programmer done. Welcome to the 74S571 PROM Programmer. Please power up the PROM Programmer now. First read the PROM (y/n)? y 00: D F D D D 0 F D D F B D A B C A 10: B 0 D 0 D F D D F F D A D D F D 20: D F D D 0 D 2 F 5 5 0 D D F 7 3 30: 1 5 2 1 5 7 F 8 3 1 5 3 1 5 9 B 40: 9 5 1 5 4 1 5 9 D D 9 F 1 0 0 0 50: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 60: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 70: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 F PROM read done. Ready to program the PROM (y/n)? y Write high or low nimble of ROM data (h/l)? h Post programmed PROM read 00: D F D D D 0 F D D F B D A B C A 10: B 0 D 0 D F D D F F D A D D F D 20: D F D D 0 D 2 F 5 5 0 D D F 7 3 30: 1 5 2 1 5 7 F 8 3 1 5 3 1 5 9 B 40: 9 5 1 5 4 1 5 9 D D 9 F 3 0 0 0 50: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 60: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 70: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 F PROM write done. PROM Programmer done.
AlanX
-
Design considerations
07/16/2017 at 21:30 • 0 comments(moved from the project description page)
Since I want to program both 74187 and 74188, I need 8 bits of input and 8 bits of output. I started with my favourite parts: a couple of hexadecimal encoding wheels and a couple of TIL311 for the address bus.
The data bus is a bit unusual : one of the data bits is shorted to 0V, so I use a 11-positions rotary switch (leftover from the #Clockwork germanium discrete clock project) to select the desired bit. For the lower nibble (in the 74187 case) I might add a TIL311 for inspection of the output but LEDs should be enough otherwise. A 7-segments module is used as well to check the output.
The fuse is blown when the power supply is raised from 5V to 10.5V. The different voltage sources are isolated by diodes so approximately 5.6V and 11.2V are required. Add to this that the TIL311 are undervolted at 3.6V... That's a few diode drops, but too close to the margins to use LM317s.
Starting from 12V, two diode drops provide about 10.6V but this is not accurately regulated and might affect the programming. A 14 or 15V input source would allow the use of a LM317 so the power supply would be a 12V unregulated "wall wart" (let's see what I have in stock).
From 10.6V down to 5.6V, another LM317 drops 5V. This is probably the one that dissipates the most power.
Then from 5.6V to 3.6V, two volts are dropped but the TIL311 power rail does not need a tight regulation so a string of 3 silicon diodes would do.
The TIL311's current is measured in the 125mA ballpark (around 60mA per module) and this is the most consuming circuit. The power drops are: 1/4W for the 2V drop and 0.7W for the 5V drop. This is significant but still in the range of the circuits made in the 80s... The good side is : this current keeps the LM317 in the regulation range. In the end, the wall wart must provide at least 200mA (probably rated at 500mA) and most of it will be turned into heat.
I found several LT1086, in fixed and adjustable versions, with are low dropout versions.Minimum load current less than 5mA, input voltage is high enough (25V max) and the dropout does not exceed 1.5V at max current. That's just enough margin for the input regulator (11V) and the TIL311 rail (5.6V to 3.6V) without weird hacks.
Let's start with the 3.6V rail : I got the regulator and I just have to add a couple of resistors to set the voltage. I find that the ratio of resistors is 2.88 so if I set one resistor to 1K Ohms, all I have to do is find a 2.88K-1K=1.9K resistor. Fortunately this is close to the standard 1.8K value, and the voltage does not need high precision. There is also a need of capacitors but that's not a critical consideration... 100uF/25V will do, I have a significant number of them in stock. Ahem.
The 1.8K and 1K resistors give about 3.59V which is pretty good :-)
This works quite well when you don't mistake a fixed with an adjustable version. And it also made me devise a little trick to calculate the resistors : just convert the volts in kiloohms :-) With a 1.2K resistor for the adjust pin, if I want 3.6V I need 3600-1200=2400 ohms. This is less reliable because of the disturbance of the adjust pin's current but we'll add a trimpot later.
For the 5.6V part I'll use a different trick that the datasheet suggests:
If we consider that 1K provides a 5V swing, 1K/5=200 ohms will provide the required 1V swing :-) That's possible though if I haven't burned the first LT1086-5 that I mistook for an adjustable version for my first attempt...
(Now I realise I could have used this trick because I have 3.3V versions and that would have saved one resistor)
With a 330 Ohms trimpot, I can vary the output from 5V to 6.8V :-) This amounts to about 180 ohms per Volt so a 1K resistor will increase the output by about 5.4V, resulting in 10.4V.
Using a 990 Ohms and the same type of 330 Ohm trimpot, I get a range of 9.6V to 11.2V, which is perfect. The 10.5V output is obtained with the trimmer at approximately half position.
For the PSU, I have a 12V 500mA AC block so a diode bridge and 2200µF 25V capacitor will do. Current draw with just the TIL311 as loads is about 120mA and the filtered input of the whole string of regulators is 14.75V. I've put dissipators on all the LT1086s because the whole thing is just sitting there, dissipating power... But hey, they are regulating well ;-)
The stage is set now, the actors (power rails) are working, now we have to make them... do something. At this point, the next circuit to design is the one that allows the PROM's Vcc to increase from 5V to 10.5V. Other circuits (see 1. References) use a diode on the Vcc rail and the 10V is pulsed either with a transistor, a relay or a push-button. To complete this circuit and ensure it works as intended, the PROM chip must close the loop (to ensure that the current is right) but it's too early yet. I don't want to burn or damage chips and I'll need a dummy load... What can resist at 10 and 5V ? A resistor but this is going to heat (even more). So I'm looking at something that heats but not too much, such as... an incandescent bulb ?
Fortunately I had already hacked a few Glühbirnchen as a 12V load. I measured the current draw : 30mA@5V and 45mA@11V, this is pretty compatible with a bipolar part :-)
The 5V diode is a basic 1N4007. No need of a larger one, but not sure a smaller package would be reliable.
Once the 5V rail is loaded through the diode, I can adjust the 5V regulator to precisely 5V. With this added load, the input voltage at the first regulator is 14.3V.
Then, how do I switch the 11V rail ? Electromechanical methods are not appropriate because I want a totally electronic control, in case I control it with a Pi later. Transistors then, P-type but Bipolar or MOSFET ?
- Bipolar might be simpler but the dropout voltage is not precise (I'd like a 100mV precision)
- MOSFET can have low losses but are not "vintage"...
I have to choose between the SI2301 and the 2N2907, but I'll give vintage (1973, 0.6A, 60V, 400mW) a chance :-)
So how do I push the 2907 hard into saturation ? With quite a lot of base current, of course. But how much is too much ? This is not indicated but one datasheet mentions Ib=50mA. That's probably almost as much as the programming current... So let's say 20mA (nice, just what a LED needs :-) )
Vce(sat) <= -0.4V at Ic=-150mA and Ib=-15mA
Vce(sat) <= -1.6V at Ic=-500mA and Ib=-50mA20mA seems to be good enough and a LED in series with Ib will show the programming status. It's the right time to find an old LED from my antiques archives ;-)
The LED drops 1.8V at 20mA, Vbe=0.6V so the LED gets to a minimal voltage 10V-0.6V-1.8=7.6V. The proper base resistor's value is 7.6/0.02=380 Ohms. 390 will do :-) => I get 20.6mA of base current with a nice, not very bright red glow.
The added load and the transistor shifts the Vpp to the range 9.40 - 10.93V with around 70mV of drop through the transistor (not bad, not bad). I'll have to 'scope the transient response...
-
First casualties
07/16/2017 at 21:08 • 0 commentsI already damaged 2 TIL311 :-(I wonder what happened but I suspect my new fancy digital lab power supply. Turning it off while the circuit is still connected could send spikes that damage the pins...
So I have to implement the power supply ASAP or I'll burn my stock of TIL311 quickly :-/
Lesson learned : TIL311 are quite fragile...
-
References
07/16/2017 at 10:57 • 0 commentsI've been lucky to find several similar circuits on the web, as well as datasheets. Here's a list for those who are as curious as me...
- I once found a page but it is now closed. Fortunately I saved the page "just in case" and here is the programmer's circuit:
I'm not sure to understand most of it but it contains some interesting ideas.
- http://www.retrotechnology.com/dri/prom_shook.html and http://www.retrotechnology.com/restore/fuse_bipolar_prom.html
Note: this schematic applies to the 82S23 which has a particular, slower programming cycle, with a 1s pulse, limited to about 65mA (hence the series resistor and the push button), as found at http://www.avrfreaks.net/forum/scheme-prom-ic-programmer :
Yup, Vpp is also applied to the data pin, not Vcc...
Note that current-limiting the Vpp node should be possible with a suitable base resistance...
- http://www.seekic.com/circuit_diagram/Amplifier_Circuit/PROM_BURNER.html (but for the similar 82(S)23 where Vpp is applied to the data pin, not just on Vcc)
- http://www.abicko.cz/clanek/serialy/5964/cislicova-technika-87.html (not very useful, unless something is hidden in the text which I don't understand)
- http://www.iva-w.org/ZXS/sinclair_zx_spectrum.htm : broken site ? Fortunately I saved the schematic :
- Another one (source forgotten, maybe from one of the above broken links ?)
- Another set of pictures I had saved but couldn't trace to the origin. I appreciate the (quite clumsy) translations :-)
(ok it's obviously a translation and redrawing of the original TI datasheet but it's still nice)
- PROMs from National Semiconductors are described in section 5 of http://bitsavers.trailing-edge.com/pdf/national/_dataBooks/1977_National_Memory_Databook.pdf
There is also the 1980 version at http://mirrors.acm.jhu.edu/bitsavers/pdf/national/_dataBooks/1980_Memory_Data_Book.pdf with the programming procedure at page 6-28 with a slightly better description