Tuesday, 11 February 2014

42. Working with the 74193 - 4 bit binary up/down counter.

The 74193 is quite a useful IC to have in your collection.  It can count up or down in binary from 0000 to 1111.  You can reset the value to zero, you can pre-set the start value (useful as a buffer when not used as a counter) and if you count above or below the four bits it can flag a carry or borrow condition. This last bit is quite important as it means you can daisy chain lots of 74193s together to count with 8, 12, 16 bits and so on.

The pins are:

16 Vcc        Input Voltage
 8 GND        Ground

15 A      IN  Input Bit 0
 1 B      IN  Input Bit 1
10 C      IN  Input Bit 2
 9 D      IN  Input Bit 3

11 LOAD   IN  Load Inputs   - Inactive state HIGH.  Go LOW/HIGH to load inputs.

 3 QA     OUT Output Bit 0
 2 QB     OUT Output Bit 1
 6 QC     OUT Output Bit 2
 7 QD     OUT Output Bit 3

14 CLEAR  IN  Reset Outputs - Inactive State LOW.  Go HIGH/LOW to reset.

 4 DOWN   IN  Count Down    - Inactive state HIGH.  Go LOW/HIGH to count down.
 5 UP     IN  Count Up      - Inactive State HIGH.  Go LOW/HIGH to count up.

13 BORROW OUT Count has gone below 0000.  Connect this to DOWN of IC below.
12 CARRY  OUT Count has gone above 1111.  Connect this to UP of IC above.

In this example below I have daisy chained 3x Philips 74HC193Ns together to produce a 12 bit value:



The red jump wires are connected to the UP input. Initially from an Arduino UNO providing a simple pulse with a 100ms delay, then from the CARRY to the UP of the next IC.

A/B/C/D and BORROW are not connected. LOAD and DOWN connected to +5V as I'm not going to load a value and I am not going to count down.

Just to show how this works I connect the outputs to some red LEDs followed by some inline 1K resistors (which are hidden behind the LEDs in the picture).

Using this method, these 3x 74193s create a 12 bit address line which could be used help program or read a 4K by 8 bit EEPROM.



Here's the Arduino code to pulse the 74193:
/*
  74193 Synchronous 4 bit binary up/down counter
*/

int RESET = 2;    // Connect to Pin 14 on the IC
int COUNT_UP = 3; // Connect to Pin  5 on the IC

void setup() {
  
  // Initialise Pins
  pinMode(RESET,OUTPUT);
  pinMode(COUNT_UP,OUTPUT);
  
  // Set default pin states
  digitalWrite(COUNT_UP,HIGH);
  digitalWrite(RESET,LOW);
  
  // Perform a reset.  Clears outputs to low state i.e. 0000
  digitalWrite(RESET,HIGH);
  digitalWrite(RESET,LOW);

}

void loop() {
  
  // Clock Up Pulse
  digitalWrite(COUNT_UP,LOW);
  digitalWrite(COUNT_UP,HIGH);
  delay(100);

}

Friday, 31 January 2014

41. PS/2 Keyboard Test

Now a computer is no good, unless you can type something into it.  Although it is possible to read a USB keyboard you need additional hardware if you are just using an Arduino UNO.  However there is an Arduino library for PS/2 Keyboards. I found it at http://www.pjrc.com/teensy/td_libs_PS2Keyboard.html.  You'll need to add it to the Arduino IDE Libraries. Click on Sketch->Import Library->Add Library...

All I needed now was a PS/2 Keyboard as all my keyboards are USB these days.  Fortunately they can still be found in plentiful supply at your favourite online stores.

Of course, with s PS/2 keyboard you need a PS/2 socket to plug it in.  I had an old motherboard and a hot air gun soon melted the solder to free it from the main board.  Now to make it breadboard friendly.

You only need 4 pins.  +5V, GND, Clock and Data.  See http://en.wikipedia.org/wiki/PS/2_port for details of the pin outs.  I used a continuity tester to check which pins underneath matched which ps/2 port inputs and soldered on four jump wires.



Using just the LiquidCrystal library and the PS2Keyboard library, I was able to write all over my 20x4 LCD display.

The PS2Keyboard library defaults to US layout doesnt have the UK layout defined so I might tweak that later.

Heres the code:
#include <LiquidCrystal.h>

#include <PS2Keyboard.h>

LiquidCrystal lcd(10,9,8,7,6,5,4);
PS2Keyboard keyboard;
const int DataPin = 3;
const int IRQpin =  2;

int row=1;
int col=0;

void setup() {
  // put your setup code here, to run once:
  delay(1000);
  keyboard.begin(DataPin, IRQpin);
  lcd.begin(20,4);
  lcd.print("Keyboard Test");
  //lcd.cursor();
  lcd.blink();
  lcd.setCursor(col,row);

}

void loop() {
  // put your main code here, to run repeatedly: 
  if (keyboard.available()) {
    
    // read the next key
    char c = keyboard.read();
    
    // check for some of the special keys
    if (c == PS2_ENTER) {
      col=0;
      row=row+1;
    } else if (c == PS2_ESC) {
      lcd.clear();  // clear screen if ESC is pressed.
      col=0;
      row=0;
    } else if (c == PS2_LEFTARROW) {
      col=col-1;
    } else if (c == PS2_RIGHTARROW) {
      col=col+1;
    } else if (c == PS2_UPARROW) {
      row=row-1;
    } else if (c == PS2_DOWNARROW) {
      row=row+1;
    } else if (c == PS2_DELETE) {
      col=col-1;
      lcd.setCursor(col,row);
      c=32;
      lcd.print(c);
      lcd.setCursor(col,row);
    } else {
      
      // otherwise, just print all normal characters
      lcd.print(c);
      col=col+1;
   }
   if (col>19) {
     col=0;
     row=row+1;
   }
   if (col<0) {
     col=19;
     row=row-1;
   }
   if (row>3) row=0;
   if (row<0) row=3;
  }
  lcd.setCursor(col,row);
}

Monday, 20 January 2014

40. A foray with I²C

It's been a while since I built something that didn't come in a kit.

I've had a RTC (Real Time Clock) chip (PCF8563) in my collection for a while as I wanted to get to grips with I²C.

I²C is a protocol for allowing ICs to communicate via a 2 wire interface.  One wire is the clock (SCL) and the other is the data (SDA).  This saves on the number of connections and also simplifies circuit design.

My early experiments writing bit bashing code on a PIC to speak I²C ended up fruitless and I thought I had missed some vital information.  Needless to say, it put me off for a bit.  I got other people's code to work on the PIC but I wanted to understand it because I thought it might be cool to get the Z80 to talk to a RTC.

However, the Arduino boards have a dedicated I²C interface and library code that makes it a piece of cake to get started.  So I dug out the PCF8563 and started coding.  Fortunately there was even code examples for Arduino using the PCF8563. Once you've seen how the code should be written its a lot easier to roll your own.

So I got the RTC clock wired up, and added my 16x2 LCD and in no time had a clock working.  It seemed a bit too easy, so I wondered what else I could connect to the I²C bus.  I found the DS1631 temperature/thermostat IC.

Each I²C device has a different address.  I don't know how unique they are as there are only 128 addresses available.  Bit 0 is used to signify read or write.  Luckily the RTC and Temp IC are different.

Needless to say it wasn't to hard to talk to the DS1631 as well using the Wire library and display the temperature.

To spice things up a bit more I wanted to divorce the ATMega328P from my Arduino Uno and put it directly on the breadboard.  This needed an additional 16MHz crystal and 2x 22pF capacitors.

Lastly a battery backup for the RTC clock which is quite easy to connect by using diodes to make sure the current goes in the right direction.

The software allows you (via the 2 buttons) to set the date and time and set a thermostat temperature, which when reached lights the red LED via a 1K resistor at the bottom.  In fact the DS1631 will operate on its own once configured to control a heating system.

Update: somehow the 1K resistor was a 47 ohm.  I noticed that when the thermostat temperature was reached and the LED lit up the temperature would go back up again.  It seems without much resistance on the output it causes the IC to warm up due to the current flow.  What I have done now it put a 10k resistor and fed that into a BC548B transistor to light the LED.


39. Time on my hands.

I bought this watch kit from Cool Components.  Easy to solder and assemble.  I realised afterwards that I could customize the PIC chip as the source code is available.   I prefer a 24 hour clock, and this is programmed just to display the 12 hour clock.  But its still a great watch and wearing it about at work has become a conversation piece.

