Help making Arduino work with MOS 6522

I'm trying to set MOS 6522 to "Shift Out controlled by T2 timer" as per the spec.

My goal is to send a parallel pattern of 0s and 1s to the Shift Register, and receive those 0s and 1s in series on CB2 pin; the pattern should be output at T2 rate, continuously, without further engagement from Arduino.

Instead, on running the code I'm getting just one pulse on CB2 and nothing else. What am I doing wrong?

Here's my setup:

Here's my code:

// Define Arduino pin constants to correspond with MOS6522 pins

const byte CS1 = 24; // Chip Select 1
const byte CS2 = 23; // Chip Select 2
const byte RS0 = 38; // Register Select 0
const byte RS1 = 37; // Register Select 1
const byte RS2 = 36; // Register Select 2
const byte RS3 = 35; // Register Select 3
const byte RW  = 22; // Read-Write Line
const byte D0 =  33; // Data Bus 0
const byte D1 =  32; // Data Bus 1
const byte D2 =  31; // Data Bus 2
const byte D3 =  30; // Data Bus 3
const byte D4 =  29; // Data Bus 4
const byte D5 =  28; // Data Bus 5
const byte D6 =  27; // Data Bus 6
const byte D7 =  26; // Data Bus 7

const byte CLOCKOUT = 11;  // Mega 2560 clock goes to 

void setup() {

    // set all digital ports to output mode

  int inMin = 11; // Lowest input pin
  int inMax = 38; // Highest input pin

  for(int i = inMin; i <= inMax; i++)
    {
      pinMode(i, OUTPUT);
    }
  
  // set up 1 MHz timer on CLOCKOUT (OC1A)
  pinMode (CLOCKOUT, OUTPUT); 
  // set up Timer 1
  TCCR1A = bit (COM1A0);               // toggle OC1A on Compare Match
  TCCR1B = bit (WGM12) | bit (CS10);   // CTC, no prescaling
  OCR1A = 7;                          // output every eight cycle
  
  // per 6522 datasheet:
  // "selected MCS6522 register will be accessed when CS1 is high and CS2 is low"
  digitalWrite(CS1, HIGH);
  digitalWrite(CS2, LOW);

  // RW needs to be low too
  digitalWrite(RW, LOW);

  
  // first set Register Select to select ACR (1011):
  delay(1);
  digitalWrite(RS3, HIGH);
  digitalWrite(RS2, LOW);
  digitalWrite(RS1, HIGH);
  digitalWrite(RS0, HIGH);
  
  // then set the ACR to enable Shift Out 
  // Start by zeroing the 3 relevant ACR bits (000):
  delay(1);
  digitalWrite(D4, LOW);
  digitalWrite(D3, LOW);
  digitalWrite(D2, LOW);

  
  // then set to Shift Out, shift rate controlled by T2 (101):
  delay(1);
  digitalWrite(D4, HIGH);
  digitalWrite(D3, LOW);
  digitalWrite(D2, HIGH);
  
  // now set Register Select to select T2C-L timer (1000):
  delay(1);
  digitalWrite(RS3, HIGH);
  digitalWrite(RS2, LOW);
  digitalWrite(RS1, LOW);
  digitalWrite(RS0, LOW);
  
  // set T2C-L timer to a value, say A0 (10100000)
  delay(1);
  digitalWrite(D7, HIGH);
  digitalWrite(D6, LOW);
  digitalWrite(D5, HIGH);
  digitalWrite(D4, LOW);
  digitalWrite(D3, LOW);
  digitalWrite(D2, LOW);
  digitalWrite(D1, LOW);
  digitalWrite(D0, LOW);

  // now set Register Select to select Shift Register (1010):
  delay(1);
  digitalWrite(RS3, HIGH);
  digitalWrite(RS2, LOW);
  digitalWrite(RS1, HIGH);
  digitalWrite(RS0, LOW);

  // send a pattern to Shift Register (e.g. 00011000)
  delay(1);
  digitalWrite(D7, LOW);
  digitalWrite(D6, LOW);
  digitalWrite(D5, LOW);
  digitalWrite(D4, HIGH);
  digitalWrite(D3, HIGH);
  digitalWrite(D2, LOW);
  digitalWrite(D1, LOW);
  digitalWrite(D0, LOW);

}

