Reading and playing sound data from external EEPROM (M27C801)

I'm working on restoring an old arcade board that had a broken main MCU. Instead, I soldered the Mega 2560 on a breadboard and wrote code to control all the functions on the board.
All that was left was the sound.
The original MCU (H8S/2390) reads data from the EPROM and transmits it to the audio power amplifier.
I'm trying to do the same.

To read EPROM I use this code (and it works fine):
https://forum.arduino.cc/t/how-to-extract-read-the-code-stored-in-am27c256-120dc-eprom-using-arduino/621926/19

unsigned int
    Address;

//PORTF
//can use PINF to read data bus
const byte pinD0 = A0;
const byte pinD1 = A1;
const byte pinD2 = A2;
const byte pinD3 = A3;
const byte pinD4 = A4;
const byte pinD5 = A5;
const byte pinD6 = A6;
const byte pinD7 = A7;

const byte pinA0 = 2;
const byte pinA1 = 3;
const byte pinA2 = 4;
const byte pinA3 = 5;
const byte pinA4 = 6;
const byte pinA5 = 7;
const byte pinA6 = 8;
const byte pinA7 = 9;
const byte pinA8 = 10;
const byte pinA9 = 11;
const byte pinA10 = 12;
const byte pinA11 = 13;
const byte pinA12 = 21;
const byte pinA13 = 20;
const byte pinA14 = 19;

const byte pinG = 18;

const byte grData[] = 
{
    pinD0, pinD1, pinD2, pinD3,
    pinD4, pinD5, pinD6, pinD7
        
};

const byte grAddr[] = 
{
    pinA0, pinA1, pinA2, pinA3,
    pinA4, pinA5, pinA6, pinA7,
    pinA8, pinA9, pinA10, pinA11,
    pinA12, pinA13, pinA14
    
};

char szStr[16];

void setup( void )
{
    unsigned char
        idx,
        databyte;
        
    Serial.begin(115200);

    pinMode( pinG, OUTPUT );
    digitalWrite( pinG, HIGH );
    for( int i=0; i<8; i++ )
        pinMode( grData[i], INPUT_PULLUP );
        
    for( int i=0; i<15; i++ )
        pinMode( grAddr[i], OUTPUT );
        
    //0bx111 1111 1111 1111
    Address = 0x0000;
    idx = 0;
    do
    {
        SetAddress( Address );
        digitalWrite( pinG, LOW );
        databyte = PINF;
        digitalWrite( pinG, HIGH );

        sprintf( szStr, "%02X ", databyte );
        Serial.print( szStr );
        idx++;
        if( idx == 16 )
        {
            idx = 0;
            Serial.println("");
            
        }//if
        
        Address++;
        
    }while( Address < 0x8000 );
    
}//setup

void loop( void )
{
        
}//loop

void SetAddress( unsigned int Adr )
{
    for( int i=0; i<15; i++ )
        digitalWrite( grAddr[i], (Adr & (1<<i)) ? HIGH:LOW );
    
}//SetAddress

In order to play back the read bytes I'm trying to add this code:
https://github.com/idanre1/audioStreamArduino/blob/master/arduinoMaster/audioSerial.ino

#include <stdint.h>
#include <avr/interrupt.h>
#include <avr/io.h>
#include <avr/pgmspace.h>

#define SAMPLE_RATE 8000
#define BUFFER_SIZE 128
#define TRANSFER_SIZE 64
//#define SERIAL_BUFFER_SIZE 512 // ToDo patch in HardwareSerial.cpp inside /usr/share/arduino/hardware/arduino/cores/arduino/

void startPlayback();
void stopPlayback();
long powlong(long x, long y);
void reset();

unsigned long sounddata_length=0;
unsigned char sounddata_data[BUFFER_SIZE];
int BufferHead=0;
int HalfBufferSize=BUFFER_SIZE/2;
int BufferTail=0;
unsigned long sample=0;
unsigned long BytesReceived=0;

unsigned long Temp=0;
unsigned long NewTemp=0;

int ledPin = 13;
int speakerPin = 11;
int Playing = 0;

