Pages: [1]   Go Down
Author Topic: [SOLVED] Help with the AY-3-8910 IC datasheet!  (Read 942 times)
0 Members and 1 Guest are viewing this topic.
Offline Offline
Full Member
***
Karma: 0
Posts: 100
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi! I'm somewhat experimented in programming but not in electronics.
I am planning to do a little theramin/synth with the AY-3-8910 IC (the one used on NES and so many other old consoles), it doesn't seem too complicated, but there is something I don't understand from the IC datasheet.

DATASHEET: http://www.michael-george-hart.com/articles/computerscience/AY-3-8910_8912-Programmable_Sound_Generator.pdf

From what I undestood, the process of generatin a sound would be:

1) Select LATCH mode by setting BCDIR, BC2 and BC1 to: 111.
2) Send the register ADDRESS through the data bus.
3) Select WRITE mode by setting BCDIR, BC2 and BC1 to: 110.
4) Send the register VALUE through the data bus.

For example: to give the R1 register a value of 0-15 (decimal) and so writing the tune of the channel A.

Now, what I don't understand is how do I select the different registers? What are the addresses? I imagine that the R0 register would be: 00000000, R1: 00000001, R2: 00000010 and so on... but I am not sure of that.

More info on this .rar: http://bulba.untergrund.net/ay8910-2.rar

THANKS A LOT!
« Last Edit: July 20, 2012, 02:33:39 am by Pancra85 » Logged

UK
Offline Offline
Faraday Member
**
Karma: 100
Posts: 4153
Where is your SSCCE?!?!
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Section 2.3 explains it:

Quote
DA7-DA0 correspond to Register Array bits B7-B0. In the address mode, DA3-DA0 select the register # (0-178) and DA7-DA4 in conjunction with address inputs /A9 and A8 form the high order address (chip select)

So, as long as DA7 to DA4 are set to 1, then the rest of the data bits select the register number.  A8 and /A9 can be left unconnected as:

Quote
... each is provided with either an on-chip pull down (/A9) or pull-up (A8) resistor.
Logged

Get 10% off all 4D Systems TFT screens this month: use discount code MAJENKO10

Offline Offline
Full Member
***
Karma: 0
Posts: 100
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hey, thanks for your time!
So, to select R01 the address should be: 11110001, right?

Another question, I am worried about the speed that the data output bite changes, so what about I do this:

1) send register address
2) select latch mode (so it takes the data from step 1)
3) select inactive mode (BDir:0, BC2:1, BC1:0)
4) send register value
5) select write mode (taking the above data)
6) inactive mode again

would that work???
Logged

UK
Offline Offline
Faraday Member
**
Karma: 100
Posts: 4153
Where is your SSCCE?!?!
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Section 2.5.1 and 2.5.2 detail it:

1. NACT
2. Write address to bus
3. INTAK
4. NACT
5. Write data to bus
6. DWS
7. NACT

For reading, it's:

1. NACT
2. Write address to bus
3. INTAK
4. NACT
5. DTB
6. Read data from bus
7. NACT

There's a nice state diagram in section 2.5.
Logged

Get 10% off all 4D Systems TFT screens this month: use discount code MAJENKO10

Offline Offline
Full Member
***
Karma: 0
Posts: 100
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Thanks! Don't think I didn't read the datasheet, I read it a lot of times but didn't see that!
 
Already coded it, now I need to get the 2mhz crystal oscillator, got a crystal but it has 2 pins... I think I needed the 3 one with 3 pins  smiley-confuse
Logged

Offline Offline
Full Member
***
Karma: 0
Posts: 100
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I know I am asking so many things, but please be patient with me, I am new to Arduino!

I tried with a clock circuit and also with a code clock using PIN 3 of Arduino.
I get no sound from any channel, could you please take a look at this code and tell me if I am in the right direction???

On the main loop, just to test for sound on Channel A I do this:

Code:
void loop() {
  delay(3000);
  writeICFun(7,62); //Mixer: channel A only
  writeICFun(1,50); //Channel A course pitch
  writeICFun(8,15); //Volume A to max
}