void loop() {

}

But - just - Why? :astonished:

That is serious "retro" stuff! Sure, it is a shift register and a number of other things, but what is so good about using it? :thinking:

(It is not very fast as microcontrollers and peripherals currently go.)

1 Like

Maybe OP is like me and has stock of ancient Z-80 SIO and CTC chips in the basement :wink:

Haha, using the MOS 6522.

But you do you.

We curious, why?

a7

Not really wrong but of little help:

  • Draw circuit diagrams instead of Fritzing spaghetti. Then everybody can see easily whether you use T1 (in code) or T2 (description).
  • use ports for the address and data with less output statements and immediately readable addresses. You also may want to use the Mega 8-bit interface, but that's not a requirement.

Certainly wrong:

  • set all data bits/pins, don't assume anything about the states of omitted pins.
  • force a write cycle for each data byte using the Phi2 pin.
  • blame the writer of your code for ignorance of the most basic microprocessor protocols.

Why did you not use the External Memory Interface feature of the 2560? The bus timing signals are available on I/O pins, to map memory mapped devices like the 6522 directly to the AVR memory space. See chapter 9 of the data sheet. You might need some simple glue logic but it would probably be worth it.

It looks like you just set up some output bits and wait for a millisecond. The sketch doesn't seem to be doing anything with the DataReady and DataTaken signals that trigger the read and write cycles.

Thank you all so much for responding. This is very helpful already. Answering questions, and asking more:

  1. Yes, I am ignorant of basic microcontroller protocols! To be honest for this project (see below) I need some kind of shortcut or recipe which I don't have to fully understand but which works. The focus of this project is sound, not communication protocols. But ultimately I am eager to learn, and if there are good books or courses which someone could recommend, I will make use of them, as the subject seems fascinating in itself.

  2. Why 6522? The whole project is my attempt to understand the mechanics of sound generation in one "retro" computer. That computer (Lisa) can produce sound by — among other methods — setting a timer and sending a byte of data to the Shift Register, which triggers a series of bits to be sent to Motorola 3417. The content of the byte can simulate various wave shapes while the timer controls frequency. I want to recreate this using Arduino for my own understanding and for fun. I'm also writing an article on computer sound which I'm not pointing to here to avoid shameless plugs... My primitive approach to programming Arduino probably stems from the fact that Lisa takes care of the communication with 6522 in the background while the programmer can just program the sound machine like this (omitting a few additional aspects of sound here which are irrelevant to this topic):

     ANDI.B  #$E3,ACR1(A0)   ;clear shift mode bits
     ORI.B   #$10,ACR1(A0)   ;set shift reg for continuous rotate
    
     MOVE.B  D0,T2CL1(A0)    ;set frequency
     MOVE.B  #$0F,SHR1(A0)   ;set for square wave and trigger
    
  3. So given all your advice above, I think I'm looking for either of:

    • a shortcut or tutorial for dummies: how to take care of forcing write cycles / DataReady/DataTaken signals in the fastest possible way — something that will just work and which I can only later spend time on understanding; I want to focus on the content of the byte sent to SR, and how it affects sound, not on the mechanics of how that byte is sent
    • or a tutorial on External Memory Interface which was mentioned, if that can somehow abstract me from the timing aspects and where I can write to 6522 almost as if I would in assembly language

What is the point of that? And you contradict yourself:

The whole project is my attempt to understand the mechanics of sound generation in one "retro" computer.

