Hardware

An investigation into the behaviour of the Yamaha OPL3 chipset.
With a view to a more accurate emulator

Re: Hardware

Postby sto » Fri Oct 30, 2015 6:56 am

Maybe I did something wrong and broke the chips, but could you please help? I wired it all up, with the reset and master clock signals running through the quad buffer chip to amplify them. The quad buffer (HCT125) is powered from the 5V supply from the teensy, and the clock and reset signals are connected to the inputs. The inverter pins are not wired at all, and the master clock signal comes from one of the PWM pins from which I try to produce a 12MHz signal. The OPL3's supply pin is also connected to the 5V source, and all other pins are connected either to the teensy or the quad buffer. They're all connected directly, i.e. no capacitors or resistors are present.

//edit: I should say that the problem is that I don't get the SY signal to work.

Here's the code I'm using to communicate with the chip:
Code: Select all
#include <TimerThree.h>

constexpr int OPL_MASTERCLOCK = 3;
constexpr int OPL_IC = 1;
constexpr int OPL_D2 = 2;
constexpr int OPL_D3 = 0;
constexpr int OPL_D4 = 4;
constexpr int OPL_D5 = 5;
constexpr int OPL_D6 = 6;
constexpr int OPL_D7 = 7;
constexpr int OPL_SMP_BD = 8;
constexpr int OPL_SMP_AC = 9;
constexpr int OPL_DO_AB = 10;
constexpr int OPL_DO_CD = 11;
constexpr int OPL_SY = 12;

constexpr int OPL_D1 = 16;
constexpr int OPL_D0 = 17;
constexpr int OPL_TEST = 18;
constexpr int OPL_CS = 19;
constexpr int OPL_RD = 20;
constexpr int OPL_WR = 21;
constexpr int OPL_A1 = 22;
constexpr int OPL_A0 = 23;

constexpr unsigned int Masterclock = 12e6; // 14.31818e6;
constexpr unsigned int SmpRate = Masterclock/288;
constexpr unsigned int SyRate = SmpRate*36;
volatile int toggleCounter = 0;
int toggleTs = 0;

void masterToggle()
{
  static bool state = false;
  state = !state;
  if(state) {
    digitalWrite(OPL_MASTERCLOCK, HIGH);
    digitalWrite(13, HIGH);
  }
  else {
    digitalWrite(OPL_MASTERCLOCK, LOW);
    digitalWrite(13, LOW);
  }
  ++toggleCounter;
}

void setup() {
  Serial.begin(9600);
 
  // put your setup code here, to run once:
  pinMode(OPL_IC, OUTPUT);
  pinMode(OPL_A0, OUTPUT);
  pinMode(OPL_A1, OUTPUT);
  pinMode(OPL_WR, OUTPUT);
  pinMode(OPL_RD, OUTPUT);
  pinMode(OPL_CS, OUTPUT);
  pinMode(OPL_TEST, INPUT);
  pinMode(OPL_D0, INPUT);
  pinMode(OPL_D1, INPUT);
  pinMode(OPL_D2, INPUT);
  pinMode(OPL_D3, INPUT);
  pinMode(OPL_D4, INPUT);
  pinMode(OPL_D5, INPUT);
  pinMode(OPL_D6, INPUT);
  pinMode(OPL_D7, INPUT);
  pinMode(OPL_SMP_BD, INPUT);
  pinMode(OPL_SMP_AC, INPUT);
  pinMode(OPL_DO_AB, INPUT);
  pinMode(OPL_DO_CD, INPUT);
  pinMode(OPL_SY, INPUT);
  pinMode(OPL_MASTERCLOCK, OUTPUT);
  pinMode(13, OUTPUT);

  //analogWriteResolution(1);
  //analogWriteFrequency(OPL_MASTERCLOCK, Masterclock);
  tone(OPL_MASTERCLOCK, Masterclock);

  digitalWrite(OPL_CS, LOW);
  delay(10);
  digitalWrite(OPL_IC, HIGH);
  delay(100);
  digitalWrite(OPL_IC, LOW);

  //Timer3.initialize(1); // 1.0e6/(Masterclock*2));
  //Timer3.attachInterrupt(masterToggle);
}

int chAB[2] = {0,0};
int chCD[2] = {0,0};
int dataCtr = -1;
bool chBD = false; // second set of data?

void handleSy()
{
  const bool acState = digitalRead(OPL_SMP_AC);
  const bool bdState = digitalRead(OPL_SMP_BD);

  if(dataCtr < 0) {
    if( dataCtr == -1 ) {
      if(acState) {
        Serial.print("Sync start: ");
        Serial.print(dataCtr);
        Serial.print(" ");
        Serial.print(acState);
        Serial.print(" ");
        Serial.println(bdState);
        dataCtr = -2; // wait for fall
      }
    }
    else if(dataCtr == -2) {
      if(!acState) {
        Serial.print("Sync stop: ");
        Serial.print(dataCtr);
        Serial.print(" ");
        Serial.print(acState);
        Serial.print(" ");
        Serial.println(bdState);
        dataCtr = 16; // wait 2 samples, then start
      }
    }
    return;
  }

  int index = dataCtr%18;
  int ofs = dataCtr/18;

  if(digitalRead(OPL_DO_AB))
    chAB[ofs] |= (1 << index);
  if(digitalRead(OPL_DO_CD))
    chCD[ofs] |= (1 << index);

  ++dataCtr;
  //if(dataCtr == 36)
  //  Serial.println(chAB[0]);
  dataCtr %= 36;
}

void loop() {
  static bool s = false;
  float delta = millis()-toggleTs;
  if(delta>1000) {
    toggleTs = millis();
    Serial.print("Toggle: ");
    //noInterrupts();
    Serial.println(toggleCounter*1000/delta);
    toggleCounter = 0;
    //interrupts();
    //digitalWrite(13, s ? HIGH : LOW);
    s = !s;
  }

    Serial.print(digitalRead(OPL_SY));
    Serial.print(" ");
    Serial.print(digitalRead(OPL_DO_AB));
    Serial.print(" ");
    Serial.print(digitalRead(OPL_DO_CD));
    Serial.print(" ");
    Serial.print(digitalRead(OPL_SMP_AC));
    Serial.print(" ");
    Serial.print(digitalRead(OPL_SMP_BD));
    Serial.print(" ");
    Serial.print(digitalRead(OPL_TEST));
    Serial.print(" ");
    Serial.print(digitalRead(OPL_D7));
    Serial.print(digitalRead(OPL_D6));
    Serial.print(digitalRead(OPL_D5));
    Serial.print(digitalRead(OPL_D4));
    Serial.print(digitalRead(OPL_D3));
    Serial.print(digitalRead(OPL_D2));
    Serial.print(digitalRead(OPL_D1));
    Serial.print(digitalRead(OPL_D0));
    Serial.println("");
 
  auto tm = pulseIn(OPL_SY, HIGH, 1e3);
  if(tm != 0) {
    Serial.print(SyRate);
    Serial.print(" ");
    Serial.println(1.0e6/tm);
  }
  handleSy();
}


Thanks in advance.
sto
 
Posts: 60
Joined: Thu Nov 08, 2012 4:33 am

Re: Hardware

Postby opl3 » Fri Oct 30, 2015 9:12 pm

Hi, I don't know how this Teensy environment works, but my guess is the serial port writes are not buffered, so at 9600 bps, each byte sent to serial port takes about 1.04 milliseconds to transfer, and the SY polling must be done at twice the SY frequency, ~3.6MHz. There's no time for sending serial data, or do nothing much else than just receive the serial bits.

In practice, the SY is not 50% duty square wave, it is 25% duty square wave, so that's why it needs to be polled at ~7.2 MHz.

To capture the data stream, I'd take a look at which hardware module could do it. SPI module is one, but not so convenient solution.
opl3
 
Posts: 55
Joined: Sun Sep 26, 2010 8:11 pm

Re: Hardware

Postby sto » Sat Oct 31, 2015 12:01 am

I'm aware that the current solution is "suboptimal" (to say the least), but the SY doesn't seem to be triggered at all. In fact, I don't seem to get the OPL to do anything at all, as the outputs from the chip are never changing. I'm still trying to get it to do something, and only then I will start fiddling around with reading/transmitting the data.
sto
 
Posts: 60
Joined: Thu Nov 08, 2012 4:33 am

Re: Hardware

Postby synthop » Sun Nov 08, 2015 4:21 pm

Do you have a scope? First thing I do when I bring up a new board or whatever is check the clocks, resets, power, ground. I know it sounds overly basic but often times one of those is the problem.
synthop
 
Posts: 33
Joined: Sun Oct 26, 2014 9:21 pm
Location: Brooklyn, New York, USA

Re: Hardware

Postby sto » Sun Nov 08, 2015 10:22 pm

Well, unfortunately not. The only thing I have at hand is a voltmeter, which isn't of any use anymore, because the soldering points are properly connected. It was my first though to also buy an oscillosope, but everything I found was too expensive for the budget I've set. I'll try to play around with the PWM pins though, as I think I'm not programming them correctly.
sto
 
Posts: 60
Joined: Thu Nov 08, 2012 4:33 am

Re: Hardware

Postby sto » Fri Jan 15, 2016 5:28 pm

Now that I own a oscilloscope, it turns out that I'm only generating a 7kHz master clock...
sto
 
Posts: 60
Joined: Thu Nov 08, 2012 4:33 am

Re: Hardware

Postby synthop » Fri Jan 15, 2016 7:53 pm

Visibility is great isn't is? Glad you crossed that off the list. Keep us updated.
synthop
 
Posts: 33
Joined: Sun Oct 26, 2014 9:21 pm
Location: Brooklyn, New York, USA

Re: Hardware

Postby sto » Fri Jan 15, 2016 11:05 pm

Hm, OK, I managed to get the PWM pin 3 working at 12 MHz and it's producing a nice sine wave. I tried to hook that up to the 74HCT125, but then I realized I need to change the "working point" of the input, because all I get is either HI or LO, independent of the output enable pin (which I hooked up to the PWM pin). The buffer's input should then be the 5V supply from the teensy, the output hooked up the the OPL's master clock, but what should the buffer's supply voltage be, 3.3V, 5V or GND?

I'm a bit overwhelmed by the complexity of hooking it up, so maybe I'll get it working in 2-3 years, once I managed to learn electrical engineering ;)

// EDIT: Turns out, my soldering skills are "optimizable"... time to solder another 74HCT125 onto an adaptor...
sto
 
Posts: 60
Joined: Thu Nov 08, 2012 4:33 am

Re: Hardware

Postby sto » Mon Jan 18, 2016 3:07 am

Turns out that the jump wire board I bought seems to be not that good, too. But at least the OPL produces output, now I need to figure out a way to process the data in time...
Attachments
IMAG002.jpg
IMAG002.jpg (67.26 KiB) Viewed 21062 times
sto
 
Posts: 60
Joined: Thu Nov 08, 2012 4:33 am

Re: Hardware

Postby opl3 » Mon Jan 18, 2016 8:24 pm

I bet the yellow is your 12MHz masterclock (M) from Teensy, and blue is 1.5 MHz bitclock (SY) from YMF262 because it has 25% duty cycle.
opl3
 
Posts: 55
Joined: Sun Sep 26, 2010 8:11 pm

PreviousNext

Return to Yamaha OPL-3 research

Who is online

Users browsing this forum: No registered users and 1 guest

cron