From b8251d5c10b1f72ab0a2f1dfdfa1210c26876e75 Mon Sep 17 00:00:00 2001 From: Tom Nisbet Date: Mon, 24 Aug 2020 12:14:20 -0400 Subject: [PATCH] Add support for 74LS595 shift registers --- TommyPROM/Configure.h | 5 +++ TommyPROM/PromAddressDriver.cpp | 44 ++++++++++++++++---- docs/hardware.md | 71 ++++++++++++++++++++++++++++++--- docs/troubleshooting.md | 4 +- 4 files changed, 110 insertions(+), 14 deletions(-) diff --git a/TommyPROM/Configure.h b/TommyPROM/Configure.h index 73dd243..6b62360 100644 --- a/TommyPROM/Configure.h +++ b/TommyPROM/Configure.h @@ -10,6 +10,11 @@ //#define PROM_IS_27 //#define PROM_IS_8755A +// Uncomment the line below to use 74LS595 shift registers instead of the 74LS164s shown +// in the schematics. This enables extra code in PromAddressDriver.cpp to control the +// RCLK line that latches the data to the output pins. + +// #define SHIFT_REGISTER_IS_595 // Don't change anything below this comment unless you are adding support for a new device type. #if defined(PROM_IS_28C) diff --git a/TommyPROM/PromAddressDriver.cpp b/TommyPROM/PromAddressDriver.cpp index 07d060e..968e8b8 100644 --- a/TommyPROM/PromAddressDriver.cpp +++ b/TommyPROM/PromAddressDriver.cpp @@ -1,9 +1,32 @@ +// This controls the shift register that generates the address lines for A0..A15 for most +// chip families. This is not used by the PromDevice8755A code. +// +// Note that this uses direct port control instead of digitalWrite calls so that the code +// can run fast enough to meet the tBLC requirements for SDP and block writes. This +// sacrifices portability and readability for speed. // +// +// This code will only work on Arduino Uno and Nano hardware. The ports for other +// Arduinos map to different IO pins. + #include "PromAddressDriver.h" #define ADDR_CLK_HI A3 #define ADDR_CLK_LO A4 #define ADDR_DATA A5 +// Define masks for the address clk and data lines on PC3..PC5 for direct port control. +#define ADDR_CLK_HI_MASK 0x80 +#define ADDR_CLK_LO_MASK 0x10 +#define ADDR_DATA_MASK 0x20 + +// For larger ROMs, address lines A16..A18 are controlled by D10..D12 (PB2..PB4). +#define UPPER_ADDR_MASK 0x1c + +// When using the 74LS595 shift registers, the RCLK lines of both shift registers can be +// connected to D13 (PB5). Uncomment the #define SHIFT_REGISTER_IS_595 in Configure.h to +// enable the code for this. +#define RCLK_595_MASK 0x20 + void PromAddressDriver::begin() { @@ -14,8 +37,7 @@ void PromAddressDriver::begin() digitalWrite(ADDR_DATA, LOW); digitalWrite(ADDR_CLK_LO, LOW); digitalWrite(ADDR_CLK_HI, LOW); - DDRB |= 0x1c; // Set D10..D12 as outputs - + DDRB |= UPPER_ADDR_MASK | RCLK_595_MASK; // Set D10..D13 as outputs // To save time, the setAddress only writes the hi byte if it has changed. // The value used to detect the change is initialized to a non-zero value, @@ -52,7 +74,7 @@ void PromAddressDriver::setAddress(uint32_t address) void PromAddressDriver::setUpperAddress(byte addr) { // Set the upper address on pins D10..D12. - PORTB = (PORTB & 0xe3) | ((addr << 2) & 0x1c); + PORTB = (PORTB & ~UPPER_ADDR_MASK) | ((addr << 2) & UPPER_ADDR_MASK); } @@ -63,9 +85,9 @@ void PromAddressDriver::setAddressRegister(uint8_t clkPin, byte addr) { byte mask = 0; if (clkPin == ADDR_CLK_HI) - mask = 0x08; + mask = ADDR_CLK_HI_MASK; else if (clkPin == ADDR_CLK_LO) - mask = 0x10; + mask = ADDR_CLK_LO_MASK; // Make sure the clock is low to start. PORTC &= ~mask; @@ -76,11 +98,11 @@ void PromAddressDriver::setAddressRegister(uint8_t clkPin, byte addr) // Set the data bit if (addr & 0x80) { - PORTC |= 0x20; + PORTC |= ADDR_DATA_MASK; } else { - PORTC &= 0xdf; + PORTC &= ~ADDR_DATA_MASK; } // Toggle the clock high then low @@ -89,4 +111,12 @@ void PromAddressDriver::setAddressRegister(uint8_t clkPin, byte addr) PORTC &= ~mask; addr <<= 1; } + +#ifdef SHIFT_REGISTER_IS_595 + PORTB &= ~RCLK_595_MASK; + delayMicroseconds(1); + PORTB |= RCLK_595_MASK; + delayMicroseconds(1); + PORTB &= ~RCLK_595_MASK; +#endif } diff --git a/docs/hardware.md b/docs/hardware.md index 6fe7459..3cb484d 100644 --- a/docs/hardware.md +++ b/docs/hardware.md @@ -12,7 +12,8 @@ nav_order: 3 The hardware uses an Arduino to write data and to toggle control lines with the appropriate timing to access the PROM. A pair of 74LS164 serial to parallel shift registers latch the address lines. Use of the shift registers allows the Arduino to -control up to 16 address lines using only 3 output ports. +control up to 16 address lines using only 3 output ports. This design will read and +program the 28C series chips and can read most other parallel ROM chip families. The basic circuit is as follows: * Pins D2..D9 are wired to the data lines on the target PROM. @@ -21,17 +22,77 @@ The basic circuit is as follows: * Pins D10..D12 control A16..A18 for chips larger than 64K bytes. Note that the existing design uses 74LS164 shift registers, but another 8-bit parallel out -shift register, like the 74LS594 or 74LS595, could be used instead with some pin changes. +shift register, like the 74LS595, could be used instead with some pin changes. + +When using the 74LS595 instead of the 74LS164, there is an additional output latch that +needs to be pulsed to put the contents of the shift register on the output lines. The +code supports this by uncommenting the _#define SHIFT_REGISTER_IS_595_ line in +Configure.h. The D13 line from the Arduino controls the RCLK latch on the '595. The table +below shows the connections when using either the 74LS164 or the 74LS595 for the address +shift registers. USR refers to the Upper Shift Register (A8..A15) +and LSR refers to the Lower Shift Register (A0..A7). + +|Arduino |74LS164 |74LS595| +|:---: |:---: |:---: | +|A0 |ROM WE |ROM WE| +|A1 |ROM CE |ROM CE| +|A2 |ROM OE |ROM OE| +|A3 |USR CLK |USR SRCLK| +|A4 |LSR CLK |LSR SRCLK| +|A51 |LSR+USR A |LSR+USR SER| +|D2..D9 |ROM D0..D7 |ROM D0..D7 | +|D10..D122 |ROM A16..A18|ROM A16..A18| +|D133|-- |LSR+USR RCLK| + +Notes: +1. The data pin on A5 is connected to both the Upper Shift Register (USR) and the Lower Shift Register (LSR). +2. The upper address lines are not needed for 28C64 and 28C256 chips, but are used for +larger chips like the 27C040. +3. The D13 pin controls the output register on the '595 shift registers. The code for +this must be enabled in Configure.h. This pin is not connected when using the 74LS164. The two shift registers can produce a sixteen bit address, although the 28C256 only needs -15 addresses. Chips larger than 64K are supported by using the shift registers for A0..A15 -and connecting Arduino pins D10..D12 to the chip's A16..A18 +15 addresses. Chips larger than 64K are supported by using the shift registers for A0..A15 +and connecting Arduino pins D10..D12 to the chip's A16..A18 ![TommyPROM Nano Schematic](images/TommyPROM-nano-sch.png) **NOTE:** The schematic does not show the Vcc and ground pins for the 74LS164 shift registers. -These must be connected to +5 and ground, respectively. +These must be connected to +5 and ground, respectively. It is also good practice to place a decoupling capacitor (0.1uF or 0.01uF is good) on the power rails near the Vcc connections. + +## Ben Eater EEPROM Programmer + +If you are here because you built the [Ben Eater EEPROM +Programmer](https://github.com/beneater/eeprom-programmer), note that the designs are +similar, but the TommyPROM code will not run on that hardware without some significant +changes. If you just need to unlock the Software Data Protection (SDP) on a chip, then +see the +[unlock-ben-eater-hardware sketch](https://github.com/TomNisbet/TommyPROM/tree/master/unlock-ben-eater-hardware) for a solution. That sketch is purpose-built to run on the Ben Eater +hardware directly and it will not work with the TommyPROM hardware. + +If you want the functionality of the TommyPROM software on the Ben Eater hardware, the +easiest path is probably to modify the hardware to match the TommyPROM software rather +than trying to change the pin assignments in software. There are a few reasons for this: + +* The Ben Eater hardware uses D13 to control the ROM's Write Enable pin and it ties the +Chip Enable pin to always be active. The D13 pin is connected to the Arduino's built-in +LED, which blinks at boot. This means that the chip is likely some writing random data at +boot time. This isn't a problem for the Ben Eater sketches, because they always write +their own data to the chip anyway. One use of TommyPROM is to just read data from a chip, +so a random write on boot would be bad. +* The OE pin is controlled by the Address shift registers. This doesn't work well with +the modular architecture of TommyPROM and it definitely would not work with 74LS164s +because it would toggle the OE pin as new addresses are shifted in. +* The direct port write software is a bit complicated and is more difficult to change than +just renaming a few pin #defines. This was done for performance reasons, particularly +for the SDP timing, but it means that the code is not easy to change. + +Changing the hardware is fairly straightforward. The data lines move 3 pins from D5..D12 +down to D2..D9. Most of the ROM and shift register control lines move over to the A0..A5 +pins. The upper shift register is controlled directly from the Arduino instead of being +connected to the overflow of the lower shift register. All of the connections are in the +chart in the section above. ## Intel 8755A Hardware Version diff --git a/docs/troubleshooting.md b/docs/troubleshooting.md index 461c2dd..74b5a02 100644 --- a/docs/troubleshooting.md +++ b/docs/troubleshooting.md @@ -15,7 +15,7 @@ The verifier sketch can be used without a chip installed to scope out address an lines. It also offers low-level control when the chip is installed. THIS TOOL USES DIRECT PORT ACCESS ON THE ARDUINO. CHECK TO MAKE SURE IT IS COMPATIBLE -WITH YOUR BOARD BEFORE USING. It will work correctly on the Unu, Nano, and Boarduino. It +WITH YOUR BOARD BEFORE USING. It will work correctly on the Uno, Nano, and Boarduino. It WILL NOT WORK on the Micro. Note that the commands write to the individual 28C control lines with some exceptions to @@ -34,7 +34,7 @@ is unlocked. Hardware Verifier - 28C series EEPROM Valid commands are: - Axxxx - Set address bus to xxxx + Axxxx - Set Address bus to xxxx Dxx - Set Data bus to xx Cs - Set Chip enable to state (e=enable, d=disable) Os - Set Output enable to state (e=enable, d=disable)