Thursday, 3 January 2013

38. Nixie Clock with ZM1177 Tubes.

For Christmas, my wife bought me a ZM1177 Nixie QTC Clock kit from http://www.pvelectronics.co.uk

It took me all Saturday afternoon to make, mostly soldering and snipping wires. There was a bit of a mess up with the plexiglass case as I was sent 2 base parts and no top part with holes for the tubes.  However a quick email to the vendor and the correct part was mailed out straight away.  Excellent Service!

I also got the GPS option so the time is always right.

And here it is.....

Tuesday, 7 August 2012

37. Raspberry Pi Case.

Just got this case for my Raspberry Pi.  I got it from http://www.modmypi.com.  Its very good.  Fit is perfect, it doesn't rattle around in the case and the quality is very good too.  You can choose any colours you like and even mix and match top and bottom case colours.  The case clips together very solidly and comes with some stick on clear rubber feet. Well worth the money.

Friday, 3 August 2012

36. Apple 1 - Hello World!

It's been a while. I've been getting distracted by all things geeky. I thought I'd share this though.

I became curious by the Apple-1, the original must have Apple product, the Ford Model T of computers if you like.  All you got was a circuit board, but no keyboard or monitor (a bit like the raspberry Pi of its day).  I decided to look for an emulator for it, and at this stage knew nothing of the Apple-1's underpinnings.  It wasn't a Z80 but my old friend the 6502.  I've not touched the 6502 since secondary school when I used to play with the Commodore PET/CBM in the early 80's.

I got the Pom-1 emulator in Java flavor and downloaded the Apple-1 manual.

I soon realised that to program the Apple-1 you just entered 6502 machine codes and ran the machine code programs.  No BASIC interpreter (although there is a 6502 program for the Apple-1 that you can load in to get BASIC).  So I set about relearning 6502 machine language and so far my efforts have resulted in my first "Hello World!" program.

Here's a screenshot of the code and it running:


\ is the only screen indication that the Apple-1 is alive.  0.22 displays the first 23 bytes and R runs from address 0.

Why is this relevant?  Well this is something like what I want to build with the Z80

Sunday, 20 May 2012

35. Floppy Drive Music. Stage 1.

Ok well, I need to find time to understand the radio stuff, so I'm gonna park that for now and move on to Floopy Drive Music.  Ok yes, its been done before (as has most of the stuff I'm doing), but I haven't done it yet.

So what is floppy drive music?  Well by stepping the drive's motor at different speeds we can get different pitches from it.  Combine the different pitches and you get music.

I'm going to use the Arduino Uno to start with but I may program a PIC chip to do the same later.

After a bit of reading on the web, it seems the Arduino will not have enough power from the +5V supply to power the floppy drive.  Its recommended to use another power source.

