2014-08-15

68008 SRAM Microcomputer - Circuit Description V1.1

While waiting for the Z80 project for co-production, the 68008 board circuit has evolved. A severe bug has been removed (connecting one input of a NAND gate to ground doesn't transform it into an inverter) and a lot of timings have been scrutinized by hand, resulting in some modifications; e.g. only using address lines to select the strobe signal for the K1-bus strobe decoder or swapping /CE and /OE of the EPROM. This will be covered in another article.

This post is about the logic of the circuit. It is very simple and covered in great detail, so i hope it's possible to really understand how the board works. The project web page contains some additional material and eventually reading the 68000 data sheet will provide deeper insight.

This is a simple 68008 CPU board for the K1-bus. It uses a 681000-70 128kB SRAM and one 27C010 128kB EPROM or one 27C512 64kB EPROM or similar. The board does not contain any i/o circuitry except for an unbuffered K1-bus. Even a system timer must be provided this way.

Main Circuit



Main Circuit with CPU, RAM and ROM

The connection of RAM and ROM is very straight forward. Data bus lines and address bus lines are connected 1:1. Only two standard logic chips are used to interface the control signals: one 74HCT00 quad NAND and one 74HCT139 dual 2-to-4 decoder.

CPU control outputs used are /AS (controlling all bus cycles) and /WR (discriminating between read and write cycles). CPU control inputs used are /DTACK (terminate a bus cycle), /VPA (terminate a slow bus cycle) and /IPL1 (interrupt request).

Let's start with the signals provided and received by the 68008 CPU:

CLK: a clock signal of 10 MHz is generated by a DIL clock generator.

FC0 to FC3: These outputs provide information about each bus cycle: Whether it's program or data and whether it's user mode or supervisor and whether it's an interrupt acknowledge cycle. I was thinking of using this to page-in ROM at address 0x000000 after reset but found it did not save me components and would make software more complicated. So these outputs are not used.

/BERR: signals a bus error to the CPU. Not used on this board. There will never be a bus error detected. All bus cycles terminate with /DTACK or /VPA.

/BR and /BG: Used for multi bus master control. Not used on this board. There is only one bus master: the CPU.

/RESET and /HALT: After power-up the CPU must be reset for 0.1 seconds (really!) by pulling these lines low. Both pins are outputs as well: /RESET can be asserted by software and will in return activate /HALT: this will halt the CPU after the current bus cycle, by when /RESET is already released again thus it should not cause problems to the CPU. Or /HALT can be asserted and will reset the CPU. /HALT is asserted if double bus errors are detected (and evtl. other conditions) and can eventually never happen with this board. To be tested when built :-) This signal is directly connected to the K1-bus /RESET line.

/AS: During a bus cycle /AS is activated while the address is valid. Basically /AS going low starts a bus cycle and /AS going high terminates it.

/DS is similar to /AS but in write cycles it is asserted slightly later than /AS. I thought that it was not asserted at all in 6800 cycles, because the signal is not shown in the 6800 timing chart, but it is, as can be seen in the autovector timing chart. This signal is not used.

/WR indicates that this bus cycle is a write cycle. The opposite signal /RD does not exist and is generated by an inverter.

/DTACK: Data Acknowledge is asserted by external circuitry to tell the CPU that it can finish the current bus cycle. It is possible to keep this signal low all the time so that the CPU will run without wait cycles. (Though the timing charts all tell you that this signal has to go up and down.) On this board /DTACK is asserted all the time except if /WAIT on the K1-bus is activated or a slow bus cycle is performed which will be terminated by /VPA.

/VPA is connected to a signal called /SLOW_IO: A bus cycle of the 68008 can be terminated normally in two ways: by /DTACK or by /VPA. /VPA means "valid peripheral address" and is used to interface old (very old!) 6800 peripherals. The 68008 then does an extremely slow bus cycle. I use this to do very slow i/o cycles on the K1-bus. /VPA has a second meaning: If an interrupt acknowledge cycle is terminated with /VPA, then the CPU does not read the interrupt vector from the data bus but generates an 'autovector' internally. This board does not use /VPA for interrupt acknowledge cycles. Instead it uses vectored interrupts and uses /DTACK to terminate interrupt acknowledge cycles.

IPL0/2 and IPL1: Interrupt inputs. The 68000 has 3 interrupt lines, the 68008 has only 2 due to pin shortage in the dip package and connects both IPL0 and IPL2 to one pin. Pulling low any combination of these lines forces an interrupt in the 68008. Pulling low all interrupt lines generates a non-maskable interrupt, pulling low less lines results in an interrupt of level 1 to 6. In the 68008 normal interrupts of level 2 (IPL1) and 5 (IPL0/2) can be generated. This board uses only interrupt IPL1, which is directly connected to the K1-bus interrupt line.

The Control Signals of the RAM and ROM:

/CE: This enables the memory chip. While enabled, it can be read or written. The RAM also has a positive CE2 input, but this is not used. /CE is enabled by a 2-to-4 address decoder. See below.

/OE: If the memory chip is enabled, asserting /OE enables it's output drivers and the currently addressed byte is put on the data bus, where it can be read by the CPU. /OE is connected to the inverted /WR signal of the CPU: so at any time either /OE or /WR is enabled.

/WE: The RAM can also be written: if /WE is asserted while the RAM is enabled, then it will read the byte from the data bus and write it into the currently addressed memory cell. /WE is connected directly to the CPU's /WR output.

/CE and /OE of the EPROM are not connected as expected but swapped: the result is the same – the EPROM puts data on the data bus if both signals are enabled – but memory access after /CE is much slower than after /OE and enabling the chip with /CE would always require one wait state, at least if i use one of my (well stocked) 27C512-250 EPROMs with 250 nano seconds access time from /CE. But the EPROM's access time from /OE is only 100 ns, and therefore i connect /OE to the timing critical output of the 2-to-4 address decoder and /CE to the less timing critical /RD signal and can access the EPROM with no wait cycles.

Glue Logics


Only two standard logic chips are used to interface the control signals: one 74HCT00 quad NAND and one 74HCT139 dual 2-to-4 decoder.

Bringing it all together

The 74HCT00 quad NAND provides one NAND, one inverter and one flip flop, as can be seen to the left.

The first gate generates /DTACK to terminate most bus cycles. /DTACK is permanently low except if /SLOW_IO or /K1_WAIT is low. /K1_WAIT originates from the K1-bus and /SLOW_IO is activated when access to a special address range is decoded.

The 2nd gate is used to invert the /WR signal of the CPU to generate the /RD signal required by the RAM and ROM.

Gate 3 and 4 construct a flip flop. After reset the CPU reads reset vectors from address 0x000000 which can only be provided by reading from ROM. But at runtime we'd like to have RAM at address 0x000000 to allow the running program to modify the vector table. To achieve this, this flip flop is set by the /RESET signal and cleared by the first access to an i/o address which activates signal /CLEAR_INIT. While set, the INIT output is used to temporarily map ROM at address 0x000000.


The two 2-to-4 decoders of the 74HCT139 are used to generate the RAM and ROM /CE signals, to clear the init_FF and to generate the /SLOW_IO signal.

The 1 MB address space of the 68008 CPU is divided into 4 regions: RAM, ROM, fast i/o and slow i/o.

The first decoder generates the RAM and ROM /CE signals. As explained above it actually generates /OE for the EPROM. For this it decodes the highest address lines A19 and A18: A19 must be low for both and A18 discriminates between RAM and ROM. This results in a memory map as follows:

0x000000 .. 0x03ffff  max. 256kB SRAM (actual size: 128kB)
0x040000 .. 0x07ffff  max. 256kB ROM  (actual size: 64kB or 128kB)

As explained above we need ROM at address 0x000000 after reset. Therefore signal INIT from the init_FF is used to pull A0 of the address decoder high, so that memory accesses in the RAM address range will activate the EPROM instead. Technically the resistor and the diode construct an OR gate.

The decoder is strobed with /AS from the CPU so that there are no spikes on the outputs when the address toggles between bus cycles. This is important, so that the RAM does not erroneously write some void data into random cells and that /CLEAR_INIT is not activated too early, e.g. immediately after reset before the CPU even read the first byte of the reset vector.

/CLEAR_INIT is generated when A19 is high and either A18 or INIT is high, and will clear the init_FF. A19 high means this is an i/o address.

The second decoder generates the /SLOW_IO signal, which is connected to the CPU's /VPA address input and to the first NAND gate to suppress /DTACK. If this signal is activated, the CPU will perform a very slow 6800 peripherals bus cycle. The signal is activated when A19 is high and A14 is low:

A19 must be high for any i/o access, because A19 low is used for memory access, either RAM or ROM.

A14 is used to discriminate between fast and slow i/o cycles. If we'd use A18 instead then the first decoder would have done the job. But A14 is used because it is in the low word of the address.

The 68000 uses 32 bit addresses but has a short addressing mode, where a 16 bit address is sign-extended to 32 bits. This saves program space and execution time, as only 2 address bytes must be read from memory.