There are plenty of books from the 1980s on that topic, when "retro" computers were what people had. Google "sound generation" together with "Atari, Commodore, C-64, Apple" etc. to find them. Plenty of stuff on line, too: SID - C64-Wiki

1 Like

No kidding. KIM-1, haha.

Hal Chamberlin literally wrote the book on that

If you want ppl to be able to follow along at home, select a modern part.

a7

There is no shortcut for this. You've made it more difficult by using esoteric vintage parts. Much, much more difficult. I'm not saying, don't do this, but realize your own limitations and the huge scope of the project.

You could probably bypass the 6522 and just drive your hardware directly from Arduino pins. If there are not enough, use a Mega.

The Arduino has a timer controlled shift register. It's called SPI.

Then abandon this project right now because...

After a closer look at the data sheets I think that you should be willing and able to implement the basic read and write cycles, according to Figure 21/22 and A.C. Characteristics in the VIA data sheet, using assembly code and/or external circuitry.

The Mega XMEM interface is not applicable to the VIA chip, at least not without additional circuitry.

As long as you are the only one with access to such a chip you are the only one who can verify proper operation of the suggested hard and software.

It's an "Intel" protocol. You can create the "Motorola" memory interface that the 6522 uses from it, with a few logic gates.

It's not beginner stuff, though...

Yes for memory chips, but not for a dynamic VIA that requires a continuous clock signal of 0.5 to 2 MHz.

It's possible to derive an E clock from the CPU clock, but it's a huge hassle to configure the fuses and board to extract that from the processor.

A timer is sufficient for that purpose. The problems reside in the synchronization of the CS and data signals.

I'm looking at figure 9-3 on page 29 of the 2560 data sheet. I've seen an Intel to Mot conversion circuit before, that handles this. Basically, E is derived from the system clock and runs continuously. It is the source of synchronization. Then all that is needed is to combine ALE, R, and W to produce a R/W signal. It will generate "gratuitous" or unused read memory accesses, but it should work.

In the Mot universe, chip selects are usually just tied to memory address lines, or signals decoded from them. Possibly, they could be gated with ALE to eliminate the unused read accesses.

But, why? If you want to reproduce a Lisa, you would just use a 68000. :slight_smile:

The "Intel" method follows closely the S-100 bus spec which is why it uses separate R and W signals, they control bus buffers on the S-100 cards.

Thank you all again. Still not fully understanding what I'm doing, I tried following DrDiettrich's advice and looked at how Chip Select and R/W lines are set up. Turns out that enabling CS before any writing to the chip, and then disabling after all register write operations are done, correctly starts the shift out operation.

The oscilloscope screenshots below show the 101110101 pattern repeatedly occurring on CB2 pin (yellow), with the corresponding generated clock ticks on CB1 pin (blue). They align nicely.

However, I'm still struggling with one thing. The shifting always stops at certain point by itself. When it stops seems to depend on the least significant bit of the pattern, so pattern 101110101 will stop after 1 to 30-odd runs, while 101110100 will stop after much longer, 8-10 seconds:

I don't understand why. Once put in "free-running" mode (100), the chip should send the pattern continuously, and in my case it always stops. I tried powering the chip from both 5V and 3.3V lines, using different frequencies of the ϕ2 clock, even connecting a clock from outside of Arduino, changing patterns, switching to more reliable power source, etc. to no avail.

Ultimately, the 8-10 second runs will be enough for my sound experiments so my problem is sort of "solved", but I'm curious what may be causing this.

Regarding alto777's recommendation of Musical Applications of Microprocessors — this is amazing, I didn't know that book existed. Will definitely read.

You are writing any number of intermediate patterns to the chip. If you apply a continuous clock signal and modify one data bit after another then you should only select the chip after all data bits are valid and then deselect again.

It will be safer and shorter to code if you access Mega ports and update all 8 data bits at once.

Some versions of the 6522, had a timing flaw, to do with hold time between clock and R\W.

Caused absolute havoc at one point in the production of the BBC Micro.