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).

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...