So I have an old PC power supply handy which should do the job.  However, when its disconnected from its host PC's motherboard, its does nothing when plugged into the mains.  Fortunately you can fake this by shorting the PS_ON# pin to it's adjacent COM (see http://www.smpspowersupply.com/connectors-pinouts.html for pin details).

Of course using a PC PSU (Power Supply Unit) means it come with all the connectors to connect to the power pins of floppy drive, and andthing else you might want to plug in.

Pins connected, plugged in and powered on.  Fan on the PSU starts and floppy drive makes a short whirring noise.


Thursday, 12 April 2012

34. Diversion into radio.

The lack of any joy with the MSF signal has got me thinking about radio electronics. I connect a wire to CH1 on my Xprotolabs Oscilloscope because I remember getting random signals once before.

Here's watch I picked up.
Its very weak, the oscilloscope settings are at max resolution. Somewhere in there is probably the MSF signal.

Now while this is a divergence from the Z80 theme, I think its well worth looking into so improve my electronics knowledge as this is part if the journey.

So I learnt recently about transistors, and how they can amplify a signal. So lets amplify this and see what we can make of it...

Thursday, 5 April 2012

33. Radio Ga Ga

Rather than set the time myself, I thought I might be able to get the time signal from the Rugby Transmitter in the UK. Well its not in Rugby anymore but the name still sticks. Its in Anthorn in Cumbria and is called the MSF Signal transmitting on 60KHz. The National Physics Laboratory (NPL) give you all the details of how to decode the signal so all I need is a receiver.

I bought one from PV Electronics. It come with an antenna and a receiver module which sends a signal that you can simply connect to an IC and decode the message.

Well I get a signal, but not very well. Its anything I can use. I should get a pulse of varying length every second, but all I get are random on/offs. I have no way to tell if either the antenna or the receiver are faulty. I am assuming that I am not getting very good reception. It does get better when I point the antenna directly towards Anthorn, but still nothing useful.

Maybe I just need a bigger antenna, so I started reading about them so I could make one, and found that its not a simple subject. Check this out: http://www.antenna-theory.com/ My brain hurts!

A glimmer of hope though, it turns out that MSF was turned off from 26/03/2012 until today. Alas no, still a random signal.

Saturday, 3 March 2012

32. PIC Clock - Tic 2

I wanted to see how far I could push the clock idea by adding two more dual 7 segment displays to add seconds and information. This meant controlling 8 transistors, however with all pins on the PIC16F505 used up from the last version I had to come up with a way to control 8 digits from 4 pins. Well as it happens, using binary, 3 pins are enough to control 8 outputs. Binary 000 to 111 is 8 different values.

Now as luck would have it, there is such a thing as an 8 bit decoder controlled by 3 inputs in the guise of a 74LS238. There are many manufacturers and I used an M74HC238B1 from ST Microelectronics. Its does exactly the same thing.

Using 1 less pin to control the 8 digits means I have a pin left over. This gives me an extra button to control the functions of the clock. I have yet to program these in but the its all wired up ready. All you can do is increase the minutes as before. The day was hardcoded so it always says SA for Saturday.

I programmed in the entire alphabet (well as best you can with a 7 segment display as M,W,K,Q and X are not ideal) and this means I can display the day (Mo, Tu, We etc.), mode (AL for alarm, Yr for year etc.) amongst other uses I have yet to conjour.

Here is it displaying Saturday 10:39 and 41 seconds.


With the additional displays there is a noticeable flicker as each one is updated and this is because the delay between refreshing each digit has doubled from 4x4ms to 8x4ms. I've not addressed this as its not that bad. Using a faster external oscillator is one option but all pins on the PIC are used so the alternatives are to halve the prescaler for TMR0 or use a different PIC with a faster internal oscillator.

Saturday, 18 February 2012

31. PIC Controlled Digital Clock.

Following on from my new found friend the transistor, I had the idea to use four of them to switch on four 7 segment LED displays. Using 7 outputs from the PIC16F505 to control the segments a,b,c,d,e,f & g, another 4 outputs would switch each digit on in sequence. As it would be very fast you would see all digits on.

This I realised would make a good clock project.

With the PIC16F505 there are 14 pins, one for VCC on for GND and 12 can be used for I/O, 4 for controlling each 7 segment display, 7 for the individual segments and 1 to act as a time adjustment input. One of the pins can only be an input but all the others are bi-directional if needed so the input only pin was assign for the clock adjustment.

Something to bare in mind when writing code for a clock is that you must keep refreshing the display. Its no good writing the time out then waiting for a minute because all you will see is the last digit. You have to keep writing over and over to fool the eye into seeing a continuous display. In order to do this you must sync the time between displaying each digit. The internal clock runs at 4MHz and the internal timer (TMR0) is incremented on each instruction cycle which is made of 4 clock pulses. Effectively then the timer is 1/4 of the clock i.e 1MHz. By setting the PIC prescaler to 1:32 (dividing the timer by 32), you have time to run code to display one digit and wait for 125 tics at 1MHz/32/125 which makes 4ms. So the time between displaying each digit is 4ms. Keeping a count of the 4ms increments, when we reach 250 we have 1 second. Keep a count of the seconds and you then have your minutes.

The prescaler effectively tells you how many instructions can be executed between TMR0 tics so at 1:32 it equates to 32 instructions. The whole of my PIC program is 163 instructions (163 12bit bytes). We wait for 125 lots of 32 instructions before we increment the 4ms counter and move onto the next digit. What I am trying to point out here is that TMR0 may have ticked over a few times before you reach the checking loop.

One last timing issue is how to check for the clock-set button being pressed. This also needs to be done between each digit and allow the minutes to incremented reasonable quickly to set the time. This can be done by checking bit 5 of the 4ms counter, if set then check the input line and if that's set then increment the minutes.

Here some of the timing code that sits between each digit being displayed to show you how I've done it:

; time synchronisation
wait      movf   TMR0,W    ; get timer  4MHz/4cy/32 = 32us
          xorlw  .125      ; compare with 125 x 32us = 4ms
          btfss  STATUS,Z  ; if not equal
          goto   wait      ; then continue waiting

; If TMR0 register is written, the increment is inhibited for the
; following two cycles. The user can work around this by writing
; an adjusted value to the TMR0 register.

; increment 4ms counter
          movlw  8         ; advance 8x32us to allow for TMR0 reset
          movwf  TMR0      ; reset TMR0 with adjusted value
          incf   CNT1      ; increment 4ms timer

; check for clock set
clkset    btfss  CNT1,5    ; check every time bit 5 goes hi
          goto   incsec    ; if not set goto incsec
          movf   PORTB,W   ; Get input from PORTB
          andlw  b'001000' ; Line high?
          btfss  STATUS,Z  ; If not -- active low
          goto   incsec    ; got incsec
          incf   MINUTE    ; increment minute
          clrf   SECOND    ; reset seconds to zero
          clrf   CNT1      ; clear 4ms counter
          goto   lomin     ; go check the minutes

; increment seconds
incsec    movf   CNT1,W    ; get 4ms counter
          xorlw  .250      ; compare with 250
          btfss  STATUS,Z  ; if not equal
          goto   check     ; goto check
          incf   SECOND    ; else increment second
          clrf   CNT1      ; reset 8ms timer

; check time
check     movf   SECOND,W  ; get seconds.
          xorlw  .60       ; compare with 60.
          btfss  STATUS,Z  ; if not
          goto   lomin     ; goto lomin,
          incf   MINUTE    ; else increment minutes.
          clrf   SECOND    ; clear seconds.

;work out new time
lomin

The breadboard layout looks like this:

Saturday, 11 February 2012

30. Christmas Lights with Transistors

A component I haven't used yet: The Transistor.

I had some battery operated Christmas lights. They were static, always on, with red, green, orange and blue LEDs.

I wondered if I could make them flash. As it turns out they were wired into two groups, red/orange and green/blue. At one end they were connect all together at the positive terminal and at the other end they two groups each connected to a resistor and the negative terminal. As this was all wound up in plastic sheath I would probably have damaged it trying to separate all the wires, so I left it as it was and went with the two grouped colours.

Now as the red/orange and green/blue were connect to the negative terminal via a resistor each, this meant they were outputs, that is +5---LED---Resistor---GND.

In order to program a PIC chip to control them I needed an input. This was not going to work, so I figured I could use an NPN Transistor to act as a switch.

I programmed a PIC12F508 to connect to pins to two transistors to switch the LEDs on and off. I also incorporated a 4-gang DIP switch to allow 16 flashing modes. I ended up just having Switch 1 as a fast/slow option, switches 2 & 3 to give 4 flashing modes and switch 4 enables the original static always on mode.

Here's my breadboard layout before I soldered it all together and put it into battery compartment and put a USB cable to provide +5V power instead of 4.5V with batteries.

Sunday, 23 October 2011

29. Manual Up/Down Counter

I modified the circuit in the previous post by removing the 555 timer clock input and adding two switches so I could manually increment or decrement the value. These sent a signal to a 556 Timer chip (dual 555s) setup in monostable fashion to send a distinct pulse to the "clock-up/down" signals of the 74193. I also wired the "borrow" output of the first 74193 to the "clock-down" input of the second 74193 so it could count backwards. As inactive inputs to the clock up/down should be high when not in use I sent the 556 outputs via a 7404 hex inverter.

On the monostable circuits I used 8.2K resistors and a 10μF capacitors. I tried a 47μF capacitors but the pulse length was a little too long. With the 10μF capacitors I am getting the occasional double clock pulse, so it would sometimes skip 2 counts. I hooked up my oscilloscope and it looks like I have some noise on the output pulse when triggered. I'm not sure what's causing this so any ideas would be much appreciated.

Update: the circuit noise I have read is due to the switch contacts bouncing and to fix this I need a debouncing circuit.

Thursday, 20 October 2011

28. Here are my 2 digits

Giving my PIC16F505s programmed as Hex-to-7-segment-display-drivers a work out by making a Hex Counter. I wanted to have 4 digits but the breadboard wasn't big enough. I might work on this later

For now, check out my little video:

27. Traffic Lights with PIC12F508s

I thought I'd have some fun with the PICs, so I made this 3 way traffic light system.

Pins:
1. +5V
2. Transmit
3. Receive
4. Master/Slave
5. Green
6. Amber
7. Red
8. Ground

PIC code can be found here.

Friday, 7 October 2011

26. No Logic In using PICs

I considered using PIC chips for memory logic, so they could select whether an address was for RAM or ROM. Programmatically this is not a problem, the code can be written to do this quite easily. The problem is that they cant do it fast enough.

Most Z80 instructions work over 4 clock cycles, T1, T2, T3 and T4. During T1, the address pins A0-A15 are set to the value of PC (Program Counter) and half a cycle later, MREQ (Memory Request) and RD (Read) pins go active. By the end of T2 the data is fetched from the data bus on D0-D7.

If the Z80 is running at 1MHz then each cycle is 1μs (1 micro second), so fetching an instruction takes at most 2μs.

Now consider a PIC microcontroller running at 4MHz. Again each instruction takes 4 cycles, so the instruction to read the pins on a PIC such as MOVF GPIO,W will take 1μs (4Mhz / 4 cycles), so at most we could only perform 2 instructions on the PIC while the Z80 is trying to fetch the next instruction or operand on the data bus. A branch instruction on the PIC takes 8 cycles, so we could not even fit a loop into the time frame.

The only it could work with a PIC is if the Z80 was running at a much slower clock rate. However this Z80 can go at 2.5MHz and the Z80B can go at 4MHz, and it'd be a shame not to run at full speed.

You can clock some of the PICs with an external crystal to 20MHz and the more expensive PICS to 60MHz and this would allow 5 or 15 instructions in 1μs respectively, but probably still not fast enough at higher Z80 speeds.

Time to bring out the classic TTL chips.

Saturday, 1 October 2011

25. Need a clock? Take your PIC!

Having discovered PIC microcontrollers, I think I will use them quite a lot on this project. One use is as a clock. The smaller PICs have 4MHZ internal oscillators and the larger ones I think are 8MHz. One of the pins can be configured to be a CLKOUTand will send a signal 1/4 of the clock speed. This is effectively 1 pulse for every instruction. Using the internal oscillator of 4MHz this should give a 1MHz clock signal.

I'm using one my PIC16F505s for this, although a PIC12F508 would be (a) cheaper and (b) has less pins [update: and it doesn't externalize its clock]. We only need to connect up +5V and ground, plus the clock pin. On the PIC16F505 its pin 3 (RB4/OSC2/CLKOUT).

The code would look like this:
include "p16f505.inc" ;
        __config _IntRC_OSC_CLKOUTEN
        org     000
loop    nop
        goto    loop
        end

I tried it on the Z80. I think it works. I measured it on my small oscilloscope but I don't think its fast enough to keep up with the signal change. Instead I measured the signal on the A15 pin. I did get a signal but there was a lot of noise when the pin went low. Its 4.705Hz, so multiply this by 65536 (the Z80 is executing NOP and the PC will loop every 65536 instructions) and then by 4 (number of clock signals to execute NOP) should give the clock speed. It gives 1,233,387.52, just slightly over 1MHz. Peak voltage is 2.040V, low is 0.480V. At this resolution I am not sure these voltages are accurate. I checked the MREQ pin and this looks like its working but the voltage delta is 800mV. Is this enough to give a true high/low difference? I'm not sure at this stage.

There was a wierd effect after a few mins where the higher address pins such as A15 seemed to be static rather than blinking. I put a decoupling capacitor (don't ask me why I just guessed), on the PIC chip and that seems to have solved the issue. Its been running for over an hour now and seems to be ok.

Time to see what else these babies can do...

Wednesday, 28 September 2011

24. Homebrew Hex to 7 segment display drivers working.

Yes I did it. I wrote PIC machine code to program the PIC16F505 Microcontrollers to perform the function of Hex to 7 segment Display Drivers.

I started writing the code before I even had the PIC Programmer or PIC chips. On the first run, I found I had an issue with the inputs not being grounded with pull-down resistors, causing the inputs to fluctuate randomly, but some 10K resistors on the inputs connected to ground sorted that. If you have a switch, when its on its fine, a voltage goes to set the pin high or 1. When the switch is off the pull-down resistors connect the pin to ground giving a low or 0 input.

I did initially opt to use one pin on the PIC16F505 as a latch, so it would only display the input when a button was pressed. I decided it wasn't necessary and the program loops around reading the inputs and setting the outputs to light up the LEDs.

Hers's a pic of the setup with annotation.

The PIC assembly code is here:

; include file with config bit definitions
 include "p16f505.inc" ;

; config - enable internal OSC and allow use of RB4
;        - disable MCLRE and allow use of RB3 (input only)
;        - disable Watchdog Timer, we don't use it.
 __config _IntRC_OSC_RB4EN & _MCLRE_OFF & _WDT_OFF


; local regsiters
INB equ 0x08
INC equ  0x09
INPUT equ  0x0A
OUTB equ 0x0B
OUTC equ 0x0C
PWRSTS equ  0x0D
SEGDATA equ 0x10

SEG0 equ 0x10
SEG1 equ 0x11
SEG2 equ 0x12
SEG3 equ 0x13
SEG4 equ 0x14
SEG5 equ 0x15
SEG6 equ 0x16
SEG7 equ 0x17
SEG8 equ 0x18
SEG9 equ 0x19
SEGA equ 0x1A
SEGB equ 0x1B
SEGC equ 0x1C
SEGD equ 0x1D
SEGE equ 0x1E
SEGF equ 0x1F

; start here 
 org 000
 movf STATUS,PWRSTS ; Save Power on status

; Port configuration
;                                        a
;              +-----+                 ---
;         VCC [|     |] GND           f| g |b
;  D3 --> RB5 [|     |] RB0 --> a ---
;  D2 --> RB4 [| PIC |] RB1 --> b     e|   |c
;  D1 --> RB3 [| 16F |] RB2 --> c       ---
;  D0 --> RC5 [| 505 |] RC0 --> d        d
;  NC     RC4 [|     |] RC1 --> e
;   g <-- RC3 [|     |] RC2 --> f
;              +-----+
;

;                 RRRRRR
;                 BBBBBB
;                 543210
init movlw b'111000' ; Set PORTB Pins
 tris PORTB

;                 RRRRRR
;                 CCCCCC
;                 543210
 movlw b'100000' ; Set PORTC Pins
 tris PORTC

; Load Segment values into memory.
;Digit gfedcba abcdefg a b c d e f g
;0 0x3F 0x7E on on on on on on off
;1 0x06 0x30 off on on off off off off
;2 0x5B 0x6D on on off on on off on
;3 0x4F 0x79 on on on on off off on
;4 0x66 0x33 off on on off off on on
;5 0x6D 0x5B on off on on off on on
;6 0x7D 0x5F on off on on on on on
;7 0x07 0x70 on on on off off off off
;8 0x7F 0x7F on on on on on on on
;9 0x6F 0x7B on on on on off on on
;A 0x77 0x77 on on on off on on on
;b 0x7C 0x1F off off on on on on on
;C 0x39 0x4E on off off on on on off
;d 0x5E 0x3D off on on on on off on
;E 0x79 0x4F on off off on on on on
;F 0x71 0x47 on off off off on on on

 movlw 0x3F
 movwf SEG0

 movlw 0x06
 movwf SEG1

 movlw 0x5B
 movwf SEG2

 movlw 0x4F
 movwf SEG3

 movlw 0x66
 movwf SEG4

 movlw 0x6D
 movwf SEG5

 movlw 0x7D
 movwf SEG6

 movlw 0x07
 movwf SEG7

 movlw 0x7F
 movwf SEG8

 movlw 0x6F
 movwf SEG9

 movlw 0x77
 movwf SEGA

 movlw 0x7C
 movwf SEGB

 movlw 0x39
 movwf SEGC

 movlw 0x5E
 movwf SEGD

 movlw 0x79
 movwf SEGE

 movlw 0x71
 movwf SEGF

; End of initialisation

; To here 37 Instructions @ 4MHz = 37uS

; Main Program Starts here.
poweron clrf OUTB  ; Clear output Register B
 clrf OUTC  ; Clear output Register C
 btfss PWRSTS,RBWUF; Check Power-On Status
 goto display  ; blank if power on

; Reset output values and indexes
loop clrf OUTB  ; Clear output Register B
 clrf OUTC  ; Clear output Register C
 movlw SEGDATA  ; Load W with SEG DATA base
 movwf FSR  ; Save to FSR

; read value from PORTs
 movf PORTB,W      ; Read PORTB
 movwf INB  ; Save PORTB
 movf PORTC,W  ; Read PORTC
 movwf INC  ; Save PORTC

; combine port reads into a nibble in W register
 clrf INPUT  ; Clear INPUT register
 btfsc INB,RB5  ; Test RB5 (D3)
 bsf INPUT,3  ; Set D0
 btfsc INB,RB4  ; Test RB4 (D2)
 bsf INPUT,2  ; Set D1
 btfsc INB,RB3  ; Test RB3 (D1)
 bsf INPUT,1  ; Set D2
 btfsc INC,RC5  ; Test RC5 (D0)
 bsf INPUT,0  ; Set D3
 movf INPUT,W  ; Move value to W


; add value to index register and fetch segment value
 addwf FSR,F  ; Add index to FSR pointer

; prepare register output bits
 btfsc INDF,0  ; Test for 'a' segment
 bsf OUTB,RB0 ; Set 'a' segment
 btfsc INDF,1  ; Test for 'b' segment
 bsf OUTB,RB1 ; Set 'b' segment
 btfsc INDF,2  ; Test for 'c' segment
 bsf OUTB,RB2 ; Set 'c' segment
 btfsc INDF,3  ; Test for 'd' segment
 bsf OUTC,RC0 ; Set 'd' segment
 btfsc INDF,4  ; Test for 'e' segment
 bsf OUTC,RB1 ; Set 'e' segment
 btfsc INDF,5  ; Test for 'f' segment
 bsf OUTC,RB2 ; Set 'f' segment
 btfsc INDF,6  ; Test for 'g' segment
 bsf OUTC,RB3 ; Set 'g' segment

; move output to ports
display movf OUTB,W  ; Get values to send to PORTB
 movwf PORTB  ; Send to PORTB
 movf OUTC,W  ; Get values to send to PORTC
 movwf PORTC  ; Send to PORTC

; around again
 goto loop  ; go back to loop - 50uS loop
 end

Friday, 23 September 2011

23. Put out by the output.

I had this idea, that I would connect up some 7 segment displays to show what all the registers where set to if I stepped through a Z80 program. Its a little bit ambitious at this stage of my journey, so I thought I would start by creating something to input Z80 commands directly onto the data bus. I bought some in-line 8 bit switches, however the data pins on the Z80 are split into two group by the fact that the +5V Vcc input sit between them. Not only that, they are not in order like the address pins. So I put some jump wires in to put them into the right order. Now it'd be great to have a hex display of the data that I am trying to put in, so I thought I could use two 7 segment displays. Easy right?

For each nibble (thats what 4 bits of a byte are called) I need a 7 segment display. One for the upper values of 0123456789ABCDEF and one for the lower. The displays have 8 inputs 7 for the segments and one for the decimal point. So I read that to convert 4 bits to 7 I needed a hex to 7 segment display driver. Cool, so I go surfing the web to find one. All I can can find are BCD to 7 segment display drivers (BCD is Binary Coded Decimal and basically allows the values 0123456789) such as the 7447. I eventually find some, the DM9368 and the MC14495. They don't make them any more, but if you hunt around you can find them for like £30 each.

Going back to my original idea of displaying the registers, I worked out I'd need 52. Ouch!

As I desperately try to find alternatives, one blogger mentions using a PIC microprocessor instead, and programming it to perform the same function. Hmm, could this work?

So I get diverted into looking at what these PIC things are. I soon discover that they're kind of like the ATMega that powers the Arduino, but can come in very small sizes, I mean some are only 8 pins. This diversion opens up a whole new world. New software, new machine code language, new software to program them and new programmers to, well, program them.

Needless to say, I have been reading numerous .pdf documents on how all this stuff works. I'm not even sure if it will work yet. I've initially plumbed for the PIC16F505. I was going to go with the PIC16C505 from Maplin for £1.89, but its a bit outdated, but the PIC16F505 is 79p from RS Components. Now it used to be that RS were only open to Businesses, but I believe they have now opened up their doors to the general public.

I found this USB PIC Programmer too for £35. So I am going to bite the bullet and give it a go because 79p x 52 is a lot easier to swallow. Of course I'll just try with 1 for now.

The software is free from Microchip and I've started writing some simple code so I can get the hang of it. At least its compiling ok.

So here I am programming a completely new and alien (to me) microprocessor so I can get some output (and input) from (to) a Z80 using some 7 segment displays. Kind of ironic really.

I may be a while....

Wednesday, 7 September 2011

22. Building An EEPROM Programmer (Part 3).

Ok So does it actually work. YES!

On linux you can check the data in the zx81.rom file by typing:
od -Ax -t x1 zx81.rom

Running the EERPROM Reader in Part 1, I can visually see that they look the same. As a final check I got the ERRPROM Reader to add all the bytes together (OK not the best way to check sum a file but I am not here to write a proper CRC checksum routine for the Arduino just now), and also wrote a C program to do the same on Linux called sum.c:

#include 
main()
{
 int c,sum;
 sum=0;
 while ((c=getchar()) != EOF) {
  sum=sum+c;
 }
 printf("Checksum: %d\n",sum);
}

The final value came back as 855105 for both.

Result!

As a final check, I unplugged the Arduino removing power from the EEPROM in the process. Left it for a few minutes and then plugged that Arduino again restoring power to the EEPROM and reran the EEPROM Reader program. All data preserved and sum still the same.

21. Building An EEPROM Programmer (Part 2).

The Arduino can receive data via the Serial interface. This is how I want to send the Z80 programs to the EEPROM. The problem is the Arduino is not reading fast enough and so what gets sent is lost. Its fine for sending the odd few bytes now and then, but (using my zx81.rom as a test) sending 8K of data is a bit much for it to handle in one go.

The Serial buffer on the Arduino is 128 bytes, so all I was getting to start with was the first 128 bytes of the 8K successfully, after that it was a random sets of 128 bytes from the Serial port that it grabbed hold of before the stream of data ended.

To compensate for this, I decided to send 64 bytes at a time with 1 second interval. Now this is fairly easy to do in Linux with a script:

eeprom_send.sh
#!/bin/bash
split -C 64 ${1} ${1}.part.
for part in `ls ${1}.part.*`
do
 cat ${part} >> ${2}
 sleep 1
done
rm -f ${1}.part.*

To use it type:
./eeprom_send.sh zx81.rom /dev/ttyACM0

But first you just need to program the Arduino and then open the serial monitor window (dont ask me why).

Here is the Arduino program:
/*
 EEPROM Programmer
*/
#define memsize 8192

int STS   = 13;  // Status Indicator

int AP[16] = {22,24,26,28,30,32,34,36,38,40,42,44,46,48,50,52};
int AD[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
int DP[8]  = {23,25,27,29,31,33,35,37};
int DD[8]  = {0,0,0,0,0,0,0,0};

int CE  = 4;
int OE  = 3;
int WE  = 2;

int i;
int A;
int D;
int wait;

void setup() {
  
  Serial.begin(115200);
  Serial.flush();
  
  pinMode(STS,   OUTPUT);
  
  // Setup Address Pins 
  for (i=0;i<16;i++) {
    pinMode(AP[i],OUTPUT);
  }
  
  // Setup Data Pins
  for (i=0;i<8;i++) {
    pinMode(DP[i],OUTPUT);
  }
  
  // Setup Control Pins
  pinMode(CE, OUTPUT);
  pinMode(WE, OUTPUT);
  pinMode(OE, OUTPUT);
  
  // Setup Chip
  digitalWrite(CE, LOW);
  digitalWrite(WE, LOW);
  digitalWrite(OE, HIGH);

  Serial.println("Waiting for Data...");
  while(Serial.available()==0) {
    digitalWrite(STS,LOW);
    delay(100);
    digitalWrite(STS,HIGH);
    delay(100);
  }

  for (A=0;A<memsize;A++) {
    
    D=Serial.read();
    digitalWrite(STS,HIGH);  //Signal that we're writing.

    // Setup Address Pins
    for (i=0;i<16;i++) {
      if((A&bit(i))>0) {
        AD[i]=HIGH;
      } else {
        AD[i]=LOW;
      }      
      digitalWrite(AP[i],AD[i]);
    }
    delay(1);
    
    digitalWrite(OE,LOW);   // Reads Disabled
    delay(1);

    digitalWrite(CE,HIGH);    // Chip Enable
    delay(1);

    digitalWrite(WE,HIGH);    // Write Enabled
    delay(1);
    
    // Setup Data Pins
    for (i=0;i<8;i++) {
      if((D&bit(i))>0) {
        DD[i]=HIGH;
      } else {
        DD[i]=LOW;
      }      
      digitalWrite(DP[i],DD[i]);
    }
    delay(1);

    digitalWrite(WE,LOW);      // Write Disabled
    delay(1);

    digitalWrite(CE,LOW);      // Chip Disabled
    delay(1);

    digitalWrite(OE,HIGH);       // Reads Enabled
    delay(1);
    
   digitalWrite(STS,LOW); // Signal that we're waiting
    wait=0;
    while(Serial.available()==0) {
      delay(1);
      if (wait>2000) {
        A=memsize;
        break;
      }
      wait++;
    }
    
  }
  
}

void loop() {
  digitalWrite(STS, HIGH);   // set the LED on
  delay(1000);              // wait for a second
  digitalWrite(STS, LOW);    // set the LED off
  delay(1000);              // wait for a second
}

Tuesday, 6 September 2011

20. Building An EEPROM Programmer (Part 1).

Please note that I have disabled comments on this post purely due to a persistent spammer - Dave 23/04/2021.

Its all very well having an EEPROM chip to store our program for the Z80, but somehow we need to get the code onto it. Enter, the EEPROM programmer. So far I have wired up the EEPROM to the Arduino Mega and I can read from it successfully. Writing to it is easy enough, but just now I can't bulk load a file to it. When I do, go find Part 2 :)

Here's a diagram I made using this great tool called Fritizing:
As you can see I've used a 74LS04 Hex Inverter to make sure the 3 control lines are HIGH by default as the pins on the Arduino are LOW by default and as the control pins are 'Active Low' we don't want data overwritten accidentally. It also means that setting the pin to HIGH in the Arduino code means the pin is Active.

Here's the EEPROM Reader code for the Arduino Mega:
/*
 EEPROM Chip Reader
*/

#define memsize 8192

int STS   = 13;  // Status Indicator

int AP[16] = {22,24,26,28,30,32,34,36,38,40,42,44,46,48,50,52};
int AD[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
int DP[8]  = {23,25,27,29,31,33,35,37};
int DD[8]  = {0,0,0,0,0,0,0,0};

int CE  = 4;
int OE  = 3;
int WE  = 2;

int i;
int j;
int D;
int A;

void setup() {
      
  // Setup Control Pins
  pinMode(CE, OUTPUT);
  pinMode(WE, OUTPUT);
  pinMode(OE, OUTPUT);
  
  // Disable Chip, and disable read and write.
  digitalWrite(CE, LOW);
  digitalWrite(WE, LOW);
  digitalWrite(OE, LOW);

  Serial.begin(115200);
  
  Serial.println("Reading EEPROM...");
  
  pinMode(STS,   OUTPUT);
  digitalWrite(STS,HIGH);
  
  // Setup Address Pins 
  for (i=0;i<16;i++) {
    pinMode(AP[i],OUTPUT);
  }
  
  // Setup Data Pins
  for (i=0;i<8;i++) {
    pinMode(DP[i],INPUT);
  }

  delay(1000);
  
  for (A=0;A<memsize;) {
    
    if (A<4096) Serial.print("0");
    if (A<256)  Serial.print("0");
    if (A<16)   Serial.print("0");
    Serial.print(A,HEX);
    Serial.print(" ");

    for (j=0;j<16;j++) {
    
      // Setup Address Pins
      for (i=0;i<16;i++) {
        if((A&bit(i))>0) {
          AD[i]=HIGH;
        } else {
          AD[i]=LOW;
        }      
        digitalWrite(AP[i],AD[i]);
      }
    
      digitalWrite(CE,HIGH);      // Chip Enabled
      digitalWrite(OE,HIGH);      // Read Enabled
    
      // Read Data Pins
      D=0;
      for (i=0;i<8;i++) {
        DD[i]=digitalRead(DP[i]);
        D=D+bit(i)*DD[i];
      }
    
      digitalWrite(OE,LOW);     // Read Disabled
      digitalWrite(CE,LOW);     // Chip Disabled
    
      if (D<16) Serial.print("0");
      Serial.print(D,HEX);
      Serial.print(" ");
      
      A++;
    }
    
    Serial.println();
    
  }
  
}

void loop() {
  digitalWrite(STS, HIGH);   // set the LED on
  delay(500);              // wait for a second
  digitalWrite(STS, LOW);    // set the LED off
  delay(500);              // wait for a second
}

Wednesday, 31 August 2011

19. The Ups and Downs of an Astable 555 Timer (How fast will it go?)

Well not that fast really. OK its faster than the refresh rate on your TV, but in the grand scheme of the computer world, its not that fast at all. Now I did get it to clock up 250KHz but the problem is that the peak voltage was not high enough and the low voltage not low enough. Its seems the faster I tried to get it to go the smaller the voltage difference.

Measuring the signal with the Xprotolab Oscilloscope is not easy either. It has a minimum resolution of 500 nano seconds per pixel, which if you do the sum 1/0.0000005 = 2MHz, means a 250KHz signal is 8 pixels wide. At higher frequencies the signal starts to become a blur on the screen.

Another aspect of the astable 555 timer is the Duty Cycle. Ideally, you probably want the time the voltage is high to be the same as when it is low, e.g. 50% each. The main external components used are 2 resistors (R1 & R2) and a capacitor (C1). Using 2 identical resistors gives you a Duty Cycle of 66%. To achive a Duty Cycle of 50% R2 needs to be roughly 10x that of R1. So with 2x 1K resistors and a 1nF capacitor we get about 250KHz with a 66% Duty Cycle, but changing R2 for a 10K resistor gets a 52% Duty Cycle and a much reduced clock speed of 57KHz. However, the low volatge is 0.000V and the peak is 4.480V using a 5V supply, much more usable. The Z80 Datasheet says that the input voltage for CLK should be Vcc-0.6 minimum, which with a 5V supply is 4.4V, so 4.480V should be OK to drive the clock signal.

Here are a few screenshots to show what I am talking about:
R1=1K R2=1K C1=1nF ~ Vmax=4.160V Vmin=1.600V Freq=250KHz Duty=66%
R1=1K R2=1K C1=10nF ~ Vmax=4.480V Vmin=0.000V Freq=42.55KHz Duty=66%
R1=1K R2=10K C1=1nF ~ Vmax=4.480V Vmin=0.000V Freq=58.82KHz Duty=52%

If I want to run this faster I am going to have to buy a quartz crystal. For this standard Z80 it needs to be 2.5MHz. (The Z80A will go at 4MHz).

18. Pinups! Oops! I mean Pinouts :)

I was trying to visualise the connections between the main ICs for my little project. Specifically the address bus pins(A0 to A15) and the data bus (D0 to D7). Looking at 3 .pdf datasheets did not help and what I really wanted was a side by side picture. So I started up Microsoft Paint and started making some of my own images, and here they are:
The Z80, the 128k SRAM and the 8K EEPROM.

Friday, 26 August 2011

17. Old Timer

Thinking about what to use as a clock source to tick over the Z80, I remembered I had a couple of 555 timers. These have been around since 1971 and not much has changed. There are several modes you can operate these 555s but I am going to get it to generate a squarish pulse using the 'astable' confuration. You can read up about how to do that elsewhere on the web. Suffice to say I'm using 2x 1k resistors and a 10nF capacitor. Hook these up to the 555 and you get a pusle from pin 3. Yay!

Here a pic of the setup:

Now to measure the pulse we have produced. The Xprotolab Oscilloscope comes into it own here. I connect pin3 from the 555 to the CH1 input. It seems we have a pulse operating at 42.55KHz. Ok its not the speediest rate to run a Z80 at but it'll do to start with.

Here's the output from the oscilloscope:

There is formula for working out what combination of resistors and capacitor give a particular frequency, however, as I found out using resistors of too low a value gave a very weak pulse, ie the high voltage was not enough to trigger a response on the CLK input to the Z80. However, just changing the capacitor and keeping the 1K resistors, does allow you to adjust the frequency. Changing it to a 470uF almost gets you a 1 seconds pulse. Its slightly over, and it does also depend on the tolerance of the resistors, but its close enough. This lead me to ponder if there was such a thing as a variable capacitor, and then I remembered from my Denshi Block days that is what was inside the tuner. With something like that we could have a variable speed computer. Something to look at later.

16. Serial Killer App.

I got the USB to UART device yesterday. Works a treat. I'm glad I didn't decide to make my own, the CP2102 is so small the soldering would have been a nightmare. Although it did come with drivers for Windows, I don't have any File Transfer over Serial Port Software, but Linux does.

I downloaded the capture.sh script from www.gabotronics.com and installed the following package:
sudo apt-get install -y lrzsz

I then ran capture.sh and it transfered a screenshot of the Xprotolab Oscilloscope:

It comes out black on white, so a little bit of image conversion:
convert -negate a.bmp b.bmp
and hey presto:

Now there is an interface that is in development for the PC using the same Serial connection. it still needs a bit of work, but so far its looking good. Check it out at http://www.gabotronics.com/product-info/xprotolab-pc-interface.htm

However for now, I'm happy with the screenshots from the oscilloscope. :D

Tuesday, 23 August 2011

15. USB connector for the XProtolab

The micro USB port on the Xprotolab is actually a serial port with a USB connector. Connecting it up to the USB port on the PC gives power, but thats it. In order to use the serial port capabilities you need to have some hardware in between so that when you plug into the USB on the PC it thinks its a COM port.

Now in America, you can buy a cable from Gabotronics, however their distributor in the UK doesn't stock it. However Gabotronics do tell you how to connect one up... to a CP2102. Its a small chip. Fiddly soldering. But wait, there is something I can buy that will get me most of the way: TRIXES USB 2.0 To TTL Serial Converter from Play.com For £4.24 including shipping, I cant refuse. A CP2102 chip from Farnells cost £4.44+VAT.

All I need now is an old micro USB cable to dissect to connect to the Serial Converter.

Why do I want to do this anyway? Well they are designing an interface for the PC to communicate with the Xprotolab and you can also get screenshots (aparently). We'll see.

Another parcel coming then, its Christmas again :)

14. Goodies Received.

I got the oscilloscope and the Ardunio board yesterday. I should have gotten them Saturday but I was out when the postman came so had to wait for the Post Office depot to open at 7am Monday.

Not much to say about the Arduino except, its bigger, has more pins and will allow me to connect up the whole of the Z80, the SRAM and EEPROM chips.

The oscilloscope is amazing! It's so small but full of features, and despite the small display is actually very readable.

Heres a pic of them both:


Friday, 19 August 2011

1101. Retail Therapy.

I bought some goodies from Cool Components.

The Arduino Mega 2560 and the XMega XProtolab Oscilloscope.

The bigger Arduino gives me more connections for communicating with the Z80, the SRAM and the EEPROM. The oscilloscope means I can test and check my circuits are working such as a clock circuit running at 1MHz.

Its like Christmas :)