To write a value to a register I use these functions:

Code:
void writeICFun(int reg,int valor) {
  //address to R01 is 11110001. If reg=1, then we need to add: 11110000 -> 240(dec)
  reg=reg+240;

  inactiveModeFun();
  Serial.println("Write on Reg number: ");
  writeBusFun(reg); //sends address of register
  latchModeFun();
  inactiveModeFun();
  Serial.println("Value to write :");
  writeBusFun(valor); //send value
  writeModeFun(); 
  inactiveModeFun();
}

void writeBusFun(int value) {
  Serial.println(value,BIN); 
  for (int x=0;x<8;x++) {
    digitalWrite(dataPins[x],bitRead(value,x));
  }
  Serial.println("-FIN Write-");
}
void inactiveModeFun(){
  digitalWrite(bdirPin,0);
  digitalWrite(bc1Pin,0);
}
void readModeFun(){
  digitalWrite(bdirPin,0);
  digitalWrite(bc1Pin,1);
}
void writeModeFun(){
  digitalWrite(bdirPin,1);
  digitalWrite(bc1Pin,0);
}
void latchModeFun() {
  digitalWrite(bdirPin,1);
  digitalWrite(bc1Pin,1);
}

Thanks a lot!
Logged

UK
Offline Offline
Faraday Member
**
Karma: 100
Posts: 4153
Where is your SSCCE?!?!
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Code:
void writeICFun(int reg,int valor) {
  //address to R01 is 11110001. If reg=1, then we need to add: 11110000 -> 240(dec)
  reg=reg+240;


Where did you get this information? Standard 8910 chips require all zeros in the four high order address bits.  R01 = 00000001.

From the datasheet: "Unless otherwise specified, address bits DA7--DA4 are programmed to recognize only a 000 code.

Ah, that'll be my fault I', afraid.  Reading one part of the data sheet it reads like they should all be 1 as those, plus A8 and A9 "form the chip select", which to my mind would be (internally, after the inversion of the one A pin) be all 1's.
Logged

Get 10% off all 4D Systems TFT screens this month: use discount code MAJENKO10

Offline Offline
Full Member
***
Karma: 0
Posts: 100
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hahaha, I'm glad you took responsibility for that!
No problem, I'll try again replacing all those "1111" with "0000" on the register addresses and report back.
I saw somewhere else that the high order bits were all "1" but maybe it was something else...
Logged

Offline Offline
Full Member
***
Karma: 0
Posts: 100
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

OH YEAH! The problem was the way I was sending the address for the registers.
I used a library for fast pin switching so I didn't have to use PORT manipulation.

Right now I reached a point where you can play a note with a button and you can change pitch of the note with a pot.

Again, thank you very much to all, especially Majenco and Telecommando for taking the time to help me!

For future generations  smiley-cool I will paste the entire code here:

Code:
#include <digitalWriteFast.h>
//then you can use digitalWriteFast(pin,HIGH/LOW),
//digitalReadFast(pin), pinMode(pin,INPUT/OUTPUT),
//digitalWriteFast2(pin,HIGH/LOW), digitalReadFast2(pin),
//pinMode2(pin,INPUT/OUTPUT)very much as you have used the built-in commands.
//The object code will not only be faster, but actually smaller as well.

//----CLOCK OUTPUT ON PIN 3
const int freqOutputPin = 3; 
const int ocr2aval  = 3;
const int prescale  = 1;
const float period    = 2.0 * prescale * (ocr2aval+1) / (F_CPU/1.0e6);
const float freq      = 1.0e6 / period;
//---------


const int dataPins[] = {4,5,6,7,8,9,10,11};
const int bc1Pin=12;
const int bdirPin=13;
//-------

const int pitchPin=A0;
float oldPitch=-1;
int oldPitchDec=-1;
const int playPin=A1;

void setup() {
  //---for the clock output
  pinMode(freqOutputPin, OUTPUT);
  Serial.begin(9600);
  TCCR2A = ((1 << WGM21) | (1 << COM2B0));
  TCCR2B = (1 << CS20);
  TIMSK2 = 0;
  OCR2A = ocr2aval;

  Serial.print("Period    = ");
  Serial.print(period);
  Serial.println(" microseconds");
  Serial.print("Frequency = ");
  Serial.print(freq);
  Serial.println(" Hz");
  //----
 
  pinMode (bc1Pin,OUTPUT);
  pinMode (bdirPin,OUTPUT);
  pinMode (pitchPin,INPUT);
  Serial.begin(9600);
  inactiveModeFun();
  setDataOutFun();
  resetICFun();
  testSoundA();
}

void loop() {
  float pitch = analogRead(pitchPin);
  pitch=(pitch/1023)*15;
  int pitchDec=(pitch-int(pitch))*255;
 
  if (analogRead(playPin) < 16) {
  writeICFun(13,0);
  }
 
  delay(100);
  if (int(pitch)!=int(oldPitch)) {
    oldPitch=pitch;
    Serial.print("Course: ");
    Serial.println(int(pitch));
    writeICFun(1,int(pitch));
    writeICFun(3,int(pitch));
    writeICFun(5,int(pitch));
  } 
  if (pitchDec-oldPitchDec<10 ||  pitchDec-oldPitchDec>-10){
    oldPitchDec=pitchDec;
    //Serial.print("Fine: ");
    //Serial.println(pitchDec);
    writeICFun(0,int(pitchDec));
    writeICFun(2,int(pitchDec));
    writeICFun(4,int(pitchDec));
  }
 
}

void writeICFun(int reg,int valor) { //maneja valor integer, lo convierte y lo pasa a la otra

  writeBusFun(reg); //buscar dir
  latchModeFun();
  inactiveModeFun();
  writeBusFun(valor); //darle varlor
  writeModeFun(); 
  inactiveModeFun();
}
void writeBusFun(int valor) {
  for (int x=0;x<8;x++) {
    digitalWriteFast2(dataPins[x],bitRead(valor,x));
  }
}

byte readICFun(int reg) {
  writeBusFun(reg); //buscar dir
  latchModeFun();
  inactiveModeFun();
  readModeFun();
  byte valorByte=readBusFun(); //mira valores
  inactiveModeFun();
  return valorByte;

}
byte readBusFun() {
  setDataInFun();
  byte valorByte=0;
  for (int x=0;x<8;x++) {
    bitWrite(valorByte,x,digitalRead(dataPins[x]));
  }
  setDataOutFun();
  return valorByte; 
}

void inactiveModeFun(){
  digitalWriteFast2(bdirPin,LOW);
  digitalWriteFast2(bc1Pin,LOW)
}
void readModeFun(){
  digitalWriteFast2(bdirPin,LOW);
  digitalWriteFast2(bc1Pin,HIGH)
}
void writeModeFun(){
  digitalWriteFast2(bdirPin,HIGH);
  digitalWriteFast2(bc1Pin,LOW)
}
void latchModeFun() {
  digitalWriteFast2(bdirPin,HIGH);
  digitalWriteFast2(bc1Pin,HIGH)
}
void setDataOutFun(){
  for (int x=0;x<8;x++) {
    pinMode(dataPins[x],OUTPUT);
}
}
void setDataInFun(){
  for (int x=0;x<8;x++) {
    pinMode(dataPins[x],INPUT);
}
}
void testSoundA(){
  writeICFun(0,0);
  writeICFun(1,6);
  //delay(6);
  writeICFun(2,0);
  writeICFun(3,6);
  writeICFun(4,0);
  writeICFun(5,6);
  writeICFun(6,1);
  writeICFun(7,int(B11111000));
  writeICFun(8,16);
  writeICFun(9,16);
  writeICFun(10,16);
  writeICFun(11,0);
  writeICFun(12,50);
  writeICFun(13,0);
}
void resetICFun(){
  for (int x=0;x<6;x++){
    writeICFun(x,0);
  }
}

There might be some variables named in spanish language but I changed that, so it's the minority.
Logged

Pages: [1]   Go Up
Jump to: