Jump to content

johnnye79

New Members
  • Content Count

    9
  • Joined

  • Last visited

Posts posted by johnnye79


  1. I'm all about sound, but unsure what you are trying to do.

    There is the detailed operation above of what the hardware is doing to produce sound.

    That results in the 319 tones and noises you can use in the 2 channel output for notes and percussion.

     

    That's my business mate. ;)

     

    Kidding.

     

    It would be great to know in making a ***NON-COMMERCIAL*** open source VSTi (translated: I'm here for the good of the community), also some hardware projects I'm doing with embedded microcontrollers (STM32 NUCLEO F103RB for example) for neat sound effects, playing music, etc. I understand TIATracker exists, but TIATracker looks like it's for playing music on an Atari cart. Plus, I like to learn things, plus, there's a lot of practical applications I can think of right now for various projects.

     

    I want to get Atari notes in tune with normal piano frequencies by changing the pitch/speed to get them in tune (this can be done procedurally in OpenAL just by changing pitch parameters on a looping sample (1.0 plays at normal frequency, 1.054467467 plays higher, 0.9543954 plays lower, etc), trying to do it with a wav file in Audacity though seems to only go to 3 decimal places).

     

    So far I've used a pitch detection plugin in Audacity to detect the pitches, it uses a YIN algorithm (the plugin is written in Nyquist so a lot is left behind the scenes, I'm looking at a pure C/C++ implementation), and I'm not 100% sure of its accuracy. There are other pitch detection algorithms I'll probably have to look at to determine the best one.

     

    In your picture above what was the method used to determine how many cents a note is off? Is there a mathematical method to it or is that all done by ear? (I'm not implying that one method is better than the other, after all, it all comes down to what sounds pleasing to the ear.)

     

    Why are some of the instruments missing in the above picture? (2, 3, 8, those are some of the best Atari instruments!)

     

    Last bit is trying to figure out how to make a 31400Hz clock in C++ for mbed for audio output, which has proven a little cumbersome since you only get up to microsecond resolution, so I'll have to figure out a clock based on CPU cycles (I have some 72Mhz and 180Mhz STM32s), but that's a side issue.


  2. These are the frequencies I analyzed based on a Pitch Detection plugin for Audacity written in Nyquist. I don't know enough yet about Nyquist to see where in the code it's rounding off and truncating frequencies. Clearly it's rounding to the nearest Hz. I wonder if there's a better way to figure it out? I'd like to know those exact frequencies so I know how detuned an instrument is.

        const float *startingFrequencies[15] = {
            400.0f, // Sample 01
            13.0f,  // Sample 02
            172.0f, // Sample 03
            616.0f, // Sample 04
            616.0f, // Sample 05
            39.0f,  // Sample 06
            39.0f,  // Sample 07
            592.0f, // Sample 08
            405.0f, // Sample 09
            39.0f,  // Sample 10
            0.0f,   // Sample 11
            200.0f, // Sample 12
            200.0f, // Sample 13
            12.0f,  // Sample 14
            405.0f  // Sample 15
        };
    

  3. I'm learning about the Atari 2600's sound and have some questions regarding frequency, it has to do with shifting pitches.

     

    How do I obtain the fundamental frequency of a note from the Atari 2600 that's sampled at 31400Hz, with a frequency (AUDF) divisor of 25 for each instrument so that I can shift them in pitch to piano notes?

     

    (This is understandably a mix of programming, mathematics, and music theory, so I'm posting it here.)

     

    So I've sampled small 8-bit Mono WAV files for each instrument (sampled at 31400Hz) with a divisor of 25 at their repetitions. So for example since instrument 8 has a repetition every 511 runs, I ran my Python code to output a wav of 26*511 samples (26 because count goes from 25 to 0) at frequency 25, and I've done this for each sound file so that I get a nice perfectly looping wav file.

     

    My question comes down to how to understand what pitch that sample is at, so that I can shift its pitch to notes that are in tune with piano frequencies. I've tried doing some analysis on the samples in Audacity, but of course see frequency ranges all over the spectrum. So I suppose I need to understand how to attain the fundamental frequency of the sample so that I shift the pitch (this is easily done in OpenAL by specifying a float that determines the multiplier for scaling the pitch).

     

    I've looked at the "Atari 2600 Frequency and Tuning Chart for NTSC" but that only seems to show some information about 5 of the instruments, I'm guessing the whole concept of "Setups" is specific to Paul Slocum's Synthcart, and I'm unsure how they came to the conclusion that a particular note from the 2600 was X number of cents above or below a certain note/octave.


  4. I don't think TIA ever worked with any variant of C or Phython. Have you tried ASM? ;)

     

    Stella is written in C you know. :P

    Would be great if Stella would let me put debug watches the AUDXX registers while playing without frame stepping in the debugger. Guess I'll have to mod the source at some point.

     

    The software portion of my project is working at least, just had to set PyAudio to output 16-bit samples instead of 8-bit. (Even though my samples look like they're 8-bit?... O_o) Now to translate it all to a VSTi, there's of course still the issue of frequency translation. (Also turns out that I was smoking crack, instrument 11 is not played on the TIA apparently.)


  5. I'm playing around both with emulation code (porting Stella's code to python for testing) and with hardware (I have 2 TIA chips, one from eBay and one that I extracted from a 2600 Jr).

     

    Basically I'd love to write a single channel open source VSTi for the TIA (note: I am not concerned with the $95 Plogue, and right now don't care about emulating the POKEY or any other chipset) that you can plug into your DAW (note: TIATracker does not count, that's a tracker not a VSTi).

     

    (Note: this is also for hobby, fun, learning, and most importantly sharing :) )

     

    I'd also like to toy around with the hardware on the TIA on one of my actual chips, and have it mostly wired up to my Arduino, but am running into issues and need help.

     

    My Arduino mapping looks like this:

    GND to 1 (Vss)

    +5V to 20 (Vcc)

    Crystal Oscillator output (3.5Mhz) to 11 (OSC)

    D2-D7 on Arduino to TIA D0-D5 respectively, writing LSB to D0

    A0-A5 on Arduino (writing as digitalWrite outputs) to TIA A0-A5 respectively, writing LSB to A0

    D11 on Arduino to RW

    D12 on Arduino to Phi-2

    +5V to CS2, GND to CS1,CS3,CS4

    AUD1/2 to LM386 amp to speakers

     

    When I run it, my speakers make a horrible screaming sound like the sound on Doom 3 when you're going through a teleporter...??

     

    Either my wiring needs to be fixed, my Arduino sketch (included below) needs work...

    or I need a young priest, an old priest, some holy water, and some lasers for good measure.

     

    Arduino code:

    const unsigned char Sound[2] = {0x15,0x16}; // 4-bit D3-D0: 0 = voice 1, 1111 = voice 16
    const unsigned char Freq[2] = {0x17,0x18}; // 5-bit D4-D0: 0 = no division, 11111 = divide by 32
    const unsigned char Vol[2] = {0x19,0x1A}; // 4-bit D3-D0: 0 = no output, 1111 = highest
    
    // Set RW to Low
    // Set CS high then low to strobe
    
    //const int Ready = 10;
    const int ClockSync = 11; // Phi-2 on the Atari
    const int ReadWrite = 12;
    
    void setup() {
      Serial.begin(9600);
      delay(500);
      Serial.println("Initializing...");
      // put your setup code here, to run once:
    
      // data bus pins
      pinMode(2,OUTPUT);
      pinMode(3,OUTPUT);
      pinMode(4,OUTPUT);
      pinMode(5,OUTPUT);
      pinMode(6,OUTPUT);
      pinMode(7,OUTPUT);
    
      // address pins (set digital)
      pinMode(A0,OUTPUT);
      pinMode(A1,OUTPUT);
      pinMode(A2,OUTPUT);
      pinMode(A3,OUTPUT);
      pinMode(A4,OUTPUT);
      pinMode(A5,OUTPUT);
    
      //pinMode(Ready, INPUT);
      pinMode(ReadWrite, OUTPUT);
      // This is Phi-2 on the Atari
      pinMode(ClockSync, OUTPUT);
    
      initAtari();
    
    }
    
    void initAtari() {
      digitalWrite(ClockSync, 1); 
      digitalWrite(ReadWrite, 1); 
      delay(100);
    }
    
    void AtariWriteTone(int chan, unsigned char volume, unsigned char freq, unsigned char sound) {
      digitalWrite(ClockSync, 1); 
      digitalWrite(ReadWrite, 1); 
      delay(200);
      writeAddressByte(Sound[chan]);
      writeByteToDataBus(sound);
      digitalWrite(ClockSync, 0); 
      delay(100);
      digitalWrite(ReadWrite, 0); 
      delay(200);
    
      digitalWrite(ClockSync, 1); 
      digitalWrite(ReadWrite, 1); 
      delay(200);
      writeAddressByte(Freq[chan]);
      writeByteToDataBus(freq);
      digitalWrite(ClockSync, 0); 
      delay(100);
      digitalWrite(ReadWrite, 0); 
      delay(200);
    
      digitalWrite(ClockSync, 1); 
      digitalWrite(ReadWrite, 1); 
      delay(200);
      writeAddressByte(Vol[chan]);
      writeByteToDataBus(volume);
      digitalWrite(ClockSync, 0); 
      delay(100);
      digitalWrite(ReadWrite, 0); 
      delay(200);
    }
    
    void writeAddressByte(unsigned char data) {
      int b0 = data & 1;
      int b1 = (data >> 1) & 1;
      int b2 = (data >> 2) & 1;
      int b3 = (data >> 3) & 1;
      int b4 = (data >> 4) & 1;
      int b5 = (data >> 5) & 1;
    
      digitalWrite(A0,b0);
      digitalWrite(A1,b1);
      digitalWrite(A2,b2);
      digitalWrite(A3,b3);
      digitalWrite(A4,b4);
      digitalWrite(A5,b5);
    }
    
    void writeByteToDataBus(unsigned char data) {
      int b0 = data & 1;
      int b1 = (data >> 1) & 1;
      int b2 = (data >> 2) & 1;
      int b3 = (data >> 3) & 1;
      int b4 = (data >> 4) & 1;
      int b5 = (data >> 5) & 1;
    
      digitalWrite(2,b0);
      digitalWrite(3,b1);
      digitalWrite(4,b2);
      digitalWrite(5,b3);
      digitalWrite(6,b4);
      digitalWrite(7,b5);
    
    }
    
    
    
    void loop() {
      // put your main code here, to run repeatedly:
    //  int rdy = digitalRead(Ready);
      //Serial.println("Ready: " + String(rdy));
      //delay(1000);
    
      for (int voice = 0; voice < 16; voice++ ) {
        for (int freq = 0; freq < 32; freq++) {
          Serial.println("Write to Channel 0...");
          AtariWriteTone(0,2,freq,voice);
          //Serial.println("Write to Channel 1...");
          //AtariWriteTone(1,2,freq,voice);
        }
      }
    
    }
    

    Now on to the software side. I've been working today on porting Stella's sound code over to Python for testing as kind of a starting point for my VSTi (this is how I learn, don't judge :P ). It looks like it works, but Instrument 11 (AUDC 0xB) just gives me a high pitched tone on all frequencies. Some of the other instruments I distinctly remember on the VCS being able to go higher frequency. I'm not sure where I'm screwing up here:

     

    Python code (yeah I know, pyAudio is nasty, but it's a starting point):

    import math
    import pyaudio
    import sys
    import struct
    from enum import Enum
    
    class AUDCxRegister(Enum):
        SET_TO_1    = 0x00  #0000
        POLY4       = 0x01  #0001
        DIV31_POLY4 = 0x02  #0010
        POLY5_POLY4 = 0x03  #0011
        PURE1       = 0x04  #0100
        PURE2       = 0x05  #0101
        DIV31_PURE  = 0x06  #0110
        POLY5_2     = 0x07  #0111
        POLY9       = 0x08  #1000
        POLY5       = 0x09  #1001
        DIV31_POLY5 = 0x0a  #1010
        POLY5_POLY5 = 0x0b  #1011
        DIV3_PURE   = 0x0c  #1100
        DIV3_PURE2  = 0x0d  #1101
        DIV93_PURE  = 0x0e  #1110
        POLY5_DIV3  = 0x0f  #1111
    
    class AUDFlags(Enum):
        POLY4_SIZE = 0x000f
        POLY5_SIZE = 0x001f
        POLY9_SIZE = 0x01ff
        DIV3_MASK  = 0x0c
        AUDV_SHIFT = 2
        #AUDV_SHIFT = 10     # shift 2 positions for AUDV,
                          # then another 8 for 16-bit sound
    
    class TIA:
        # It made sense to initialize each TIA audio channel as a separate class object
        # decoupling it from the 2 audio channel coupling of the TIA on the Atari 2600, 
        # so that you could create multiple TIA channels for harmonies such as triad chords.
    
        # Structures to hold the 6 tia sound control bytes
        #myAUDC[2];    // AUDCx (15, 16)
        #myAUDF[2];    // AUDFx (17, 18)
        #myAUDV[2];    // AUDVx (19, 1A)
    
        myVolume = 0 # Last (final) output volume for each channel
    
        myP4 = 0     # Position pointer for the 4-bit POLY array
        myP5 = 0     # Position pointer for the 5-bit POLY array
        myP9 = 0     # Position pointer for the 9-bit POLY array
    
        myDivNCnt = 0 # Divide by n counter. one for each channel
        myDivNMax = 0 # Divide by n maximum, one for each channel
        myDiv3Cnt = 0 # Div 3 counter, used for POLY5_DIV3 mode
    
        #  ChannelMode myChannelMode;
        myOutputFrequency  = 0
        myOutputCounter    = 0
        myVolumePercentage = 0
    
        Bit4 = []
        Bit5 = []
        Bit9 = []
        Div31 = [0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
    
        SoundControl = 0     # This takes the place of myAUDCx
        SoundFrequency = 440 # This takes the place of myAUDFx
        SoundVolume = 15     # This takes the place of myAUDVx
        SoundRate = 44100   
    
        ###################################
        def __init__(self):
            for x in range(0,AUDFlags.POLY4_SIZE):
                self.Bit4.append(0)
            for x in range(0,AUDFlags.POLY5_SIZE):
                self.Bit5.append(0)
            for x in range(0,AUDFlags.POLY9_SIZE):
                self.Bit9.append(0)
            self.reset()
    
        ###################################
        def reset(self):
            self.polyInit(self.Bit4, 4, 4, 3)
            self.polyInit(self.Bit5, 5, 5, 3)
            self.polyInit(self.Bit9, 9, 9, 5)
    
            self.myVolume = 0
            self.myDivNCnt = 0
            self.myDivNMax = 0
            self.myDiv3Cnt = 3
            self.SoundControl = 0
            self.SoundFrequency = 0
            self.SoundVolume = 0
            self.myP4 = 0
            self.myP5 = 0
            self.myP9 = 0
    
            self.myOutputCounter = 0
    
        ###################################
        def polyInit(self, poly, size, f0, f1):
            mask = (1 << size) - 1
            x = mask
            for i in range(0,mask):
                bit0 = ( (x >> (size - f0)) if ( size - f0 ) else x ) & 0x01
                bit1 = ( (x >> (size - f1)) if ( size - f1 ) else x ) & 0x01
                poly[i] = x & 1
                # calculate next bit
                x = ( x >> 1 ) | ( ( bit0 ^ bit1 ) << ( size - 1) )
      
        ###################################
        def setMasterVolume(self, percent):
            if (percent <= 100):
                self.myVolumePercentage = percent
    
        ###################################
        def setOutputFrequency(self, freq):
            self.myOutputFrequency = freq;
    
        ###################################
        def setChannel(self, address, value):
            if address == 0: # (usually this would be AUDC0/AUDC1)
                self.SoundControl = value & 0x0f
            if address == 1: # (usually this would be AUDF0/AUDF1)
                self.SoundFrequency = value # (remember that this number is usually divided by 31400Hz)
            if address == 2: # (usually this would be AUDV0/AUDV1) 
                self.SoundVolume = (value & 0x0f) << AUDFlags.AUDV_SHIFT
            newVal = 0
    
            # An AUDC value of 0 is a special case
            if self.SoundControl == AUDCxRegister.SET_TO_1 or self.SoundControl == AUDCxRegister.POLY5_POLY5:
                # Indicate the clock is zero so no processing will occur,
                # and set the output to the selected volume
                newVal = 0
                self.myVolume = (self.SoundVolume * self.myVolumePercentage) / 100.0
            else:
                # Otherwise calculate the 'divide by N' value
                newVal = self.SoundFrequency + 1
                
                # If bits 2 & 3 are set, then multiply the 'div by n' count by 3
                if ((self.SoundControl & AUDFlags.DIV3_MASK) == AUDFlags.DIV3_MASK and self.SoundControl != AUDCxRegister.POLY5_DIV3):
                    newVal = newVal * 3
    
            # Only reset those channels that have changed
            if (newVal != self.myDivNMax):
                # Reset the divide by n counters
                self.myDivNMax = newVal
                
                # If the channel is now volume only or was volume only,
                # reset the counter (otherwise let it complete the previous)
                if ((self.myDivNCnt == 0) or (newVal == 0)):
                    self.myDivNCnt = newVal
          
        ###################################
        def process(self, buffer, samples):
            bufferPos = 0
            # Make temporary local copy
            audc0 = self.SoundControl
            p5_0 = self.myP5
            div_n_cnt0 = self.myDivNCnt
            v0 = self.myVolume
    
            # Take external volume into account
            audv0 = (self.SoundVolume * self.myVolumePercentage) / 100
    
            # Loop until the sample buffer is full
            while(samples > 0):
                # Process channel 0
                if (div_n_cnt0 > 1):
                    div_n_cnt0 -= 1
                elif (div_n_cnt0 == 1):
                    prev_bit5 = self.Bit5[p5_0]
                    div_n_cnt0 = self.myDivNMax
    
                    # The P5 counter has multiple uses, so we increment it here
                    p5_0 += 1
                    if (p5_0 == AUDFlags.POLY5_SIZE):
                        p5_0 = 0
    
                    # Check clock modifier for clock tick
                    if ((audc0 & 0x02) == 0 or 
                        ((audc0 & 0x01) == 0 and self.Div31[p5_0] > 0) or 
                        ((audc0 & 0x01) == 1 and self.Bit5[p5_0] > 0) or 
                        ((audc0 & 0x0f) == AUDCxRegister.POLY5_DIV3 and self.Bit5[p5_0] != prev_bit5)):
                        if (audc0 & 0x04 > 0):       # Pure modified clock selected
                            if ((audc0 & 0x0f > 0) == AUDCxRegister.POLY5_DIV3): # POLY5 -> DIV3 mode
                                if ( Bit5[p5_0] != prev_bit5 ):
                                    self.myDiv3Cnt -= 1
                                    if ( myDiv3Cnt == 0 ):
                                        self.myDiv3Cnt = 3
                                        if (v0 > 0):
                                            v0 = 0
                                        else:
                                            v0 = audv0
                            else:
                                # If the output was set turn it off, else turn it on
                                if (v0 > 0):
                                    v0 = 0
                                else:
                                    v0 = audv0
                        elif (audc0 & 0x08 > 0):  # Check for p5/p9
                            if (audc0 == AUDCxRegister.POLY9):   # Check for poly9
                                # Increase the poly9 counter
                                self.myP9 += 1
                                if (self.myP9 == AUDFlags.POLY9_SIZE):
                                    self.myP9 = 0
                                if (self.Bit9[self.myP9] > 0):
                                    v0 = audv0
                                else:
                                    v0 = 0
                            elif (audc0 & 0x02 > 0):
                                if (v0 > 0 or (audc0 & 0x01 > 0)):
                                    v0 = 0
                                else:
                                    v0 = audv0
                            else:  # Must be poly5
                                if (self.Bit5[p5_0] > 0):
                                    v0 = audv0
                                else:
                                    v0 = 0
                        else:  # Poly4 is the only remaining option
                            # Increase the poly4 counter
                            self.myP4 += 1
                            if (self.myP4 == AUDFlags.POLY4_SIZE):
                                self.myP4 = 0
                            if (self.Bit4[self.myP4] > 0):
                                v0 = audv0
                            else:
                                v0 = 0
    
                self.myOutputCounter += self.myOutputFrequency;
    
                while((samples > 0) and (self.myOutputCounter >= 31400)):
                    buffer[bufferPos] = v0
                    bufferPos += 1
                    self.myOutputCounter -= 31400
                    samples -= 1
                    #print("TEST")
    
            # Save for next round
            self.myP5 = p5_0
            self.myVolume = v0
            self.myDivNCnt = div_n_cnt0
    
    
    t = TIA()
    t.setMasterVolume(100)
    t.setOutputFrequency(44100)
    t.setChannel(0,int(sys.argv[1]))
    t.setChannel(2,int(sys.argv[2]))
    bufferSize = int(sys.argv[3])
    direction = int(sys.argv[4])
    endBuffer = []
    buffer = []
    for x in range(0,bufferSize):
        buffer.append(0)
    for x in range(0,32):
        freq = x if direction > 0 else 31-x
        t.setChannel(1,freq)
        t.process(buffer,bufferSize)
        endBuffer.extend(buffer)
    
    print("Bit 4")
    print(t.Bit4)
    print("Bit 5")
    print(t.Bit5)
    print("Bit 9")
    print(t.Bit9)
    print("Div 31")
    print(t.Div31)
    
    p = pyaudio.PyAudio()
    
    data = endBuffer
    stream = p.open(format =
                    p.get_format_from_width(1),
                    channels = 1,
                    rate = 44100,
                    output = True)
    stream.write(struct.pack('f'*len(data), *data))
    stream.stop_stream()
    stream.close()
    p.terminate()
    
    

    The next question of course is how to scale my waveforms so that I can use any piano frequency, but I'll save that one for after I get things up to a working state at least. My noob brain at Digital Signal Processing is a little fried right now on wrapping my mind around polynomial counters programmatic loops versus traditional waveforms that can expressed with Fourier series transforms and how to translate between the two. :P


  6. CS pins are used to allow more than one memory or I/O IC on the CPU address and data bus. On the 2600 only 2 of the TIA CS are used (/CS0 and /CS3), the other two are just tied to +5V and GND. The 7800 uses 1 more CS pin . If you don't have anything else sharing the same data and address lines with the TIA, then I guess that you can leave it always selected (that is, pin 21,22 and 24 low and 23 high.

    But don't take my word for it, as this is beyond my basic skills in electronics.

     

    No worries, thanks for the help you could give, definitely appreciated! :)

     

    I do have one question. Earlier up there is a picture with some green highlighted parts. Do you know where the full schematic of that image is? Looks like the top is cut off around the oscillator.

     

    Looks very different from another schematic I saw here so I'm curious as to the design of the oscillator (right now I'm using a 3.5Mhz Crystal Oscillator, may change that to 3.579545Mhz crystal with a custom oscillator):

     

    http://kevtris.org/2600/2600schemo.html


  7. TIA outputs are open-collector, so you need to put pullup resistors in order to make them work.

    attachicon.giftia_pullups.jpg

    READY (pin 3) is an output used to halt the 6502 until the end of a scanline when the TIA WSYNC register is strobed. Since you're not using the graphics, you probably don't need it in this application.

     

    CSYNC (pin 2) is an output! It's the Composite SYNC for the video signal.

     

    There are 4 CHIP SELECT inputs on the TIA: 3 active-low (pin 21, 22 and 24) and 1 active-high (pin 23). These must be set correctly before accessing the TIA.

    attachicon.giftia_ntsc.png

    EDIT: the picture I was using as reference had 2 of the CS pin active state swapped. I fixed both the picture and the post

     

    Phi0 (pin 4) is an output and it's the clock divided by 3, used as the main clock for the 6502 inside the 2600 console.

     

    Phi2 (pin 26) is an input and it's the phase-2 clock (generated by the 6502 in the 2600). This is used by the TIA to know when valid data can be read/output on the bus, so I'm pretty sure you'll need it to make it work.

     

    Take a look at the timing charts in the Stella Programmer's Guide and in the 650x processor datasheet.

     

    I'd suggest to open a thread in the "hardware" section here on AA, where it's more likely that the electronics experts will see it.

     

    Thanks for the info. I got confused in the Stella docs where it says "when the 02 clock goes high to low" in the Data Addressing section, I thought meant Pin 2. :P

     

    I've fixed it in my code now to set RW to 1, write my address/data, then set RW to 0. I've added some Pullup resistors to AUD1/AUD2.

     

    Still getting nothing out of the device though (I should add that my speakers also have an internal amp on them, and work very well with my SN76489ANs).

     

    I took a look at the timings in the docs. I'm not sure what to set the 4 CS lines to if I *just* want to use the TIA standalone without the 6507/2 (since I'm using the Arduino to control the TIA). Right now they're floating until I know. Should 21/22/24 be high and 23 be low?

     

    If I'm applying 5V/GND, and an Oscillated 5V to OSC, shouldn't Phi0 be showing some voltage?

    My voltmeter shows 0V on 2 different TIA chips (one is out of a working 2600 Jr, and the other was delivered just this week from eBay).

     

    If I'm bypassing the 6507/2, should I be able to write to Phi2 directly? e.g. Set RW to 1 and Phi2 to 0, write address/data, set RW to 0 then Phi2 to 1, as per pages 47 & 48 in the Stella programming guide.


  8. I need some noob help, ripping my hair out.

    I'm trying to program the TIA's sound from an Arduino and don't seem to be getting anything from AUD1 or AUD2. Also my READY bit is always 0.

     

    On my Arduino I set pins 2-7 to TIA pins D0-D5, and pins A0-A5 to TIA pins A0-A5 respectively (I am writing with digitalWrite on those analog pins from the Arduino, and getting 5V as expected on the right address pins from my Voltmeter).

    I have a 3.5Mhz Crystal Oscillator hooked up to OSC on the TIA, 5V/GND to VCC/VSS.

    I set R/W to 0, set CSYNC to 1, write my address/data and set CSYNC to 0.

     

    So far no luck, am I missing something?

     

    (I'm not at all concerned with the TIA's graphics or inputs, just the sound, but should I be doing anything on other pins? Do I need to do anything with Phi-0 and Phi-2?)

     

    I've seen some Youtube vids with people circuit bending with the TIA, but haven't seen any specific How To's on the topic, just what I've read from the Stella Programming Guide.

     

    This is my Arduino Sketch just for reference. I used delays rather than waiting on Ready (I know, bad bad bad), but I put in fairly long delays just to test things out, long enough to give lots of cycles.

    const unsigned char Sound[2] = {0x15,0x16}; // 4-bit D3-D0: 0 = voice 1, 1111 = voice 16
    const unsigned char Freq[2] = {0x17,0x18}; // 5-bit D4-D0: 0 = no division, 11111 = divide by 32
    const unsigned char Vol[2] = {0x19,0x1A}; // 4-bit D3-D0: 0 = no output, 1111 = highest
    
    // Set RW to Low
    // Set CS high then low to strobe
    
    const int Ready = 10;
    const int ClockSync = 11;
    const int ReadWrite = 12;
    
    void setup() {
      Serial.begin(9600);
      delay(500);
      Serial.println("Initializing...");
      // put your setup code here, to run once:
    
      // data bus pins
      pinMode(2,OUTPUT);
      pinMode(3,OUTPUT);
      pinMode(4,OUTPUT);
      pinMode(5,OUTPUT);
      pinMode(6,OUTPUT);
      pinMode(7,OUTPUT);
    
      // address pins (set digital)
      pinMode(A0,OUTPUT);
      pinMode(A1,OUTPUT);
      pinMode(A2,OUTPUT);
      pinMode(A3,OUTPUT);
      pinMode(A4,OUTPUT);
      pinMode(A5,OUTPUT);
    
      pinMode(Ready, INPUT);
      pinMode(ReadWrite, OUTPUT);
      pinMode(ClockSync, OUTPUT);
    
      initAtari();
    
      Serial.println("Write to Channel 0...");
      AtariWriteTone(0,15,14,2);
      Serial.println("Write to Channel 1...");
      AtariWriteTone(1,15,14,2);
    }
    
    void initAtari() {
      digitalWrite(ReadWrite, 0); 
      digitalWrite(ClockSync, 1); 
      delay(100);
    }
    
    void AtariWriteTone(int chan, unsigned char volume, unsigned char freq, unsigned char sound) {
      digitalWrite(ClockSync, 1); 
      delay(200);
      writeAddressByte(Sound[chan]);
      writeByteToDataBus(sound);
      digitalWrite(ClockSync, 0); 
      delay(200);
    
      digitalWrite(ClockSync, 1); 
      delay(200);
      writeAddressByte(Freq[chan]);
      writeByteToDataBus(freq);
      digitalWrite(ClockSync, 0); 
      delay(200);
    
      digitalWrite(ClockSync, 1); 
      delay(200);
      writeAddressByte(Vol[chan]);
      writeByteToDataBus(volume);
      digitalWrite(ClockSync, 0); 
      delay(200);
    }
    
    void writeAddressByte(unsigned char data) {
      int b0 = data & 1;
      int b1 = (data >> 1) & 1;
      int b2 = (data >> 2) & 1;
      int b3 = (data >> 3) & 1;
      int b4 = (data >> 4) & 1;
      int b5 = (data >> 5) & 1;
    
      digitalWrite(A0,b0);
      digitalWrite(A1,b1);
      digitalWrite(A2,b2);
      digitalWrite(A3,b3);
      digitalWrite(A4,b4);
      digitalWrite(A5,b5);
    }
    
    void writeByteToDataBus(unsigned char data) {
      int b0 = data & 1;
      int b1 = (data >> 1) & 1;
      int b2 = (data >> 2) & 1;
      int b3 = (data >> 3) & 1;
      int b4 = (data >> 4) & 1;
      int b5 = (data >> 5) & 1;
    
      digitalWrite(2,b0);
      digitalWrite(3,b1);
      digitalWrite(4,b2);
      digitalWrite(5,b3);
      digitalWrite(6,b4);
      digitalWrite(7,b5);
    
    }
    
    
    
    void loop() {
      // put your main code here, to run repeatedly:
      int rdy = digitalRead(Ready);
      Serial.println("Ready: " + String(rdy));
      delay(1000);
    }
    
×
×
  • Create New...