Sunday 3 May 2020

6522 Versatile Interface Adapter

Introduction

I have been experimenting with the Rockwell R6522 Versatile Interface Adapter (VIA), connected to my homemade 6502 based computer. I already have a Motorola 6821 PIA connected as part of the computer, which I've used to interface a keypad, described in a previous article.

The R6522 looked very interesting, having many features, and appearing quite complex as I initially read and re-read the datasheet. I wanted to explore all of the features of this IC, and I've worked through many of these, and have proved that I can replicate the datasheet findings! All very encouraging, as this exploratory phase has involved some machine coding and working out why things don't always work first time...

Having the benefit of an oscilloscope has proved once again to be invaluable.

6522 Shift Register
In this article I thought I'd share my findings in the configuration and use of the Shift Register.

The Shift Register (SR) can be used in a number of different ways as described in the datasheet. I was particularly interested in Mode 5 (T2 control). I wanted to work out how to get the 6522 to generate serial 8-bit data bytes out on CB2 with an associated clock on CB1. In addition, I wanted to have CA2 generate a handshake (latch) signal after the SR output completes.

The idea behind this was to feed the serial data, clock and latch to a 74HC595 serial to parallel shift register. The final result would see me sending parallel data from the CPU, to the 6522, convert to serial, send to 74HC595 to observe the parallel output on connected LEDs. This might sound a bit convoluted, but if successful, I can honestly say I've understood fully what's taking place.

6522 Configuration
The 6522 VIA is memory mapped starting at address $D200 - $D20F. The settings below were setup using the monitor running on the 6502 prior to running a small code routine to output data.

Generate handshake pulse on CA2 port:

Configure Port A as outputs, with CA2 pulse handshake. CA2 line is normally held high, writing or reading Port A results in a -ve going pulse on CA2, typically 3 microseconds in duration, returning high.

 $D203   write $FF   set port A as o/ps
 $D20C   write $0A   set Peripheral Ctrl Reg; bit 3 = 1, bit 1 = 1, CA2 pulse output
 $D20E   write $7F   disable all interrupts

To generate a pulse on CA2, either write or read to $D201

Generate Shift Register output on CB2 with clock on CB1:

Shift Register configuration

 $D20B   write $14 set Auxiliary Control Register, Shift Out T2 control
 $D208   write ?? set T2 Low Counter  'n' the value determines the clock value on CB1

formula for 'n'

n = (PH2 / (F x 2)) - 2

PH2  = system clock
F = desired clock frequency for CB1

e.g for a clock frequency of 20kHz, with PH2 of 1mHz, n = $17 (23 Decimal)

Generate serial data, clock and handshake pulse
Initially, I tried putting the data into the registers using the monitor I use with the 6502 computer. This produced inconsistent results, due I believe, to delays associated with the operation of the monitor. To overcome this, I put together a small routine to run in RAM, using the monitor to execute the code, and when complete, the routine restarts the monitor.

The following code puts a data byte into the Shift Register, which appears as serial data on CB2. When the data ends, a short -ve pulse is generated. The +ve rising edge of the pulse will act as a latch function for the 74HC595.

          LDA #$81      ;data byte to shift out
          STA $D20A     ;store in Shift Register
          LDX #$00      ;start delay
          LDY #$10
LOOP:  INX
          BNE LOOP
          DEY
          BNE LOOP
          LDA #$55     ;delay ends store in port A (or a read of $D201 will generate CA2  pulse)
          STA $D201    ;data appears on Port A, CA2 handshake pulse is generated
          JMP $E000    ;back to monitor - start address of my monitor code

One unknown thing that occurred, was that the handshake pulse was produced before the serial data started being transmitted. I guess this is due to the set up time for the Shift Register to start doing its activity, whilst writing to Port A and CA2 output takes microseconds to complete. To overcome this, I included a delay to ensure the CA2 pulse occurs after the serial data has completed.

I worked out that to accommodate the extremes of the Shift Register clock speeds, highest being 250kHz to lowest 1.945kHz, the delay code would be:

For highest clock speed setting on T2 [T2=00] clock 250kHz

         LDX #$F7     ;with T2=0, CA2 pulse appears ~18uSecs after last CB1 clock pulse
loop INX
BNE loop