If we want to use short addressing for i/o, then all address bits from A15 to A31 must be the same. And as A19 is high, they must all be high. (which besides means negative addresses for i/o). This makes A18 unusable for this task. On the other hand we cannot use A14 to discriminate between RAM and ROM as well, because that would break memory into 16 kB chunks. `:-)

Slow i/o is deliberately chosen to be activated when A14 is low:

When the CPU performs an interrupt acknowledge cycle, it puts the acknowledged interrupt level (which is always 2 on this board) on A1 to A3 and pulls all other address bits high. So during an interrupt acknowledge cycle A14 and A19 will be high and /SLOW_IO, and consequently /VPA at the CPU will not be activated and the CPU will do a fast bus cycle and will read a vector number from the data bus. This is explained in more details below.

K1-Bus I/O Circuit


This board uses a K1-bus for all peripherals. This is a hobbyist-grade 16-bit peripherals bus for CMOS devices which can be used unbuffered in small systems, as is done with this CPU board. The core K1-bus uses 16 data lines (8 may be sufficient for most cards), 6 address lines (4 mandatory) and 5 control lines, aka 'strobe lines'. It has one interrupt line, a wait request line and a reset line.

A unique feature of this bus is, that cards are not selected implicitly by the address in an i/o operation but must be selected beforehand instead. The address lines are only used to select registers inside the currently selected card.

Another unique feature of this bus is, that cards have an assigned data line which is used as their address. This data line is selectable with a jumpers on the i/o cards. This data line is used in conjunction with 3 of the strobe signals: /SELECT, /RD_IRPT and /WR_IRPT. The other 2 strobe signals /WR_DATA and /RD_DATA control data transfer to and from the card. This CPU board can only use data lines D0 to D6.

As can be seen in the circuit above, there are 3 more signals used: /RD_I2C accesses an I²C bus on the K1-bus, which is used to attach I²C EEPROMs which are used to detect cards automatically and which can provide driver code. Implementing the I²C bus interface is optional but recommended. /RD_HI and /WR_HI are used to control 2 data registers which pass data from the 8 bit data bus of the 68008 CPU to the high data byte of the 16-bit K1-bus. This is optional.

A 74HCT138 3-to-8 decoder is used to generate all these 8 strobe signals. A strobe signal is enabled when A19 is high, which on this board means an i/o access. A0 to A2 select which strobe signal to activate.

/AS is used to control output enable as well (to strobe the decoder outputs) so that strobe signals are only generated when the address is valid. Otherwise there would be spurious spikes on the strobe lines. The exact timing is tricky, due to wide timing windows in the 68008 timing charts, which i will discuss somewhere else.

There are 4 strobes for read cycles and 4 strobes for write cycles. They are assigned to the decoder so that using the CPU's /WR signal could have been used instead of A2. And originally it was. But the bus cycle timings for the 68000 are so lousy that the risk for spikes on the decoder outputs was too high and i decided to use A2 instead. Now the program must take care to access i/o addresses with bit A2 properly set, or there will be bus collisions when writing to a read address.

The /RD_IRPT strobe is connected to output number 5 to allow vectored interrupts:

The strobe signal decoder is also activated in an interrupt acknowledge cycle, because /AS is activated as in any bus cycle and A19 is high. A1 to A3 encode the acknowledged interrupt level, which is always 2 on this board.

So the address on the bus is %1……111110101, where the blue digits indicate the acknowledged interrupt level. So bits A0 to A2 are %101 which selects output number 5. This instructs all attached cards to put their interrupt state on their assigned data line: '1' if inactive and '0' if active. Additionally, the data bus has pull-up resistors (initially for helping the 68008 with pulling them up for the K1-bus) which will make all unconnected data bits read '1' as well.

So the vector read by the CPU is 0xff – x, where x is the active or potentially a combination of multiple active interrupts. If we never choose D7 for the assigned data line of a card, the vector will always be in range 0x80 to 0xFF, never conflicting with any other predefined vector. The vector table has to be filled with matching interrupt vectors. Wherever more than one bit is low in the vector address the program can decide which vector to store, e.g. always the vector of the interrupt with higher data bit number, thus implementing interrupt priorities.

The CPU's A0 is used for the strobe decoder's A0 to enable word write instructions. The 68008 first writes the high byte to the even address and then the low byte to the odd address. If writing to the right address, this automatically first stores the high byte in the low-to-high data bus latch and then writes both bytes in a 16-bit K1-bus /WR_DATA cycle. Unluckily the same magic does not work for read cycles: the word will be read byte-swapped and must be swapped programmatically, which is a little bit awkward, because the 68000 CPU has no opcode for this.


The low-to-high and the high-to-low data registers

Data is stored in the low-to-high data register when the /WR_HI strobe signal is active, which means, that the CPU writes to an appropriate i/o address, and it put's it's contents on the high byte of the data bus when /WR_DATA is active, while the CPU supplies the low byte.

There is a jumper option on the board to use /WR instead of /WR_DATA to enable the low-to-high latches outputs. This is to solve potential timing problems.

The high-to-low data register reads data from the high byte of the data bus when /RD_DATA is active while the CPU reads the low byte, and it put's it's contents on the low data bus when /RD_HI is active, which means, that the CPU is reading from an appropriate i/o address.

The I²C bus connection is centered around a 74HC367 2+4 bit driver IC. The circuit is described on my K1-bus page. A6 and A7 are chosen for data output to the I²C data and clock line. D7 is used to read the state of the I²C data line. All I²C signals and timings are generated by the CPU under pure software control.

The I²C bus is used to attach I²C EEPROMs which are used to automatically detect cards and which can provide driver code.

In addition, 2 LEDs are connected to the I²C driver for debugging the board. I spent some time to find a place to connect some lights, as this CPU board does not contain any i/o port pins.

A8 to A13 of the CPU are connected to A0 to A5 ot the K1-bus. Also, there are pull-up resistors on A7 to A13. This is because the 68008 CPU uses TTL levels for all signals and has only very poor high-driving capability, while the K1-bus is defined for symmetrical signals, as used by 74HCxx or 74ACxx series ICs.

The reset circuit was already discussed in great detail in January:

After power-up the capacitor is empty and current flows through it and through the base of transistor T1 which opens and pulls the /RESET line low. While /RESET is low T2 is closed. When C1 fills up the current decreases and at some point T1 does no longer drain all current from the /RESET line: the voltage rises and T2 will open and drain the remaining base current of T1 which will rapidly close: /RESET goes high and the system starts.

2014-08-06

Z80 Microcomputer with SRAM and K1-Bus

My 68008 system is waiting for production and this is, because it uses only 1/2 of an Euro board which i prefer to order, because this size is the cheapest. So finally i finished a Z80 board for the K1-bus as well.

The system consists of a CMOS Z80 CPU running at 6 MHz, one 32kB SRAM and one 32kB EPROM or EEPROM. It has no I/O except a K1-bus connector. The K1-Bus allows attachment of 16 bit peripherals. K1-bus card selection is restricted to D0 .. D7.

Memory Map



The Z80 uses separate instructions for I/O and memory access. Therefore the I/O address space is not part of the memory address space.

RAM is mapped to $0000 .. $7FFF and ROM is mapped to $8000 .. $FFFF. This allows modifying the RST vectors at run time.

After reset the ROM is mapped to the whole address space because the CPU starts execution at address $0000 and needs to find code there.

Pin header JP3 allows using an EPROM or an EEPROM. The EEPROM is writable by the Z80.


RAM / ROM select circuit



The RD and WR outputs of the CPU are directly connected to the RAM and ROM's corresponding inputs. Activation of the memory chips is done using their CE input.

RAM is enabled when IORQ is low and A15 is low,
ROM is enabled when IORQ is low and A15 is high.

There is a 'init state FF' which is set by RESET and cleared by any I/O operation. Thus the FF is set after reset, will be cleared by the first I/O instruction and remain cleared throughout the rest of it's life. While it is set it forces A15 high in the RAM/ROM select circuit so that the CPU will always read from ROM.

Reset circuit


The reset circuit was elaborated in great detail in my hardware blog. It is a little bit load dependent but should work up to 5mA pull-up current, which is much more than is to be expected, unless you attach a LED here. ;-)

With the selected value of the timing capacitor the reset pulse will be approx. 2 ms.


I/O


The CPU board does not contain any peripherals, not even a timer interrupt. All Peripherals are expected to be connected at the K1-bus.

The K1-bus provides an I²C bus to attach EEPROMs with driver code and is 16 bit wide. Therefore two data latches are required for buffering data from the Z80's 8 bit bus to the upper half of the K1-bus.
I/O therefore is divided into I²C bus access, high-to-low and low-to-high data latch access and actual bus access.

The K1-bus is specified for symmetrical signals (HC, AC not HCT or TTL) therefore some signals may not have required levels without help.

K1-bus IRPT is directly connected to the IRPT input of the CPU. The interrupt source is determined in software.

K1-bus WAIT is directly connected to the WAIT input of the CPU. Any peripheral board which can issue WAIT fast enough can be used with this CPU board. Since the Z80 is pretty slow this probably means all peripheral boards.

The K1-bus address lines A0 to A5 are directly connected to the corresponding CPU address lines. They are pulled up with 3.3kΩ resistors to help the CPU to pull them up: The CPU has very little driving capabilities and driving high is even less than driving low:
    IOL = 2.0mA     @0.4V
    IOH = -1.6mA    @2.4V (which is too low for HC inputs)
    IOH = -250µA    @4.2V
Eventually 4k7Ω is a better choice. To be tested.

The K1-bus data lines D0 to D7 are directly connected to the CPU as well, which is an allowed design for very small systems. Expect problems with the third card added! They are pulled up with 3.3kΩ resistors to help the CPU to pull them up for the same reason as above. The K1-bus data lines D8 to D15 don't need pull-ups because they are driven by the 74HCT574 which has symmetrical outputs (though TTL inputs) and slightly higher driving capabilities as well.

K1-bus select and strobe generation


Any I/O instruction addresses the K1-bus. This is centered around a 74HCT138 3-to-8 decoder. It is enabled by IORQ=0 && M1=1. It then activates one of 8 strobe lines, depending on A6, A7 and WR. Pin headers JP4 allow to use A6, A7 and A8 instead and IORQ has a "strong" pull-up resistor. The reason for these circuit options are explained below.


The following strobe signals are generated by the 74HCT138:


WR_SEL
Signal on the K1-bus to select a card for subsequent I/O operations. I/O cycles on the K1-bus do not contain the address of the talked-to card, instead a card must be 'selected'.

RD_IRPT
Signal on the K1-bus to read in the interrupt states of all cards to detect which one actually activates the IRPT line.

WR_IRPT
Signal on the K1-bus to mask off interrupts on some or all card. Can be used to implement interrupts with priority levels.


RD_DATA
Read data from a K1-bus card. The lower data byte is read by the CPU directly while the upper data byte (if present) is latched into the high-to-low data latch.

WR_DATA
Write data to a K1-bus card. The lower data byte is supplied by the CPU directly while the upper data byte (if required) is supplied by the low-to-high data latch.

WR_HI
Write one byte of data into the low-to-high data latch for use in the next (probably immediately following) WR_DATA cycle.

RD_HI
Read the upper data byte from the last RD_DATA cycle from the high-to-low data latch.

RD_I2C
Read or write to the I2C bus. Both is done by reading. The I2C data and I2C clock lines are set by A6 and A7, the value from the I2C data line is read on D7. The circuit is taken directly from my K1-bus page and was the only idea i had to use only one IC.

The two LEDs are for debugging. It took me some time to find a place for some debugging lights on a CPU board without any i/o circuitry (except K1-bus) on it. :-)

74HCT138 enable:



A Z80 I/O bus cycle is strobed with IORQ by the CPU, so this is the first signal used to enable the signal decoder. But the CPU issues this signal for interrupt acknowledge cycles as well. This can be distinguished by the M1 signal, which is activated for interrupts but not for I/O cycles, so M1 must be high to detect an I/O cycle. M1 starts 2.5 cycles (that is: long) before IORQ and remains approx. 10ns longer active (M1: 80ns max. and IORQ 70ns max. after T3↑. These are marked with reference number 20 and 52 in the timing chart below) so it should be possible to use M1 directly to mask the IORQ signal.


Next is a timing problem: WR (and RD) and IORQ go up simultaneously: 70ns max. after T3↓ as can be seen in the I/O timing chart below. This may result in spurious pulses at arbitrary outputs of the 74HCT138.
note: T3 in an I/O cycle is one cycle earlier than T3 in an int ack cycle: int ack inserts 2 automatic wait cycles before T3 and I/O only one.


There are some ideas to overcome this:

  • Make the IORQ signal end earlier:
    Problem: edges can be delayed and not be brought forward. So some very clever circuitry would be needed to do this.
  • Make the WR signal longer:
    Adding a delay to the signal would do the job. But it would also delay the starting edge of the signal: One HCT gate adds approx. 10ns, so the front edge would at least move from 60ns to 70ns, which is now after the 65ns of the IORQ signal. Whatever we do with the WR signal, it will always at least add one gate latency to the front edge as well! So this is no easy solution either.
  • Delay both signals to have time for front and end shaping:
    Unfortunately we don't have any time available for delaying the end of the IORQ signal: in an output cycle data is only guaranteed to be stable for 30ns after IORQ goes up (time #35) which is just enough to propagate IORQ through the '138 to the strobe signal (HCT: typ. 19ns, 40ns max, HC: typ. 17ns, 30ns max)
  • Use an address line instead of WR:
    This is what i do in the Z80 reference design on my K1-bus webpage. This is safe in respect to no spikes on the strobe lines but has a small risk of bus collisions, e.g. if a program crashes. Since all lower 8 address lines are currently used up, we'd need A8 as well, which will make block I/O opcodes impossible to use. But this restriction could be limited to K1-bus cards which actually use all 6 address lines if we reassign the address lines, so that the rarely used K1-bus A5 will be driven by Z80 A8. I will use this design as a fallback for safety. This is what pin-header JP4 in the "IO strobe signal decoder" image above is for.
  • Use a "strong" pull-up:
    A method i have already used on my K1 CPU is "signal shaping" with "strong" pull-ups: If you add a low pull-up or pull-down resistor which draws "high" current, it will aid signal flipping into the pull-up's direction and delay signal flipping in the other. Applying a "strong" pull-up to the IORQ signal will slightly delay the starting edge of the pulse and slightly bring forward the ending edge. So what is "strong" here? The CMOS Z80 can only sink 2.0mA @ 0.4V, so a pull-up which supplies just this will be a reasonable choice: This is approx. 2.5kΩ. Disadvantage: The amount of time which can be shifted this way is tiny: some few ns only, but they may just be enough here.

Besides WR (or A8, if nothing else works) A6 and A7 are chosen for strobe selection, because they are in the low address half, making all I/O instructions usable and they are the only unused address lines because A0 to A5 are already used for addressing K1-bus card registers.

The board


This is a view of the component placement on the board. The board will be produced within the next few weeks in one go with the 68008 board because they can be placed on one Euro board (160x100mm). More material can be found on the project's web page on my web site.

2014-04-27

Adding value to my Mac...

Hi all,

i just wanted to write some words about my new system disk and since this is kind of hardware...
ok, here it goes.

I bought an OCZ Vector 150 480MB SSD for my Mac.

SSD
+ Speed
– Price

Pro model
+ write endurance: 5 years warranty x 50GB/day vs. 3 years warranty x 20GB/day
– Price

And now Apple enters the Scene...

I have a "late 2009 iMac" which means:
1. Apple does not like me to open it
2. There's a proprietary thermal sensor built in the current drive
   which is not documented but required or the fans spin up to maximum
3. Apple deliberately does not support TRIM for non-Apple SSDs

ad 0: Copy data to new drive: I copied all data with Carbon Copy Cloner from bombich.com beforehand from the internal HDD to the SSD which i had attached to the USB interface of my external backup drive. This took exceptional long, probably because i have some GB of hard linked files on it.

ad 1: Open the iMac: find a pair of suction cups and a dust-free working place.

ad 2: Thermal sensor problem: I found sources which said it's a 2N3904 transistor which sounds reasonable but there were signs for doubt: Shorting these 2 pins should silence the fan as well though shorting would move the measured voltage in the wrong direction. On the other hand in the mid 2009 model it is a transistor. So it might be. I consulted some data sheets and prepared to attach a BC337 as an external sensor.

When my iMac was open i measured the diode voltage at the two pins of the HDD and found in one direction slightly more than 1V and in the other direction 0.36V which says: no, it's not a transistor. Nevertheless i attached the prepared transistor in the most likely direction. I can only guess now that it's in fact a 1-wire sensor.

After restarting my Mac the fans sped up. For that "worst case" i had already downloaded SSD Fan Control from exirion.net. I installed it.

Unluckily the OCZ Vector does not have an internal temperature sensor, so the "intelligent" mode of SSD fan control does not work. I had to set a fixed value.

ad 3: TRIM support: As in it's worst days when they were nearly broke Apple tests whether the found drive is one Apple provides itself and disables TRIM support for others. TRIM support informs the SSD which blocks are deleted in the file system and from now on do not need to be updated whenever neighbor blocks are written thus speeding up writing and reducing write wear on the SSD. So i ran the already downloaded TrimEnabler from cindori.org. This patches a kernel extensions, which means: it overwrites the test for the found model.

Unexpected Problem

When i wanted to fit the SSD in it's 3"5 adapter into the iMac i found that OCZ uses metric screws whereas Apple is still stuck to 'imperial' units.

Cast in Order of Appearance:

The Backup took exceptionally long: 3:30 hours for 232GB.

The SSD with the included 3"5 adapter

The SSD attached to the USB interface of my external backup HDD.

The sensor which did not work. Also additional wire would not have been required.

When lifting the front glass there was immediately lots of dust sucked in and settled on the display.
No chance to avoid this. (the screw is only to help auto focus)

My iMac with the old HDD, a Seagate Barracuda.

The SSD with the (not-working) sensor on it's 3"5 adapter fitted to the iMac's mounting bracket.
I had to find a way around that metric/imperial problem and placed the mounting bracket between adapter and SSD and pinched it with two screws.

The SSD placed in my iMac.
Conclusion

Especially program start now noticeably faster. I think it was worth it.







2014-01-31

68008 SRAM Microcomputer - Software Toolchain

Hello,

this is not nice. It's a PITA but everyone uses it: The Gnu Compiler Collection; here with a backend to produce m68k object code. I suffered for some hours, but then i had success: The first test program compiled! Let's see how it works. (and leave out most of whatever did not work.)

Compiling the GCC is not a trivial task, you need a GCC and lot's of other tools, they should match each other, find each other and work on my desktop machine.

Mac Ports (the port system i use on my Mac to port 'alien' stuff) was no help though right now i can see they provide a (very outdated) version of the rtems tool chain. Yesterday i installed a toolchain for ARM and the Mac Ports ARM GCC for Linux is so old that it even fails to install (it's from 2005, today is 2014!)

OSdev.org is a great site but still a little bit over-complicated. (Ok, actually it's the GCC which is over-complicated.)

Next was rtems.org, a project for real-time embedded micro systems. The project supports the 68k CPUs but it's not the bare GCC but with their added extra. Maybe i'll cherry-pick some sources from them... :-) In the first place i didn't realize that this project already comes with a whole OS, else i had eventually skipped it. But so i downloaded the whole stuff from rtems.

Starting from their start page it was only three clicks away from rtems.org/ftp/pub/rtems/people/chrisj/source-builder/source-builder.html.

Following the instructions i did:

$ cd
$ mkdir -p development/rtems/src
$ cd development/rtems/src
$ git clone git://git.rtems.org/rtems-source-builder.git
$ cd rtems-source-builder
$ source-builder/sb-check
$ cd rtems
$ ../source-builder/sb-set-builder --list-bsets
$ ../source-builder/sb-set-builder --log=l-m68k.txt \
  --prefix=$HOME/development/rtems/4.11 4.11/rtems-m68k

(Actually i installed into a different directory, but that doesn't make much difference.) After waiting roughly one hour a couple of new GCC instances entered this world.

The rtems people have configured their installation scripts so that the resulting tool names all start with "m68k-rtems4.11-" which is different to "m68k-elf-" which is normally used. Probably there is a good reason for that.

Next i stumbled over the bitsnbikes blogger site. J. Silva started a 68008 project in 2010 and described the sources for his first "project". He had borrowed from others and i borrowed from him:

For the first successful test i needed 4 files and two commands:
(You can find all files in my first project folder at little-bat.de)

  • "main.c" the main source file with function main()
  • "crt0.S" an assembler file with the bootstrapping code
  • "ldscript.ld" a configure script for the loader
  • "Makefile" ah well, a Makefile

$ export PATH=$HOME/development/rtems/4.11/bin:$PATH
$ make

This actually produced an S-Record file which i can download into an Eprom. Fine!

S00B0000746573742E53313949
S1130000000800000008000841F900000400203C3A
S113001000000400B1C06704421860F841F9000808
S1130020004E43F900000400203C00000400B089A5
S1130030670412D860F842A742A742A74EB9000845
S1110040004C4FEF000C6000FFFE00004E75F8
S9030000FC

I don't know whether this will work because i haven't even built the hardware. ;-)

The software toolchain for the 68008 board is up and running! :-)

    ... Kio !

2014-01-27

68008 SRAM Microcomputer – K1-Bus Circuit v0.4

The design phase is coming to an end now, if no problems show up during verification phase later, this will be the K1-Bus I/O circuit:

K1-Bus 68008 CPU board with SRAM – K1-Bus I/O Circuit

Short summary of the K1-Bus


The ➧ K1-Bus is a 16 bit peripherals bus designed for simplicity. The basic unique concept of this bus is that the peripheral board accessed is not encoded in the address of each I/O opcode but the board to talk to must be selected. During selection the boards are addressed with a low level on their assigned data line.

Interrupts are signaled on the !K1_IRPT collector line and during interrupt processing the CPU queries the interrupt state of all devices. The CPU can enable and disable interrupts for each device individually by writing a mask work on the data bus. This way all devices may be assigned an individual interrupt priority if the programmer desires.

There are 5 control lines (strobe signals):
  • !SELECT – The CPU writes a mask word on the bus to select a peripheral board for subsequent data transfer.
  • !WR_IRPT – The CPU writes a mask word on the bus to enable or disable interrupts on the attached boards.
  • !RD_IRPT – The CPU reads a mask word with the interrupt state of all attached boards.
  • !WR_DATA – Send data to the selected device.
  • !RD_DATA – Read data from the selected device.

The circuits


The 74HCT138 3-to-8 line decoder generates the strobe signals for the bus when A19 is '1' during a bus cycle when !AS is low. A0, A5 and the !WR signal are used to determine which signal to activate. For the reason to chose A0 see below.

IC 74HC367 with the surrounding resistors and diode implement an i2c interface. Every K1-Bus extension board can provide an i2c EEprom with software driver for the board. Also, the i2c EEprom is used to detect the presence of the board. The funny circuit design is directly taken from my ➧ K1-Bus homepage. It was the simplest circuit i could come up with if no port pins are available to be used for the i2c bus.

The i2c bus is always accessed by reading from the K1-Bus and one of the select lines of the 74HCT138 3-to-8 line decoder is used to address the 74HC367. A6 and A7 are forwarded to the i2c data and clock line while the i2c data line is also read and returned in D7. When the i2c bus is selected, the upper 4 drivers of the 74HC367 are enabled. Then A6 and A7 are forwarded into the lower two drivers. When the upper drivers are disabled the resistors R1 and R2 feed back the output of the lower drivers to their inputs thus making them state keepers. So the low or high state of the i2c data and clock outputs are preserved until the next access is made to the 74HC367. The timing and protocol of the i2c bus must implemented in software. The i2c bus is optional but recommended unless you want to build a one-task computer which does not support to be extended later.

The two LEDs D4 and D5 may be attached here during debugging. As the 68008 CPU board does not have any I/O pins whatsoever, i have spent some time searching for a place to attach some status lights for initial testing. The LEDs should be removed when an I/O board is attached, because the LEDs may disturb operation of the i2c bus.

The two 74HCT574 data latches expand the 8-bit 68008 data bus to 16 bit for the K1-Bus. This is optional and only required if 16 bit extensions are actually attached. A serial card will probably be only 8 bit wide, but an IDE interface will most likely use the full bus width.

When 16 bit data is written to the bus this is done in two stages: First the upper byte is written into the 74HCT574  low-to-high data latch. One output of the 74HCT138 3-to-8 line decoder provides the !WR_HI strobe. Next the low byte is written to the !WR_DATA address as usual. While the CPU provides the low byte the latch outputs are enabled simultaneously and put their data on the upper half of the bus.

Note that only A0 discriminates between !WR_HI and !WR_DATA. This way the program can perform a 16 bit write opcode to the even base address: The high byte will be written first to the even address (A0=0) and the low byte thereafter to the odd address (A0=1). That's really sweet! :-)

When 16 bit data is read from the bus this is also done in two stages: First the low byte is read using !RD_DATA as usual. This will also load the high byte from the K1-Bus into the high-to-low data latch. Then the high byte can be read from the latch. For this the 74HCT138 3-to-8 line decoder provides the !RD_HI strobe.

Reading a 16 bit word is not as convenient as writing. Again !RD_DATA and !RD_HI are chosen to differ only in A0 and the word can be read with one 16 bit read opcode, but the result will be byte-swapped. This cannot be avoided except with some more latches and drivers. So the program has to swap them thereafter and as the 68000 does not provide a byte-swap opcode (though it provides one for word swapping) the best is probably to do an 8-fold rotate left or right on the word data which is a 24 clock cycles time consuming operation.

There are some pull-up resistors and networks related to the K1-Bus:

The !K1_IRPT collector line has a pull-up because it must be driven with open drain outputs.
!K1_RESET line has a pull-up for the same reason.
!K1_WAIT has a pull-up in case no peripheral board is selected. Whenever a board which uses the wait line is selected it must drive the wait line with a tri-state driver which actively pulls high and low. When a board is not selected it must not drive the wait line.

D0..D7 are pulled high with 3.3kΩ resistors. The data bus of the CPU is connected without bus drivers to the K1-Bus. This is possible for very small projects because the K1-Bus is defined to attach CMOS devices which draw only very little current, though switching the level on a line draws some current for the line capacitance which increases with line length and every device attached.

The 68008 CPU outputs TTL levels with very poor high-driving capability: 0.4mA only. The K1-Bus is defined for symmetrical signals as used by 74HC or 74AC types. This is in general no problem, only some timing parameters will shift a little. But as the 68008 can only drive 0.4mA high (and still guaranteeing only 2.4V, so effectively driving even less than 0.4mA) these resistors are there to help the CPU with the '1' bits. 3.3kΩ result in 1.5mA when the outputs are low which is approx. 1/2 of what the CPU can drive low. Peripheral drivers also must provide this additional current for low bits, but 1.5mA should be ok with almost any IC.

A0..A5 (on the K1 Bus) are pulled high for the same reason.

A6 and A7 are pulled high for the same reason because they are attached to the 74HC367 which is not a 74HCT367. I'm too lazy to modify the circuit for a 74HCT367 and i have HCs in stock, HCTs none.

More random notes:

The 74HCT574 high-to-low and low-to-high data latches were chosen to use HCT because when the CPU can operate the bus with TTL levels then the latches can do this as well. No need to read some data lines with HC circuits – keep it consistent.

This CPU board can attach 16 bit K1-Bus extension boards. This means, it can read and write 16 bit data. But it cannot use the upper byte of the data bus for board selection: !SELECT, !RD_IRPT and !WR_IRPT all do not trigger a read or write of the high-to-low / low-to-high data latches. Therefore peripheral cards are limited to D0..D7 for selection.

2014-01-26

68008 SRAM Microcomputer – Main Circuit v0.4

The design phase is coming to an end now, if no problems show up during verification phase later, this will be the main circuit:

K1-Bus 68008 CPU board with SRAM – Main Circuit

Connection of the static Ram and Eprom are straight forward. Ram is mapped starting at address 0x00000 and the Eprom is mapped starting at 0x40000 by use of the 2-to-4 line decoder IC2A.

After power-up the Eprom is forced into the address range of the Ram so that the reset vectors can be read from Rom. This is done by diode D2 which pulls the input A0 of IC2A high while the two-NAND-gate flip flop is in the power-up state.

The address decoder ICB2 either activates !DTACK or !VPA to terminate a bus cycle. !VPA is activated for addresses with A19=1 and A14=1 which will perform a slow 6800-style memory cycle, for all other addresses !DTACK is activated. K1-Bus peripherals may add wait states by pulling !K1_WAIT low. By choice of A14 to discriminate between fast and slow I/O all peripherals can be accessed using short addressing with A15 to A31 all '1'.

The reset circuit has been described in all details in blog post 68008 SRAM Microcomputer – Reset circuit.

Multiple bus masters and single-stepping using the !HALT input are not supported. Bus errors are not detected. All bus cycles will terminate, unless someone pulls !K1_WAIT low. The CPU board does not have it's own timer interrupt and no own I/O pins. This must be provided by at least one attached K1-Bus peripheral board.

For PCB images and Eagle CAD schematics you can view the project page at k1.spdns.de/Develop/….

2014-01-25

68008 SRAM Microcomputer – Windows-in-a-Box

Now to something completely different: Software.

As i expect my 68008 computer not to work with an empty Eprom, i will probably have to program it. For this i have bought some years ago a Genius NSP universal programmer from Shenzhen Stagger Electric. No need to remember this name, they are probably folded. For good reason.

I had installed the software on some kind of old Pentium Desktop running Windows 98 which i kept for this purpose only. But it's sitting in the Loft and i'd need to find a free space to work with it. Frankly, i want to get rid of it.

The idea is to install a Windows in Virtual Box on my Mac. I have already a Linux Mint running in Virtual Box (every now and then) and i know there are free pre-built images of this or that operating system available in the net. I thought, i'd pick an XP image, get an XP license key from an unused pre-scrapped computer from my employer, install the image, register Windows and try whether i can attach the programmer through an USB-to-Serial connection.

Good news: Microsoft offers pre-built Windows images on it's web site for testing the IE and maybe non-commercial use (some websites say). They are not registered but they are freshly installed and the registration period has not yet started. Also, i got a Windows XP Home Edition key from my employer.

I downloaded one of the XP images available, figured out how to combine the split .rar archive which consisted of one .rar file and one .sfx file (how-to: make the .sfx file executable and execute it) and imported the resulting .ova Virtual Box Appliance into Virtual Box. Made a snapshot. Started it.

Step One: It was unregistered as expected and i tried to register my key. This did not work. It seems that the XP instance is a Windows XP Professional and probably this is the reason why the key is rejected. Ok, no problem, i have 30 days ahead.

Second step is to install an anti virus software. I downloaded it with OSX, dropped it in a shared folder and installed it in XP. Yeah!

Third step is to install Firefox. :-)

Fourth step is to install this piece of crap, erm, the software for the Genius NSP programmer. I was afraid it could be on floppy disk, but it was on CD, and, yes, important, on a full-sized CD. I have a slot-in CD drive in my Mac and this matters. Installation worked within few seconds. My Mac is SO fast! :-)

I attached the programmer with an USB-to-Serial adapter to my Mac and started the software. As expected the software did not find the programmer. Ok, let's figure out why.

Windows does not see the adapter. I investigate settings for the virtual machine and found a place to enable this specific USB device which instantly bothered me with the next problem: USB 2.0 controller enabled – you need the VirtualBox Extension Pack. Googled for it, downloaded it from Oracle, it automatically installed into Virtual Box – fine!

After starting XP again and waiting for some seconds, it found 'new hardware'. Do i have a driver disk? hmm, no. Shall i search online for a driver? – yes. Wait. wait. I didn't find a driver. Mist. (Did it ever find a driver this way?)

I figured out what is inside the USB adapter – a Prolific Technology Inc. USB-Serial Controller C, product ID 0x2303. So i downloaded the PL2303_Prolific_DriverInstaller_v1_9_0 driver from the Prolific website from OSX, moved it into the shared folder and installed it in XP.

Ok installed. What's next? The Stagger software still doesn't find it. Hmm, given my experience with Windows i restarted it. And yes, now there is a Prolific USB-to-Serial Comm Port in the Device Manager and – ta ta – the NSP software can talk to the programmer! That's not a matter of course, because even if the serial communication works the software may do some weird things with the serial port, like bit-banging, and that is likely to fail with an USB adapter.

I tried reading an Eprom and it looked like this:

Crappy NSP software reading my Eprom

Only partly translated, very poorly translated, window decoration around a transparent window. Buggy chip data base. Outdated now. >:-) But it works. Somehow.

Ok, i can throw away the old Windows 98 computer. Fine. :-)

2014-01-23

68008 SRAM Microcomputer – Free Run

Hello,

yesterday i searched for some of the parts and put the 68008 on the bread board. According to other projects it is possible to do a "free run" by pulling all data lines to low. Though some people say it's the opcode of NOP it actually is some kind of ORI.

I wanted to check some prerequisites of the project:
  1. Does the CPU work?
  2. Can !DTACK (data acknowledge) be held permanently low?
  3. Can !VPA (valid peripheral address) be used for instruction fetch cycle? 
ad 1: Yes the CPU works. It cycles through it's address space and toggles A19 with 2 Hz.
ad 2: Yes, as i could tell the CPU works. :-)
ad 3: For curiosity: Yes. I believe that bus cycles and internal logic are completely separated and !VPA can be used for any bus cycle.

Next interesting question: Can i put videos in my blog? It seems i can, but for a final verification i probably have to publish this page.

Update: They are just converted into poor animated GIFs. I'll have to find something better... ok, uploaded them to youtube and embedded. back to the roots...


Free Run using !DTACK-terminated bus cycles
To the left is the 68008 on my bread board and wired up to us !DTACK to terminate bus cycles. !DTACK is permanently low (active) and the CPU runs as fast as it can: At 8 MHz it does 2 opcode fetches per µsec or 2,000,000 opcode fetches per second. As the whole address space of the 68008 is 1 MB only, it cycles through it's address space 2 times a second. The most significant address bit A19 should blink with 2 Hz. A19 is the leftmost LED in the video and i hope you can verify that it blinks with 2 Hz. Thanks.

An important result is that the 68008 actually works without deactivating !DTACK after each bus cycle. Though in all timing diagrams bus cycles start with !DTACK high it is actually possible to keep it low the whole time.


Free Run using !VPA-terminated bus cycles
In the second video i used !VPA to terminate the bus cycles instead. This mode is intended to access old (really old!) 6800 peripherals but it seems true that you can terminate any bus cycle with !VPA, even an opcode fetch cycle. It's just slower. I was curious how slow actually, if every bus cycle uses !VPA, because the 68008 data sheet say it can be from 11 to 18 clock cycles long.

Actually the M68000 8-/16-/32-Bit Microprocessors User’s Manual Ninth Edition says 10 to 19 cycles, while the M68000 Family Reference Manual – MC68008 Technical Summary says 11 to 18 cycles.


Buggy timing diagram for the 'best case' !VPA-terminated bus cycle
The latter puzzled me, because of course i started with the 68008 documentation, because that's the CPU i'm using, and i was wondering how fast the 68008 could uninterruptedly access the bus using the !VPA mode as 11 cycles is slower than the period of the free running E signal to which !VPA bus cycles are synchronized. But 10 to 19 makes sense (while 11 to 18 makes not) and i found an unnamed cycle in the 68008 manual's 'best case' chart (between the last 'w' cycle and 'S5') and i believe that someone reviewed the charts, found that the 'worst case' chart was only 18 cycles instead of 19 cycles long, demanded a correction and the missing cycle was added ... to the wrong chart. That's how real world works.

In the second video one bus cycle takes 10 clock cycles instead of 4 and therefore A19 should blink with 2 Hz *4 / 10 = 0.8 Hz instead. I think this approximately true.

In my project the !VPA bus cycle is used to access slow peripherals on the K1 bus. But it is also used during interrupt acknowledge, in order to use an auto vectored interrupt. Now the interesting question is: Does the CPU actually perform a !VPA controlled bus cycle here or a dummy cycle, as it ignores the byte read?


!VPA used in interrupt vector read cycle
My guess was, that it actually does a !VPA controlled slow bus cycle if you activate !VPA, making interrupts approximately 10 clock cycles slower. And finally i found this chart on the last (!) page of the M68000 8-/16-/32-Bit Microprocessors User’s Manual Ninth Edition. The last pages are appendix B which is about interfacing 6800 devices and which are pasted into the document as bitmaps only. :-)

The bus interface performs a slow memory cycle in the (dummy) interrupt vector read cycle if !VPA is activated to request an auto vector interrupt.











2014-01-19

68008 SRAM Microcomputer – Unused 2-to-4 Line Decoder Got a Job!

browsing through some other 68008 projects in the web
i was reminded to the fact, that the 68000 has something called short addressing: Instead of supplying a 4-byte long address you only supply a 2-byte short address which is sign-extended to 4 bytes. This saves space in program code and – more important – up to 8 CPU clock cycles. So i took a look at my current address layout:

v0.2 address decoder

This allows the first 32k of RAM to be accessed with short addressing as well as the slow I/O address range, but not the fast I/O range:
  • %xxxxxxxx,xxxx00xx,xxxxxxxx,xxxxxxxx selects RAM and
    %00000000,00000000,0xxxxxxx,xxxxxxxx is a possible subset of this which fit's in a signed word.
  • %xxxxxxxx,xxxx01xx,xxxxxxxx,xxxxxxxx selects ROM and can never be accessed with short addressing.
  • %xxxxxxxx,xxxx11xx,xxxxxxxx,xxxxxxxx selects slow I/O and
    %11111111,11111111,1xxxxxxx,xxxxxxxx is a possible subset of this which fit's in a signed word as a negative value.
  • %xxxxxxxx,xxxx10xx,xxxxxxxx,xxxxxxxx selects fast I/O and can never be accessed with short addressing.
In order to make all I/O short addressable, all I/O must have A31 .. A15 high. A18 cannot be used to select between slow and fast I/O. The first Address line which can be used for that is A14:

v0.3 address decoder

Now the memory map is as follows:
  • %xxxxxxxx,xxxx00xx,xxxxxxxx,xxxxxxxx selects RAM and
    %00000000,00000000,0xxxxxxx,xxxxxxxx is a short addressable subset.
  • %xxxxxxxx,xxxx01xx,xxxxxxxx,xxxxxxxx selects ROM (no short addressable subset).
  • %xxxxxxxx,xxxx1xxx,x1xxxxxx,xxxxxxxx selects slow I/O and
    %11111111,11111111,11xxxxxx,xxxxxxxx is a short addressable subset.
  • %xxxxxxxx,xxxx1xxx,x0xxxxxx,xxxxxxxx selects fast I/O and
    %11111111,11111111,10xxxxxx,xxxxxxxx is a short addressable subset.
There is no need to apply the post-reset INIT line pull-up to A14 for the I/O address decoder and there is no need to strobe the outputs with !AS because the I/O control lines are strobed by !AS directly at the 74HC138 which generates them (see other sheet – next to come :-)). It's even better this way because now !SLOW_IO which is directly connected to the CPU's !VPA input to request slow I/O or an auto vector toggles before !AS is valid and not shortly thereafter.

Funny Note

Actually this second 2-to-4 line decoder could be replaced entirely by one NAND gate: !FAST_IO is not used anywhere (actually it is currently used to reset the INIT line, but this could have been !SLOW_IO as well) and !SLOW_IO becomes low when A14 and A19 are both high, so, yes, that's a NAND function. The NAND gate would even be faster (the 74HCT139 is pretty slow) but – i don't have a spare NAND gate, but i had a spare 2-to-4 line decoder. :-)


2014-01-18

68008 SRAM Microcomputer – Reset circuit (Updated)

Now to something very simple which i always have problems with: The reset circuit. It's only made from few parts but it's ANALOGOUS. (shiver!)

Let's start with the requirements: 

For unknown reasons the 68008 CPU needs an excessively long reset pulse after power-up: 0.1 seconds! Because there are other circuits which may pull !RESET low, most namely the CPU itself, !RESET must be driven with an open collector or open drain output.

To the right is an image of the current circuit:

Let's discuss it. 
This is very important because it's analogous and most times my analogous stuff doesn't work. :-/

Start with R9 + R4 and ignore the rest: These two resistors form a voltage divider for Vcc and the voltage in the middle is 2.5V. (5V/2)

Now add the capacitor: Initially it is discharged and behaves like a piece of wire. But as time goes by and current flows through it (and through the voltage divider) it charges and voltage across it increases which subtracts from the voltage present at the voltage divider. So the middle voltage of the voltage divider starts at 2.5V and drops over time to zero.

Next add transistor T1: The first effect is that the middle voltage is shorted by the base-emitter diode of T1 to ground, so the middle voltage is initially 0.7V, which is the break-through voltage of the diode, stays at that voltage for a while until it drops below 0.7V and resumes dropping as with no transistor present.

While there is current sinked through the base-emitter diode, the transistor switches on, sinking the !RESET line to ground. As soon as the base-emitter voltage drops below 0.7V the transistor will switch off and !RESET rises to Vcc. We only have to choose the capacitance and the resistors appropriately, so that this will happen after approximately 0.1 second.

But that's only half of the story: The transistor is not switched on or off depending on the voltage at it's base pin, instead the amount of current it can sink is a function of the current through the base-emitter diode. While this diode keeps the voltage at the base pin at 0.7V, the current through the diode needed to do this decreases as the voltage at the voltage divider decreases. So at some point in time the transistor is no longer fully able to sink all current from the !RESET line but only a part of it and the voltage on the !RESET line will not switch instantaneous to Vcc but will rise slowly.

This is totally unreliable. !RESET must go away very fast, ideally within one CPU clock cycle. This is where T2 and it's two associated resistors enter the game: While !RESET is low T2 is switched off and the circuit behaves as if T2 wasn't there. But when !RESET slowly rises above 0.7V T2 will start to sink current. This will subtract from the base current of T1 which will in return sink less current from the !RESET line and the voltage on the !RESET line rises even more which will open T2 more which will ... Yes, a positive feedback and !RESET will rise very fast once it has reached 0.7V.

Now let's examine power-up and power-down behavior.

At power-up C1 is empty. But the state of the !RESET line is unknown. If it rises with Vcc then T2 will be open right from the start and may finish the reset pulse before it has been activated at all. It's very likely that it will do this because of the pull-up resistor on the !RESET line. To prevent this the voltage at the base of T1 must be asserted to be clearly above 0.7V when C1 is empty: This is true with the given values for R4, R9 and R12 (all 50kΩ) because when C1 is empty the voltage at the voltage divider will be 1/3 Vcc which is approximately 1.65V and which will be sinked through the base-emitter diode of T1, opening T1 which will pull !RESET low. Check.✓

After a while capacitor C1 is loaded (nearly) to Vcc and the input of the voltage divider is Vcc minus Vcap which is (nearly) 0V. When power is switched off, Vcc drops to 0V but the capacitor is still loaded, so the voltage at the voltage divider drops to -Vcc. We'll have to check the circuit that this does no harm. Check.✓

Now the capacitor must be discharged, so that it is discharged when power is switched on again. This happens through the voltage divider R4+R9 in approximately the same time as was required to load the capacitor after power-on. Check.✓

Last step: calculate the values.

!RESET is pulled up by a 5kΩ resistor which sources 1mA at Vcc=5V and there is some more circuitry attached, so let's say T1 must sink 5mA.

T1 may have a current amplification of 100 (this is a value which widely varies even for transistors of the same type) so the base-emitter current of T1 must be ~ 0.05mA.

This current must be sinked through the base-emitter diode of T1 even after C1 has charged to – let's say – 1/2 and the remaining voltage at the voltage divider is 2.5V. This leaves a voltage drop of ~2V across R9. Using the formula U=R*I <=> U/I=R we calculate the value for R9 = 2/0.05e-3 = 40kΩ.

Next the capacitor voltage must rise 2.5V (see above) during 0.1s while being loaded with 0.05mA. The formula for the capacitance is: C = I*t/U. So C1 = 0.05e-3*0.1/2.5 = 2µF. Because the calculation is very rough (actually we ignore R4 which sinks some current as well and we should integrate the current over time because it's not const) so we double the capacitance. Fine adjustments will be made when it is built on the bread board. :-)

Note: You didn't remember the formula for the capacitance? Using ISO units (not inch, miles and gallons) you don't need to look up the formula, you can construct it by pure logics:

The capacitance depends on

  • Charging current: higher current => higher capacitance => C ~ I
  • Charging time: Current supplied for longer time => higher capacitance => C ~ t
  • Voltage increase during charging time: Higher voltage increase allowed => less capacitance required => C ~ 1/U
  • Using ISO units there will be no constant factor in the formula. Yeah!
  • therefore: C = I * t / U.
Alternatives

We could use a timer IC for the reset circuit, most likely a 555. But this would have a larger footprint than the discrete solution. Else we could use a mono-flop from the 74 series. But basically this increases the footprint even more (14 pin DIP instead of 8 pin DIP).

Or use a counter. But even if fed from the E output of the CPU (which is CLK/10) we'd need to count up to 100,000 for 0.1 seconds which is impractical.

I have also seen using a PIC for reset (basically because the project used a PIC for various control purposes) but using a CPU to generate the reset pulse for a CPU is a little bit ... over designed.


Update: Reset Circuit Test on the Bread Board

Today i tested the circuit and as expected it did not work as expected. Let's see why. For your convenience to the right is another image of the circuit.

As discussed above resistor R12 must be high enough so that T1 actually switches on at power-up.

Full flip requirement:

But there's another requirement for R12: It must be able to sink the whole current which flew through the base-emitter diode of T1 when T2 switches on. Else there will be some base current left at T1 and it will not fully close and therefore the voltage at the reset line will not fully rise to +5V.

To estimate this current is a little bit tricky: It depends on the pull-up current on the reset line and the transistor's current amplification. Worst case is high pull-up current and low current amplification:

• ICE = 5 mA
• hFE = 100

=> IBE ≥ 5mA/100 = 50µA

R12 ≤ UR12 / IR12 = (0.65V-0.2V) / 50µA = 9kΩ

where 0.65V = break-through voltage UBE of the transistor's base-emitter diode
and 0.2V = saturation voltage UCE between collector and emitter.

So R12 must be at most 9kΩ to ensure a full flip when T2 opens.

Power-up requirement:

Immediately after power-on we require that T1 opens, even if T2 is also open due to the pull-up resistor on the reset line. For practical reason we assume C1 not completely empty but discharged to 1V, which leaves 4V at R9. So the current across R9 is:

IR9 = (4V-0.65V) / 50kΩ = 67µA

where 0.65V = break-through voltage UBE of the transistor's base-emitter diode

This current now flows through R4, R12 and T1:

IR4 = 0.65V / 50kΩ = 13µA
IBE ≥ 50µA
IR12 ≤ (67µA-13µA-50µA) = 4µA
R12 ≥ (0.65V-0.2V) / 4µA = 112.5kΩ

where 0.65V = break-through voltage UBE of the transistor's base-emitter diode
and 0.2V = saturation voltage UCE between collector and emitter.

So R12 must be at least 112.5kΩ to ensure that T1 is initially open at power-up even if T2 is open.

Gotcha! We're trapped!

Can we solve this?

First, we were calculating with worst-case values. We could require better worst cases. Second, we can adjust R4.

Power-up requirement with new R4 value:

R4 is used to make the circuit a bit independent of the current amplification of T1 and of the pull-up current on the reset line and it is needed to discharge C1 when power is off. We can't remove it entirely but we could double it's value which will half the current through it and redo the above calculations:

IR4 = 0.65 / 100kΩ = 6.5µA
IBE ≥ 50µA
IR12 ≤ (67µA-6.5µA-50µA) = 10.5µA
R12 ≥ (0.65V-0.2V) / 10.5µA = 43kΩ

Now R12 must be at least 43kΩ to ensure that T1 is initially open at power-up even if T2 is open. Much better. :-)

Full flip requirement with reduced maximum pull-up current on the reset line:

The other two screws are the current amplification of T1 and the pull-up current on the reset line.

The allowed pull-up current was defined as 5mA which means a pull-up resistor as low as 1kΩ. Let's reduce this to 2.5mA which is still much more than we expect, because the actually used value is 5kΩ, but there may be some current added from the attached devices, though this should be negligible. Let's redo the calculations:

IBE ≥ 2.5mA/100 = 25µA

R12 ≤ UR12 / IR12 = (0.65V-0.2V) / 25µA = 18kΩ

So R12 must be at most 18kΩ to ensure a full flip when T2 opens.

Power-up requirement with reduced maximum pull-up current on the reset line:

IR4 = 0.65 / 100kΩ = 6.5µA
IR12 ≤ (67µA-6.5µA-25µA) = 35.5µA
R12 ≥ (0.65V-0.2V) / 35.5µA = 12.75kΩ

So R12 must be at least 12.75kΩ to ensure that T1 is initially open at power-up even if T2 is open.

Both requirements are met if we use 15kΩ for R12. Fine. :-)

Reset circuit with validated resistor values
To the left is the updated reset circuit as tested on the bread board. Actually i had still problems with the power-up reset if C1 was not completely empty, but that was due to a LED which i connected to the reset line to show it's state. It had clearly more than 5mA. :-)