Welcome to my retro computer (single board Z80) playground. My goal is to make the smallest possible single board Z80 computer (cpu, rom, ram, serial I/O) that permits me to experiment with Z80 assembler, some of the Z80 cpu pins like ~wait and ~reset, etc.
My design phase has multiple iterative steps. The first step is drawing the circuit schematics of a Z80 single board computer as I think it should be. During the following steps, I eliminate all the hardware features that I estimate unnecessary for this board, I replace the IC's that are hard to obtain where I live, and the elements that are too complex for a first PCB. After all, I'd like to outsource the creation of the PCB to OSH Park, and even though they charge only $5 per square inch, a PCB order comes in the order of $30-$40 when I shrink everything down as much as possible. Please do take into account that I'm not a professional with tens of years of experience in PCB design.
The last version of the files, including the kiCad schematic and PCB design can be found in my GitHub repository https://github.com/PaintedBlck/Z80-nanocomputer-with-AVR-buscontroller
This project is not a stand-alone occupation, but a preparation for a larger project that I plan to do with a Z80 CPU and with some suited peripherals. So, this Nanocomputer project is in the mean time a very good testcase to get a grip on the Z80 and the accompanying technology. Whatever the outcome of this Nanocomputer project is, it will teach me the things I need to know later on.
The first schematic that I've designed is the following. You can click on the image to get a larger version in PDF format. The following characteristics have been foreseen:
The second schematic already limits the functionality and the logic. More specific:
The third schematic is the final version. This version only contains 4 IC's:
The circuit is further reduced by making the following choices:
Since my goal is to go all the way and make a PCB of the third design, extra checking of the circuit is important. Not only the connections have to be ok, but the circuitry and possibilities of the AtMega have to be tested. Especially the AtMega reset circuit has to be conform to the production specifications of Atmel. On top of that, I like to test if the AtMega can generate a block clockwave of sufficient quality to keep the Z80 going.
An other software question that rises is the possibility to do a hardware reset of the Z80 and a software reset of the AtMega with a single push button. If that's possible, no extra reset button is required for the AtMega, making a full system reset a lot more elegant. The theoretical approach to this is using the brown out detection (BOD) of the AtMega. If the AtMega processor is out for a number of milliseconds (disabled one way or the other), a restart is done by the BOD. When disabling interrupts and going in an eternal loop, a restart should be done by the BOD also. This means that, if all goes well, and a button push is captured by an arbitrary chosen pin of the AtMega, bouncing effects can be eliminated by a software routine, should this be necessary. At that moment, a reset signal can be send to the Z80 and finally, the AtMega can be forced in an uninterruptible eternal loop so that the BOD will force the AtMega to restart also. Making sure that the AtMega doesn't restart the Z80 for a second time during the AtMega startup has to be taken care of during software development.
Last but not least, interrupt driven serial I/O must be combined with software address control logic for the Z80 and the memory, and with 4Mhz clock division and/or generation for the Z80. It looks like a number of functionalities will be so demanding that they will have to be written in assembler. However, the first software development will be done in a higher level language. Only if things turn out for the worst (functional or performance), assembler will be an option.
The PCB design is finalised after some initial errors (like a wrong estimation of the size of the EEPROM and SRAM IC's). Design rules checking (DRC) seems not to give any errors. The actual PCB can be found by clicking on the image to the right of this text.
The next step is to verify again if all components have the right size on the PCB (to be on the safe side). I have also cleaned up the traces to give the board a more structured view. Note that the VCC and the GND pins are not connected to paths, since the non-used space on the board is filled with GND on the top layer, and with VCC on the bottom layer. So the pins in question connect straight to these filled zones.
The design rules I've used for this prototype are
These design rules are fine for most of the PCB sellers. The choice of color depends on the PCB seller, as do the prices. But on general, one can find what one needs for a reasonable price on internet (especially if it's only for prototyping).
Finally, I can order my prototype PCB's. I'll have to make a userid at OSH Park. The way to deliver information to PCB sellers about the created PCB is variable in the sense that some accept KiCad PCB files, others accept only Gerber files that are given a specific name. Care should be taken not to make mistakes during the creation of the Gerber files, since this can lead to wrong PCB's, or at least (with companies that take the effort to check the Gerber files) to longer order delays. Since OSH Park accepts my KiCad PCB file, I'm safe on that point. However, they seem to have a problem with the connection points of the barrel jack at the top left of the PCB. I have decided to go through with this design and do some drilling myself on the prototype boards.
I have received a more realistic preview of what the PCB board will look like. I have checked all elements that can be verified, and everything looks ok. Can't wait to receive the actual boards.
The PCB's have arrived and are ready for testing. First, I've tested the PCB without any components on it, to see if all contact points, drill holes and tracks are doing what they are supposed to do. Then I've installed the components (apart from the IC's) on the PCB to test the circuitry of the passive components...
And of course, I've made a beginners mistake. The goal was to provide 5V stable power from an external power supply. And what does the schematic contain? A diode. And what does a diode has as side effect? It has a power drop voltage... So I've desoldered the D1 diode and replaced it with a wire bridge. Since the Zener diode also had it's consequences on the power supply to the IC's, I've eliminated that one too (both can be skipped on the BOM). That will give me enough space on the production version of my PCB to put a led/resistor in place that will show me if the board is powered, or to put a 6 pin debugWire connection to reprogram/debug the AtMega without removing it from the board.
A high-voltage programmer for the 40-pins AtMega is also a necessity, since otherwise, my stock of AtMega's will be used within a couple of hours. The experience with my AtMega328's in previous projects has shown this clearly.
I've chosen to use the AtMega HVPP FuseBit Doctor. OshPark offers the possibility to order the PCB. After assembling the programmer, it takes some effort to understand the functioning of the HVPP, since the PCB is not exactly the most trivial to 'read'. For instance: there is a serial TTL port, but you have to figure out what the GND, TX and RX pins are. But once you're on a roll, it' smooth sailing.
It's not necessary to have a serial terminal connection between the HVPP and your pc, but it facilitates things a lot to my opinion. To make the serial connection, I use PuTTY and the Adafruit USB to TTL Console Cable. The lead connections and the settings in PuTTY are the following:
USB to TTL Console Cable leads: Red: Provides 5V (MAX 500mA) Black: GND (pin besides transistor) White: TXD on the HVPP (middel pin) Green: RXD on the HVPP (pin closest to the Start button) Terminal settings: Baudrate: 4800 Parity: none Databits: 8 Stopbits: 1 Handshake: none
The HVPP is able to set and reset a plethora of Atmel chips. Further information can be found on the website.
Programming the 40-pins AtMega will be done by using a home-made circuit on a perf-board. And that's the next thing I'll do. The circuit will be as minimalist as possible. Only the bare necessity to make programming possible and comfortable will be added. See software challenge 1 for more detailed information on what I count placing on the board.
There is one small point of attention when making a programming board for a 40-pins AtMega, and that is that these IC's don't use the debugWire protocol/header but the AVR JTAG protocol/header. That's not a major issue. In fact, it's rather a nice feature, since Atmel Studio and the Atmel ICE programmer seem to work flawless with JTAG, which can't be said of debugWire.
Since Atmel ICE comes with a JTAG cable with 10 x 100-mil female sockets, I was free to choose the pinout that suited my 'design'. I chose for a 1 x 10 male pin header. Besides this header, I also chose to put a 2 x 3 male pin header for SPI purposes. This header permits the use of an other Atmel ICE cable to program the AtMega. However, with the SPI header, debugging is not possible.
As I was using the Adafruit USB to TTL Console Cable with the AtMega HVPP FuseBit Doctor anyway, I opted to use a 1 x 4 male pin header to connect my AtMega programmer to the PuTTY on my pc. In the mean time, this permitted me to draw 500mA out of the USB power supply for my board. This board stays nicely within that power limit.
Last but not least, I've added a LED to signal if power is available, and two 1 x 20 male pin headers as a breakout for the 40 AtMega pins. These headers will permit me to give input signals or to read output signals with a protocol analyser. Note that the Rx and Tx pins of the 1 x 4 header to the USB are also the breakout pins 14 and 15. The SPI and the JTAG headers are also partly redundant with some of the breakout pins.
While I was waiting for the prototype boards, I had planned to:
In short, the next two weeks would be all about 'testing development environments' and 'developing AtMega32 software'.
Challenge 1 Before testing how the AtMega behaves with the intended workload, one should be able to program it. The first idea was to work with an AtMega programmer and an USBasp device. Therefore, an 'external tool' has to be added to Atmel Studio.
Tools menu, one can click on
In my case, I entered the following information in the external tools dialog box:
Title: USBasp Command: C:\Program Files (x86)\Arduino\hardware\tools\avr\bin\avrdude.exe Arguments: -c USBasp -C "C:\Program Files (x86)\Arduino\hardware\arduino\avr\bootloaders\gemma\avrdude.conf" -p atmega32 -P USB -B12 -U flash:w:$(ProjectDir)Debug\$(ItemFileName).hex:i
Unfortunately, when trying to do some development, it seemed that Atmel Studio was not able (understandably) to go into debugging mode for the setup in question. So that was that. I could develop without debugging possibilities and output data using only some led's, an oscilloscope and/or a protocol analyser, or I could find an other solution.
The solution I've found is the development of an own AtMega board, as I have already build for my AtMega328p's and for my AtTiny85's. This board connects Atmel Studio to an ATMEL-ICE programmer through an SPI connection. This works like a charm for the 328 and the 85 (well, it did some time ago anyway), so hopes are high that it will also work for the AtMega32. Just for information, I join a schematic and some pictures of my AtMega board for the 328 and the 85 on the right. Note that the reset button is disabled by removing the jumper, otherwise, the Atmel ICE can't use its debugWire features. Note also that the 40-pins AtMega programming board will be more limited in the sence that there will be no flexibel power supply (only 5V) no jumpers, only one led (to show if power is on or of), and no reset button (only a pullup register). Further more, I'll have to look if I need an external crystal or if I can do the programming of the AtMega using it's internal clock. So, on the whole, it would be a barrel jack power supply, one led, a dip-40 15.24mm or even better, a zif socket, a 6 pin SPI interface, one decoupling capacitor, maybe a crystal and some breakout connectors.
The above, however, took me so much time that my other goals didn't make it on the agenda. And on top of that, I had the bad luck to brick 4 AtMega328's while trying to remember what the Atmel Studio development and debug steps were. My AtMega328 High Voltage Programmer has really earned back its cost big time!
Since my stock of 40-pins AtMega's is rather limited, I can't afford to brick my test IC's. Therefore, I've ordered a DIY High Voltage Programmer to debrick (reset the fuses) of a 40-pins AtMega (see the hardware part higher on this page for more information). In the mean time, I'll continue to play around with Atmel Studio and some AtMega328's or AtTiny85's until developing and debugging AVR IC's will no longer end up with bricked IC's.
Challenge 2 will be looking into the speed of an AtMega32. Is this chip, clocked at 20Mhz, able to do all that I expect of it? More specific:
From now on, I will place the latest version of my code below this text. The date of the code is on top in the comment block, so it will be easy for the reader to see if things have changed. Note that, as the comments say, the goal of this code is not to win a beauty contest, but to live up to the expectations of minimal clock cycle use per activity. Therefore, some compromises are necessary, not in the least on the domain of splitting up the code in functions and subfunctions. Each interrupt, each jump, each call takes time that can be spent to more usefull activities.
Since it is clear that in the end, assembly will be the preferred language, I have decided not to use C at all. So I started a new Atmel Studio project, bricked my AtMega again several times before the entire configuration was stable and started to create a canvas in assembly. I count on programming kind of structured in the beginning, and decide afterwards where I have to give up the structure in favor of speed.
My first idea was: "Since the AtMega328 and the AtMega32 are very similar, I can do my testing with an AtMega328 @ 16Mhz external clock. If I can do what I want to do with this setup, there will be no problem with the AtMega32 @ 20Mhz external clock". However, after developing the Z80 Clk signal routine, I decided to switch from programming a real device to using the Atmel Studio Simulator for the initial development. It's a lot less hassle with cables, programmers, power supplies and it's less error prone during debugging.
In the previous versions of Atmel Studio, the simulator had a number of annoying bugs that seem to be solved in the actual version. So, after a first version of the assembly code for the AtMega328, I've changed to a version for the AtMega32.
An other advantage of the Atmel Studio Simulator is that there is an option to simulate the external clock frequency, including a cycle counter and a stop watch. These two together will permit me to do effective simulations and to draw a first indicative timing diagram of the functionalities that I have to develop.
The use of Atmel Studio Simulator tought me that the AtMega32 has a number of disadvantages. The most remarkable are the lack of possibility to trigger an interrupt when digital input pins toggle state, and that its second 8-bit timer only has one channel and hence other names for programming its ports. So I switched, after looking into the datasheets, to an AtMega644p. This one seems to be more compliant with the AtMega328 and doesn't has the disadvantages of the AtMega32. On top of that, the AtMega644p exists in an AtMega644p-20pu version (20Mhz clock) and has 64Kb of Flash memory. The latter could be very usefull if I decide to use the AtMega not only as a utility IC but also in replacement of the EEPROM to potential reduction of the PCB size with 1 dip40.
An element that can be interesting to the reader is the fact that Atmel Studio has the possibility to simulate (they call it stimulate) incoming pin signals when working with the simulator. It takes at most 10 minutes of reading and you're using stimuli files. A simple example is the development of the ~MREQ/~IORQ interrupt routine. In order to simulate changing incoming signals on the respective ~MREQ and the ~IORQ pins, I used the following stim file To activate it, you run your program in debug mode in Atmel Studio, and set a break point. When the debugger stops at the break point, go in the debug menu, and choose the Set Stimulifile option, if you haven't done that already. You can choose a stim file to run. Then go in the debug menu again, and choose the Execute Stimulifile option. When you hit Continu (F5), the stim file commands are executed. In the described case, the program jumps in the interrupt routine due to simulated changes in the incoming ~MREQ and ~IORQ signals.
I use several stim files to help me debugging different parts of my program, and others to check if the quality of my code stays the same. One example is the following:
Printable version of this source
The Atmel Studio Simulator has brought me as far as it can go. Now I have to develop the serial communication routines to connect the AtMega with a pc terminal simulator. And therefore, I need the real McCoy. After finishing and testing my perfboard 40-pins AtMega programmer and assembling a HVPP Fuse Bit Programmer (see hardware part of this text), I now have everything in place to focus entirely on the programming of the real AtMega644 anyway. So that's what I will be doing for the next weeks. First, I'll try to make some progress in the functional domain. Afterward, I'll start profiling and timing the code to make it gradually faster and probably, as a consequence, less structured and readable.
I finally found time to do a thourough measuring of all the signals generated by the Atmega644 utility chip. I also found time to make a quick and dirty implementation of the serial I/O provided by the Atmega644.
Below, one finds the last clean version (version without the quick and dirty serial IO) of the assembly program AtMega644.asm as it is used in the AtMega644 utility chip. As far as I have tested the code, it does what it is supposed to do, albeit with some major drawbacks.
Printable version of this source
I'm now convinced that putting the burdon of clock generation, adressing logic and serial I/O on one Atmega644 chip is a bit to much to ask. Even programmed in assembly, the poor Atmega644 is overcharged and unable to cope.
The general conclusions of further testing of this Z80 nano computer are that not all my goals can be met when I want the Z80 to run at a suitable speed. More specific, I come to the following conclusions for this first Z80 Nano prototype:
In short: The first update of the Z80 Nano design will have to correct the schematic. I also have to replace the Atmega chip by an FPGA if I want to keep all requirements on one 'programmable' chip, be it with VHDL in stead of a general programming language. The alternative is to put clocking and adressing logic in hardware, and possibly replace the Atmega644 with a smaller Atmega that only handles the serial I/O (in hardware or with a software library).
If only handling the serial I/O will be required in a programmable chip, it will not be necessary to us an FPGA, nor to keep programming in assembly. Ordinary C, or even the use of the Arduino IDE objects will be possible, making the development of the I/O module a lot faster and more flexible.