For lowest clock speed setting on T2 [T2=FF] clock 1.945kHz, additional delay is required

       LDX #$00     ;with x = 0, y = 4, CA2 pulse appears ~1mSec after last CB1 clock pulse]
         LDY #$04
loop   INX
        BNE loop
        DEY
        BNE loop

If the delay routine for the lowest clock speed is used as the default, the highest shift out rate still works, as the CA2 handshake pulse appears approximately 5mSec after the data is shifted out. If a shorter period is needed before the handshake, this is straightforward to change within the delay loop.

The first oscilloscope image shows:
Trace 1: CA2 'handshake' pulse - occurring approx 1 mSec after data ends
Trace2:  CB1 Shift Register Clock at approximately 1.9kHz, slowest clock speed
Trace3:  CB2 Shift Register Data - value $55


-ve Strobe, 8-bits of clock, 8-bit data $55


The second oscilloscope image shows:
Trace 1: CA2 handshake line (nothing showing, pulse off to the right)
Trace 2: CB1 Shift Register Clock at maximum speed 250kHz
Trace 3: CB2 Shift Register Data - value $81


250kHz clock, 8-bit data $81


The third oscilloscope image shows:
Trace 1: CA2 handshake line pulse, some 5mSec after SR data ends
Trace 2: CB1 Shift Register Clock @ 250kHz
Trace 3: CB2 Shift Register Data 


-ve strobe, clock & data (time-base compressed)


Serial data/clock to 74HC595 shift register
To check the data, clock and latch is going to work correctly with the 74HC595, the 6522 was connected to the 74HC595 as detailed below:


6522 VIA to 74HC595 connections (serial to parallel converter)


With LEDs connected via resistors to the 74HC595 QA-QH outputs, I ran the code above and confirmed that the outputs matched the byte data I supplied to the 6522 Shift Register.

The next phase of experiments will be with inputting data into the 6522 Shift Register.

I will be using an Arduino UNO to generate the serial data, clock and a strobe signal. I've used this capability, interfaced to the 74HC595 and proved the data, clock and strobe/latch timings work. As an example of what can be achieved with a small amount of Arduino coding, the sketch and the oscilloscope image is below. The UNO output - a similar representation of what I've got out of the 6522 as described above.

Trace 1: 'strobe or latch' rising +ve after serial data ends
Trace 2: serial clock, 8-bits
Trace 3: serial data, $81


Arduino UNO 'latch, clock & data ($81)


Arduino Sketch:
// Sketch to generate 8-bit serial data, to send to 74LS595 shift register.
// Code sends 8-bit values as serial with clock and latch/strobe
// Monitor the 74LS595 parallel data outputs to ensure the serial data, clock and strobe works
// to apply to 6522 VIA serial to parallel.
// Pin 2 used for serial data
// Pin 3 used for clock
// Pin 4 used as latch/strobe
// Code based on Arduino Tutorial shift out
// When the clock pin goes Low to High, the shift register reads the state of the data pin.
// Once all 8 bits of the data has been clocked in, the latch or strobe goes Low to High
// and the internal 8 bits in the 74LS595 are moved from the register memory to the output pins.
// Attaching LEDs with resistors to QA-QH will indicate the byte value.

#define dataPin 2   // data shift out
#define clockPin 3  // clock out 
#define latchPin 4  // strobe/latch

void setup() {
  pinMode(dataPin, OUTPUT);
  pinMode(clockPin, OUTPUT);
  pinMode(latchPin, OUTPUT);
  // according to the Arduino reference for shiftOut(), interfacing with a device that is
  // clocked by rising edges (74595 does), the clock pin should be taken LOW before the
  // call to shiftOut()
  digitalWrite(clockPin, LOW);
  // hold latch low, 74595 o/p doesn't change while sending data
  digitalWrite(latchPin, LOW);
  delay(2000);
}

void loop() {
  for (int j = 0; j < 256; j++){  // count from 0 - 255 and cycle through
    digitalWrite(latchPin, LOW);
    shiftOut(dataPin, clockPin, MSBFIRST, j);
    delayMicroseconds(20); // increased delay for the latching pulse to start
    digitalWrite(latchPin, HIGH);
    delay(1000);
  }

}