//Interrupt Service Routine (ISR)
// This is called at 8000 Hz to load the next sample.
ISR(TIMER1_COMPA_vect) 
{
    //If not at the end of audio
    if (sample < sounddata_length)   
    {
        //Set the PWM Freq.
        OCR2A = sounddata_data[BufferTail];
        //If circular buffer is not empty
        if (BufferTail != BufferHead)  
        {
        //Increment Buffer's tail index.
		if (++BufferTail >= BUFFER_SIZE) BufferTail = 0; //BufferTail = ((BufferTail+1) % BUFFER_SIZE);
        //Increment sample number.
        sample++;
        }//End if
    }//End if
    else //We are at the end of audio
    {
        //Stop playing.
        stopPlayback();
    }//End Else

}//End Interrupt

void startPlayback()
{
    //Set pin for OUTPUT mode.
    pinMode(speakerPin, OUTPUT);

    //---------------TIMER 2-------------------------------------
    // Set up Timer 2 to do pulse width modulation on the speaker
    // pin.  
    //This plays the music at the frequency of the audio sample.

    // Use internal clock (datasheet p.160)
    //ASSR = Asynchronous Status Register
    ASSR &= ~(_BV(EXCLK) | _BV(AS2));

    // Set fast PWM mode  (p.157)
    //Timer/Counter Control Register A/B for Timer 2
    TCCR2A |= _BV(WGM21) | _BV(WGM20);
    TCCR2B &= ~_BV(WGM22);

		// Do non-inverting PWM on pin OC2A (p.155)
    // On the Arduino this is pin 11.
    TCCR2A = (TCCR2A | _BV(COM2A1)) & ~_BV(COM2A0);
    TCCR2A &= ~(_BV(COM2B1) | _BV(COM2B0));

    // No prescaler (p.158)
    TCCR2B = (TCCR2B & ~(_BV(CS12) | _BV(CS11))) | _BV(CS10);

    //16000000 cycles       1 increment    2000000 increments
    //--------        *  ----            = -------
    //       1 second       8 cycles             1 second

    //Continued...
    //2000000 increments     1 overflow      7812 overflows
    //-------            * ---            = -----
    //      1 second       256 increments       1 second

    // Set PWM Freq to the sample at the end of the buffer.
    OCR2A = sounddata_data[BufferTail];

    //--------TIMER 1----------------------------------
    // Set up Timer 1 to send a sample every interrupt.
    // This will interrupt at the sample rate (8000 hz)
    //

    cli();

    // Set CTC mode (Clear Timer on Compare Match) (p.133)
    // Have to set OCR1A *after*, otherwise it gets reset to 0!
    TCCR1B = (TCCR1B & ~_BV(WGM13)) | _BV(WGM12);
    TCCR1A = TCCR1A & ~(_BV(WGM11) | _BV(WGM10));

    // No prescaler (p.134)
    TCCR1B = (TCCR1B & ~(_BV(CS12) | _BV(CS11))) | _BV(CS10);

    // Set the compare register (OCR1A).
    // OCR1A is a 16-bit register, so we have to do this with
    // interrupts disabled to be safe.
    OCR1A = F_CPU / SAMPLE_RATE;    // 16e6 / 8000 = 2000

    //Timer/Counter Interrupt Mask Register
    // Enable interrupt when TCNT1 == OCR1A (p.136)
    TIMSK1 |= _BV(OCIE1A);

    //Init Sample.  Start from the beginning of audio.
    sample = 0;
    
    //Enable Interrupts
    sei();  
}//End StartPlayback

void stopPlayback()
{
    // Disable playback per-sample interrupt.
    TIMSK1 &= ~_BV(OCIE1A);

    // Disable the per-sample timer completely.
    TCCR1B &= ~_BV(CS10);

    // Disable the PWM timer.
    TCCR2B &= ~_BV(CS10);

    digitalWrite(speakerPin, LOW);
}//End StopPlayback

    //Use the custom powlong() function because the standard
    //pow() function uses floats and has rounding errors.
    //This powlong() function does only integer powers.
    //Be careful not to use powers that are too large, otherwise
    //this function could take a really long time.