Tuesday, 16 August 2011

12. Resistance Is Futile.

I have a whole stash of resistors from a kit. They're on strips and none of them are labelled. Well of course they are labelled but with 5 coloured lines around them. Great, now I can work out what they are, or so I thought. Even with an online resistor calculator I can't tell for sure. Some of the colours are a bit vague, or maybe its just my eyesight going. Is that a brown or a gold, is that red a shade of blue?

Anyway, I found a better way of identifying them. I just used an Ohmmeter to measure their resistance. Simples.

Now for a little chant: Ohm, Ohm, Ohm, Ohm....

Sunday, 14 August 2011

11. Fried chips? Well just an LED so far...

Well it was bound to happen sooner or later. I fried an LED.

Maplin is open on Sundays, so I popped over to get some of those components to make a 5 volt power supply.

It worked. I put a red LED on the +5v coming from the circuit and connected the other end to ground. It lit up, for a while. I noticed this smell of hot electronics then the LED faded away. The bulb was hot, the voltage regulator (78L05) was hot. Not good!

So I rememeber reading somewhere, always use a resistor with an LED. So I put a 1K resistor in front and then found another LED and it was fine. Not hot anywhere.

Here is a diagram I made using CircuitMaker Student Edition which was free to download:

Saturday, 13 August 2011

