PIA Chips – 6820

The 6820 PIA (Peripheral Interface Adapter) chips are how the M6800 talks to the outside world. They’re used to either latch data to send to the lamps, display, or solenoids, or they’re used to grab input data and hold it for the processor to read. With only 8 data lines, the M6800 needs other chips to split out enough lines for all the data (input and output). These are those chips.

Each chip (U10 & U11) has two 8-bit I/O ports (PORT A & PORT B), two interrupt input lines (CA1 & CB1), and two other control lines (CA2 & CB2). To access the chips, they’re given four address lines. U10 is mapped to 0x88, 0x89, 0x8A, and 0x8B. U11 is mapped to 0x90, 0x91, 0x92, and 0x93. Because I’m only using five address lines to access those two chips (A0, A1, A2, A3, and A4), the address space used by the Arduino looks like 0x14 through 0x1B.

  • MPU A0 = Arduino A0
  • MPU A1 = Arduino A1
  • MPU A3 = Arduino A2
  • MPU A4 = Arduino A3
  • MPU A7 = Arduino A4

Note: I happen to be using the “Analog” pins on the Arduino for the address space, that’s why they’re named A0, A1, etc.

To read from the PIAs, all we have to do is set the Arduino data lines to input (pins 5-12), put the right address on A0-A4, set the R/W line high (Arduino pin 3), wait for a falling edge of the clock (Arduino pin 4), and pulse the VMA line (Arduino pin A5). As soon as the clock goes high again, we can read 8 bits of data on pins 5-12. The timing of these signals can be found in the 6820 datasheet.


byte BSOS_DataRead(int address) {
  
  // Set data pins to input
  // Make pins 5-7 input
  DDRD = DDRD & 0x1F;
  // Make pins 8-12 input
  DDRB = DDRB & 0xE0;

  // Set R/W to HIGH
  DDRD = DDRD | 0x08;
  PORTD = (PORTD | 0x08);

  // Set up address lines
  PORTC = (PORTC & 0xE0) | address;

  // Wait for a falling edge of the clock
  while((PIND & 0x10));

  // Pulse VMA over one clock cycle
  // Set VMA ON
  PORTC = PORTC | 0x20;
  
  // Wait while clock is low
  while(!(PIND & 0x10));

  byte inputData = (PIND>>5) | (PINB<<3);

  // Set VMA OFF
  PORTC = PORTC & 0xDF;

  // Wait for a falling edge of the clock
// Doesn't seem to help  while((PIND & 0x10));

  // Set R/W to LOW
  PORTD = (PORTD & 0xF7);

  // Clear address lines
  PORTC = (PORTC & 0xE0);

  return inputData;
}

Note: I access the Arduino ports (PORTD, PORTC) and the data direction registers (DDRD) directly because it’s so much faster than digitalRead(pin).

BSOS_DataWrite(int address, byte data) works in much the same way. Here’s a link to the code so you can review it if you’d like to:
https://github.com/MrEkted/BallySternOS

With the ability for the Arduino to read & write the PIA chip, it’s just a matter of understanding how that chip works and how it’s expected to talk to the rest of the board.

U10 is primarily concerned with reading the switches and controlling the lamps, but it also has a hand in strobing the display latches. Port A is used for output. PA0-PA4 strobe the switch banks. PA0-PA7 also output the lamp addresses & data. PA0-PA3 are also used to strobe the display latches. The pins can be used for different purposes because they’re carefully shared between the two different parts of the ISR. Details of this sharing can be found in the sections on display, lamps, and switches.

U10 Port B is the only input port. When a switch line is strobed, it allows power to flow through a bank of 8 switches and the values are then read back on U10 Port B.

U11 is used for the displays and solenoids. Port A is used for the display digit enable lines (PA1-PA7). Both of the machines that I have only used 6-digit displays, so PA1 is useless. PA0 is used for the 5th display latch strobe (credit & ball in play display).

U11 Port B controls the solenoids. PB0-PB3 are for momentary solenoid control (pop bumpers, slingshots, chimes, etc.), and PB4-PB7 are for continuous solenoids (flippers & coin lockout).

Configuring a port on one of the PIA chips requires at least 3 writes. (the example below assumes we’re talking about Port A)

  • Write #1 = setting up the control register to describe the behavior of CA1 interrupt, CA2 control line, and telling the chip that the next port write should affect the direction register.
  • Write #2 = telling the direction register which bits are input and output
  • Write #3 = changing the control register so the next read/write affects the actual port
  • Write #4 (optional) = setting the default value for the port if it’s an output port

The control register bits look like this (the example below assumes we’re talking about Port A):

  • B7 = the interrupt bit – it’s high if an interrupt has occurred on pin CA1
  • B6 = an interrupt bit for CA2 (but we always use CA2 or CB2 as output, so we never have this bit set)
  • B5, 4, 3 = the behavior of CA2
    • in our case, B5 and B4 are alway set, meaning that when we write B3 the line will reflect whatever we write
  • B2 = unset means we’re writing the data direction register, and set means we’re writing to the port
  • B1, 0 = behavior of interrupt pin CA1
    • 0x01 is interrupt on falling edge
    • 0x03 is interrupt on rising edge

Here are the values, in order, we’re going to write:

  • U10 Control Register A = 0x38, which means turn on CA2 and we want to write to the DDR (data direction register)
  • U10 A = 0xFF, all pins output (used for lamp data/address, switch strobes, and display latch strobes)
  • U10 Control Register A = 0x3C, same as above, but next write is to the register, not the DDR
  • U10 A = 0xF0, make pins 0-3 low and 4-7 high
  • U10 Control Register B = 0x33, which means turn off CB2, and we want CB1 to be an interrupt on a rising edge (for the zero-crossing interrupt)
  • U10 B = 0x00, all pins input (for the switches)
  • U10 Control Register B = 0x37, same as above, but next time we access U10 B we’re going to read from the port
  • U11 Control Register A = 0x31, which means turn off CA2, and we want a falling edge interrupt on pin CA1 (for the 320Hz timer)
  • U11 A = 0xFF, all pins output (A0 used for display latch strobe 5, A1-A7 used for display digit enable)
  • U11 Control Register A = 0x35, same as above, but next time we write to U11 A we’re writing to the port
  • U11 A = 0x00, all data lines off for now
  • U11 Control Register B = 0x30, which means turn off CB2 so solenoids will be enabled, and we don’t care about an interrupt on CB1
  • U11 B = 0xFF, all pins output (A0-A3 are momentary solenoid data, and A4-A7 are continuous solenoids)
  • U11 Control Register B = 0x34, same as above, but next time we’re writing to U11 B we’re writing to the port
  • U11 B = 0x9F, B6 and B5 are to engage flippers and coin lockout (off is powered for solenoids), and B3-B0 turn off all momentary solenoids because 0x0F means don’t engage any solenoids

This is a lot of information, I know. It only makes sense when you really get into the nuts and bolts of how this hardware is addressed. Not to worry, I’ve already been through every bit listed here and figured out what makes them work. If you have any questions or corrections, please let me know.

With those two chips configured, we’re ready to start getting interrupts on the Arduino and reading/writing the ports. One very important note: an interrupt is cleared on a PIA only when the associated port is read. So when U10:CB1 gets an interrupt from the zero-crossing circuit, the only way that it will be cleared is when U10:Port B is read. This almost makes sense for U10:Port B because it’s an input port (reading the switch returns). It makes far less sense for U11:Port A. That’s an output port, but the only way to clear an interrupt on U11:CA1 (the 320Hz timer) is to read from U11:Port A and throw away the value.

Read about the display interface. >

< Go back to MPU Overview

Leave a Reply