long powlong(long x, long y)
{
  //Base case for recursion
  if (y==0)
  {
    return(1);
  }//End if
  else
  {
    //Do recursive call.
    return(powlong(x,y-1)*x);
  }//End Else
}

void setup()
{
    //Set LED for OUTPUT mode
    pinMode(ledPin, OUTPUT);
    
    //Start Serial port.  If your application can handle a
    //faster baud rate, that would increase your bandwidth
    //115200 only allows for 14,400 Bytes/sec.  Audio will
    //require 8000 bytes / sec to play at the correct speed.
    //This only leaves 44% of the time free for processing 
    //bytes.
    Serial.begin(115200);
    Serial.println("GO");

    //PC sends audio length as 10-digit ASCII
    //While audio length hasn't arrived yet
    while (Serial.available()<10)
    {
    //Blink the LED on pin 13.
    digitalWrite(ledPin,!digitalRead(ledPin));
    delay(100);
    }
    digitalWrite(ledPin,1);
    
    //Init number of audio samples.
    sounddata_length=0;
    
    //Convert 10 ASCII digits to an unsigned long.
    for (int i=0;i<10;i++)
    {
    //Convert from ASCII to int
    Temp=Serial.read()-48; 
    
    //Shift the digit the correct location.
    NewTemp = Temp * powlong(10,9-i);  
    //Add the current digit to the total.
    sounddata_length = sounddata_length + NewTemp;
    }//End for

    //Tell the remote PC/device that the Arduino is ready
    //to begin receiving samples.
    Serial.println(sounddata_length);
    Serial.println(uint8_t(TRANSFER_SIZE));
       
    //There's data now, so start playing.
    //startPlayback();
    Playing =0;
}//End Setup

void loop()
{
  //If audio not started yet...
  if (Playing == 0)
  {
  //Check to see if the first 1000 bytes are buffered.
  if (BufferHead >= HalfBufferSize)
  {
    Playing=1;
    startPlayback();
  }//End if
  }//End if
  
  //While the serial port buffer has data
  while (Serial.available()>0) 
  {
    //If the sample buffer isn't full    
    if (((BufferHead+1) % BUFFER_SIZE) != BufferTail)
    {
    //Store the sample freq.
    sounddata_data[BufferHead] = Serial.read();
    //Increment the buffer's head index.
    BufferHead = (BufferHead+1) % BUFFER_SIZE;
    //Increment the bytes received
    BytesReceived++;
    }//End if
    
    //if the Serial port buffer has room
    if ((BytesReceived % TRANSFER_SIZE) == 0) {
      //Tell the remote PC how much bytes you want.
	  if ((sounddata_length - BytesReceived) < TRANSFER_SIZE) { 
		  Serial.println(uint8_t(sounddata_length - BytesReceived));
	  }
	  else {
		  Serial.println(uint8_t(TRANSFER_SIZE));
	  }
      // Serial.print("!");
      // Serial.println(sounddata_data[BufferHead]);
	  //Serial.println("@");
    }//End if
  }//End While
}//End Loop

I increased the BUFFER_SIZE a lot and Iinstead of Serial_data I give it the bytes read:


void loop() {
    Address = 0x7000;
    idx = 0;

    do {  
      SetAddress( Address );
      digitalWrite( pinG, LOW );
      databyte = PINK;
      digitalWrite( pinG, HIGH );

       if (((BufferHead+1) % BUFFER_SIZE) != BufferTail) {
          sounddata_data[BufferHead] = databyte;        
          BufferHead = BufferHead+1 % BUFFER_SIZE;
       }
                       
       Address++;

        if (Playing == 0) {
          if (BufferHead >= HalfBufferSize) {
              Playing=1;
              startPlayback();
          }
        }        
    }while( Address < 0xaaff );    
}

The buffer is filled and sound playback begins, but only the part limited by this buffer (2-3 seconds) and this part loops and repeats until the end of searching through all the given addresses. It appears that the buffer is not being flushed.

I understand that "startPlayback()" should be outside the loop, but it doesn’t work differently or works with distortion.
It’s also not clear what to do with the "sounddata_length".
Help me figure out how to combine these two sketches.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.