10. Oh! The Power...

A thought occurred to me. So far I've been using the Arduino to supply power to the Z80 and other ICs (Integrated Circuits aka chips). This can't be the case in the long run. I either need to use a battery or a some mains power adapter.

Now a battery would be good, but what to use. I need 5 volts. If I use 3 AA or AAA batteries, they are 1.5 volts each and thats only 4.5 volts altogether. Add a fourth and I get 6 volts. Too much. So I search the web and find I need something called a Voltage Regulator, but which one? Further reading says I could use a 7805. This will convert much higher voltages to 5v the (the 05 in the 7805 gives us a clue here it seems). Reading further tells me ideally a voltage 2-3 volts higher on the input would be preferable so an 8 volt battery? Hmm, lets go with a 9 volt PPV battery.

The 7805 comes in a few flavours, such as 78L05, 78M05 and 78S05. The L model give 0.1 Amps of current output, the M 0.5 Amps and the S 2.0 Amps. There are others, but its important to choose one that has enough power to drive the circuitry. At this stage I'm not sure. I need to look at the datasheets for ICs I already have to see what range current is expected. I expect it will be either L or M. Anything higher and I think higher and I think I'd fry the circuits.

There is also the implementation of the Voltage Regulator in the circuit that need some thought. It seems we need to put capacitors either side of the voltage regulator to stop it fluctuating too much and for safety a diode to stop us from blowing things up by connecting the battery up the wrong way. This article has a diagram on how to connect it up: http://stuff.nekhbet.ro/2006/06/18/how-to-build-a-5v-regulator-using-78l05-7805.html

I need some more components!

9. The Memory LOW down.

One thing to watch out for when connecting the Arduino to things like memory chips is that by default all the Arduino pins are LOW. Now considering that connections on the memory chips like WE (write enable) and CE (chip enable) are "active Low", then they will be active when a new program is loaded into the Arduino. This means you could overwrite your memory inadvertently. Most likely you will write the value 0 to the address 0 since all the data and address lines will probably be low.

Of course I am talking from experience here as this is exactly what happended to me when I was playing with the SRAM chip. I wrote 2 programs, one called SRAM_Writer and one called SRAM_Reader. I initially ran the Writer and then the Reader. Everything read back OK except memory address 0 which was 0 and my Writer program had written a value of 3 to it.

For safety, best to use some inverters like the 7404s on the critial connections so that they will be HIGH when the Arduino starts up.

Friday, 12 August 2011

8. SRAM Working.

I managed to get the SRAM chip working. I only have a limited number of pins on the Arduino and I needed 4 just to control the chip. I decided to use 3 pins for the address lines and 3 more pins for the data lines. All other pins on the chip I connected to ground effectively making them low or 0. With this configuration I can read/write the values 0 to 7 to the memory addresses 0 to 7 because 7 is the biggest value you can make with 3 binary digits 111 = 1x4 + 1x2 + 1x1 = 7.

There are 17 address lines on this SRAM chip I'm using labelled A0 through to A16 and that allows 217 memory addresses which is 131072 or 128K. In today's world this is an insignificant amount of RAM, but to put it into perspective, the Sinclair ZX80 had 1K of RAM and a 4K ROM, the ZX81 had 1K RAM and an 8K ROM, the Spectrum had 48K of RAM and a 16K ROM.

Wednesday, 10 August 2011

7. Writing machine code.

It would be fair to say that you can't talk to the Z80 in English, or any other language come to that.  It will however accept an 8 bit byte with a value in the range from 0 to 255 or 00 to FF in hexidecimal ( I wont explain how to convert decimal into hex or visa versa, suffice to say your PC's calculator program should be able to do it if you're interested).

If I put 00 on the data lines (basically I grounded them all for now so they are always set at 00) when the Z80 fetches the next instruction, it will read 00 and execute the NOP (No Operation) instruction, and do nothing.  This is a valid instruction for the Z80.  As each instruction byte takes 4 clock tics to process, a processor running at 1MHz will take 4us (4 micro seconds) to do nothing.  This is very useful for timing, because like in the real world when you're waiting for something to happen, you might just sit there and do nothing.

Anyway,  it not easy knowing all the values of all the commands, its much easier to know an instruction by name such as NOP.

Consider the following Z80 program:
LD A,1   ; Load A with 1
LD B,2   ; Load B with 2
ADD A,B  ; Add B to A
HALT     ; Stop

This converts into the following values in hex machine code:
3E 01  ; Load A with 1
06 02  ; Load B with 2
80     ; Add B to A
76     ; Stop
Now as you can see the program was easier to understand than the 6 bytes that the Z80 needs to receive to make it happen. What we need is something that will assemble the bytes from the written commands. As it happens there is a Z80 Assembler program called z80asm which will do it for you.  So this is what I am going to use to create the bytes that I will store in the EEPROM to instruct the Z80 what to do.

6. Memories

Well a CPU is not much good unless you can send instructions to it. They have to be stored somewhere, so you need memory. Now there are various types of memory chip and the most common types are RAM (Random Access Memory) which is fast, but forgets everything once power is switched off, and ROM (Read Only Memory) which keeps it contents after power down.

RAM is good for storing all things that change such as calculation results, the current colour of a pixel on the screen, the location of your pieces in a chess game. There are many uses. ROM on the other hand is fixed. The BIOS which is the program that initially starts your PC is stored on a ROM. It never changes. It can't change, and this makes it difficult to use in an experimental way because like CDs, once written at the factory, they can't be overwritten. We could use a PROM (Programmable Read Only Memory), but this is like a CD-R once you've finished writing to it, you can't overwrite or erase it either. There are EPROMS (Erasble Programmable Read Only Memories) but tend to need ultraviolet light to shine on them to erase them, hardly convenient. There is a better solution EEPROMS (Electrically Erasable Programmable Read Only Memories)

There is also a kind of half way house with SRAM (Static Random Access Memory) which is like RAM but will remember everything if you keep a low voltage applied as used by the BIOS to store settings and backed up with something like a CR2032 battery for when the power is switched off. They last for several years.

For my computer I am going to use an SRAM and EEPROM , which will effectively be my RAM and ROM.

The Z80 has 16 lines for addressing memories and 8 lines for the data. Back in the 80s, memories with similar pins were abundant but these days you have to go and hunt for them. I found some at Farnell's, it came to about £10 but I couldn't order with a credit card unless I bought £20 (pre VAT) worth of good, so I got 35 of each Red, Green and Yellow LEDs. The order arrived today - yay.

I got the ALLIANCE MEMORY AS6C1008-55PCN - SRAM and the ATMEL - AT28C64B-15PU - EEPROM.  Need to read the data sheets and understand how they work so it'll be a while before I get going with these yet.  The Arduino will help.

5. Here's one I made earlier...

I bought a breadboard from Maplin and some jump wires and put the ICs (intergrated circuits, that'll be the computer chips then), and some LEDs to the address pins of the Z80 and a bright blue LED on the clock. I did try initially putting the blue LED in-line but for some reason it wouldn't light up so I assumed it didnt have enough power to drive it (it was a HIGH line state before going into the inverter) , so I took a feed off the 'active low' state of the CLK signal from the 74LS04 and fed it back in and inverted the signal again and then connected the blue LED to that and it lit up like a dream. The hex inverters also have their own power supply and can boost a signal coming in. I think they're also known as 'buffers'.

Anyway, here it is all wired up ready to go:



This is the Arduino program I wrote to talk to the Z80:
/*
Zilog Z80 Controller
*/

const int CPU = 0;
const int PIN = 1;
const int DIR = 2;
const int STS = 3;


/* low states = true */
int CLK[4]    = {06,13,OUTPUT,LOW}; // in
int INT[4]    = {16,0,OUTPUT,LOW}; // in
int NMI[4]    = {17,0,OUTPUT,LOW}; // in
int HALT[4]   = {18,12,INPUT,LOW};  // out
int MREQ[4]   = {19,11,INPUT,LOW};  // out
int IORQ[4]   = {20,10,INPUT,LOW};  // out
int RD[4]     = {21,9,INPUT,LOW};  // out
int WR[4]     = {22,8,INPUT,LOW};  // out
int BUSACK[4] = {23,7,INPUT,LOW};  // out
int WAIT[4]   = {24,0,OUTPUT,LOW}; // in
int BUSRQ[4]  = {25,0,OUTPUT,LOW}; // in
int RESET[4]  = {26,6,OUTPUT,LOW}; // in
int M1[4]     = {27,5,INPUT,LOW};  // out
int RFSH[4]   = {28,4,INPUT,LOW};  // out

int OLDM1[4]  = {27,5,INPUT,LOW};

int T = 0;

void setup() {                

  // Define Pins
  pinMode(CLK[PIN],   CLK[DIR]);
  pinMode(M1[PIN],    M1[DIR]);
  pinMode(RESET[PIN], RESET[DIR]);
  pinMode(HALT[PIN],  HALT[DIR]);
  pinMode(MREQ[PIN],  MREQ[DIR]);
  pinMode(IORQ[PIN],  IORQ[DIR]);
  pinMode(RD[PIN],    RD[DIR]);
  pinMode(WR[PIN],    WR[DIR]);
  pinMode(BUSACK[PIN],  BUSACK[DIR]);
  pinMode(RFSH[PIN],  RFSH[DIR]);
  
  // Setup Serial Port
  Serial.begin(9600);

  // Reset CPU
  Serial.println("CPU Reset");
  delay(500);
  RESET[STS]=HIGH;
  digitalWrite(RESET[PIN],RESET[STS]);
  delay(2000);
  RESET[STS]=LOW;
  digitalWrite(RESET[PIN],RESET[STS]);
}

void loop() {

  //Start Clock Period T

  digitalWrite(CLK[PIN],CLK[STS]);
  
  delay(500);
 
  // Read Machine Cycle Status M  Clock High
  M1[STS]=digitalRead(M1[PIN]);
  HALT[STS]=digitalRead(HALT[PIN]);
  MREQ[STS]=digitalRead(MREQ[PIN]);
  IORQ[STS]=digitalRead(IORQ[PIN]);
  RD[STS]=digitalRead(RD[PIN]);
  WR[STS]=digitalRead(WR[PIN]);
  BUSACK[STS]=digitalRead(BUSACK[PIN]);
  RFSH[STS]=digitalRead(RFSH[PIN]);
  

  Serial.print(T);
  Serial.print("=");
  Serial.print(CLK[STS]);
  Serial.print(" M1=");
  Serial.print(M1[STS]);
  Serial.print(" HALT=");
  Serial.print(HALT[STS]);
  Serial.print(" MREQ=");
  Serial.print(MREQ[STS]);
  Serial.print(" IORQ=");
  Serial.print(IORQ[STS]);
  Serial.print(" RD=");
  Serial.print(RD[STS]);
  Serial.print(" WR=");
  Serial.print(WR[STS]);
  Serial.print(" RFSH=");
  Serial.print(RFSH[STS]);
  Serial.print(" BUSACK=");
  Serial.print(BUSACK[STS]);
  Serial.println();

  if(M1[STS]==HIGH && OLDM1[STS]==LOW) {
    Serial.println("----M1 Starts----");
  }
  OLDM1[STS]=M1[STS];

  CLK[STS]=!CLK[STS];
  T=T+CLK[STS];
} 

Tuesday, 9 August 2011

4. The Decoupling Capacitor.

Now stuff that I tell you on this blog is what I am learning as I go. This is no exception. I had no idea what a Decoupling Capacitor was. I kind of knew what a capacitor was. Its similar to the hot water tank in the loft in its function. As you use hot water, it refills the hot water boiler, then it in turn is refilled from the mains water supply. Similarly if you connect a capacitor between the +5V and GND pins on the Z80 CPU it will fill with charge so that when the CPU starts to drain the battery by turning pins on and off the capacitor can take up the slack and keep the CPU with voltage. I used a 0.1uF (microfarad) capacitor. It needs to be as close to the CPU as possible so I just straddled the capacitor directly over the CPU.

Ideally you'll have one on every logic chip, but I opted to just put one on the whole circuit so just decoupled the main +5V supply and ground.

3. What NOT?

Now it kind of goes against the grain coming from a software angle that something is ON when it is OFF and visa versa. I like 0 to represent OFF and 1 for ON. However all the control pins on the Z80 are 'Active Low' which means from a software point of view I have to turn a pin on the Arduino OFF to turn something ON on the Z80. Yes I know very confusing. Fortunately there are logic chips that can switch that around for you. I used some 74LS04 Hex Inverters. Basically on each chip you can stick in a high voltage and get a low voltage out and visa versa. One pin goes in, one comes out and there are 6 pairs (hence the Hex). Now the Z80 has 13 control pins and so I opted to get 2 Hex Inverters. Ok so that lets me control 12 pins on the Z80, so I will just hook up any pins I don't really need to use at this stage to the +5V supply (remember high voltage means OFF).

At this point I would like to thank Hackman's Realm for a description of how to get a Z80 working. After several attempts at wiring the Z80 to the Arduino I am surprised I didn't blow one of them up by connecting thing up the wrong way, and Hackman's document put me on the right path (I did say I didnt know what I was doing at the start :) ).

So now I can tell the Arduino to set a pin HIGH i.e. ON and via the 74LS04 chip the Z80 gets a LOW signal turning the pin ON.

So what I send to the CPU is NOT what I sent but satisfies the 'active Low' requirements and everyone is happy!

2. Arduino hook up.


Last Christmas, I got my wife to buy me an Arduino UNO. I'd had a passing interest in electronics from an early age when my father gave me his Denshi Block electronics set to play with. I just had to open the book of projects and place the components exactly as in the picture, connect up the battery and annoy my mother playing the electronic cat sound all day. So I knew from an early age, what the components were, but not necessarily what they did. This probably lead to me blowing up my ZX Spectrum by adding a reset switch and kind of put me off wiring up anything else and breaking it and instead I entered the world of software.

For £20, the Arduino has all the electronics, all I need to do is program it on the PC to turn a pin on and light up an LED and my interest in electronics is rekindled. If I break it, well I could fork out another £20.

I had a brief play with the UNO at Christmas but don't get much time to play with it until about 8 months later i.e. now. Having tamed the electronic beast and even got it to drive a 16x2 LCD display from Maplin, I start to look for a project. So I buy the Z80 CPU. Fortunately it was the better choice for a project as it can be easily hand cranked, compared to other processors of the same era e.g. the MOS 6502.

All CPUs need a pulse to come alive. Pin 6 on the Z80 the Clock Input and this expects to see a voltage go low then high, then low then high etc. Each time the voltage goes low, the processor moves on a step. For the Z80 it takes at least 4 clock tics to process an instruction. Ultimately the Z80 should be able to jog along at 1 million tics per second or 1 MegaHertz (MHz). I want to understand how the Z80 ticks (no pun intended) and to do this I want to see changes happen visibly (such as an LED going on and off) so I want to control the frequency of the tics.

I begin to wire up the Z80 to the Arduino...

1. Journey begins... well continues.

Back in the 80's, when I was a teenager I had a Sinclair ZX80 (which evolved into a ZX81 via an 8K ROM replacement) and a Sinclair ZX Spectrum. Apart from the obvious Sinclair brand attachment, they all were underpinned by the Zilog Z80 Processor. After getting to grips with the BASIC programming language I discovered the world of machine code programming, writing code that spoke directly to the core of the machine, and so my journey began.

Luckily for me the Z80 was all wrapped up in a nice hardware parcel courtesy of Sinclair Research Ltd with memory, a keyboard and able to hook up to a TV via an aerial input (how quaint!). I didn't have to know about electronics, all I needed to know was how to store bytes representing the Z80 instruction code into memory via the old POKE command and then executing it to do whatever I had dreamed up that day.

My affair with the Z80 came to an end after I tried to wire up a reset switch directly to the chip. It never worked again after that and my Sinclair ZX Spectrum became a door stop.

By this time, the Personal Computer had arrived on the scene and my attention was drawn to this new and shiny world.

25 years later, and after a conversation reminiscing about the good old days of the Z80 and 6502 processors I end up buying a Z80 chip for £5 off of eBay and my journey continues...