"Bit-bang" SPI IN & OUT (VS1033d)

Hello everyone. I am currently writing a program that reads data in chunks from an SD Card that then puts that data into a temporary buffer and then sends the buffer data to an MP3 decoder IC (VS1033d.) I have written the portion of the program that reads from the SD Card and outputs the data. However, I am not getting the results that I expect and at best only get a pattern of clicking from my speaker when data is actually being sent.

At this point I have rewired my circuit to make it easier to work with and really I just want to verify that I can even read and write data from the registers on the IC, namely via the SCI bus. I would like to give it a value for volume and then verify the write by reading that register from the IC and getting a return value equal to what I wrote it to.

The next post is what I have for code. I would like to modify SCI_LISTEN() to allow me to read what the VS1033d is sending back out for a result.

/*
VS1033 MP3 Player
Programmer/Researcher:  Nickolas Andersen
Researcher/Programmer:  Andrew Gray

NOT WORKING.  

Notes:
Ensure that pin 10 (default CS) is OUTPUT even if you are using a different pin for CS.
See if the card is present and can be initialized.
Open the file.  Only one file can be open at a time.

       
The circuit:
 * Yellow Wire:  VS1033D MP3 SCI Interface attached as follow:
 ** MP3FROM    - pin d3
 ** MP3TO    - pin d4
 ** MP3CLK  - pin d5
 ** SCI_xCS   - pin d6
 
 * Green Wire:  VS1033D MP3 SDI Interface attached as follows:
 ** MP3CLK  - pin d8
 ** MP3TO - pin d9
 ** MP3CLK  - pin d10
 ** SDI_DREQ  - pin d2
 
 * Blue Wire:  SD card attached to SPI bus as follows:
 ** SD_MOSI - pin d11
 ** SD_MISO - pin d12
 ** SD_CLK  - pin d13
 ** SD_CS   - pin d4 D10
  
 */

#include <SD.h>
int buffersize = 127 ; 
byte DataBuffer[128] = {} ;          // Create a 33 byte buffer. (33 indexes.)
unsigned int DataBufferPOS = 0 ;    // Initialize the buffer position variable.

long filesize = 0 ;                 // Initialize the file size variable
long CurrentFilePosition = 0 ;      // Initialize the file position variable

// * Yellow Wire:  VS1033D MP3 SCI Interface 
// * Green Wire:  VS1033D MP3 SDI Interface
const int SCI_xCS  = 7;  // Chip Select for SCI
const int SDI_xDCS = 6;  // Chip Select for SDI
const int MP3TO    = 5;  // MOSI shared between SCI and SDI
const int MP3CLK   = 4;  // CLOCK shared between SCI and SDI
const int SDI_DREQ = 3;  // SDI Data Request pin
const int MP3FROM  = 2;  // MISO shared between SCI and SDI
 
// * Blue Wire:  SD card attached to SPI bus
const int SD_CS   = 10 ;
const int SD_MOSI = 11 ;
const int SD_MISO = 12 ;
const int SD_CLK  = 13 ;

// * Purple Wire:  LCD and User Interface controls (Normally ADC pins)
const int LCDTX       = 0 ;
const int LCDPWR      = 1 ;
const int POTBASS     = 2 ;
const int POTTREBLE   = 3 ;
const int POTVOLUME   = 4 ;
const int MULTISWITCH = 5 ;

byte SCI_WRITE = B00000010 ;
byte SCI_READ  = B00000011 ; 

byte MODE        = 0x0 ; // MODE Mode control
byte STATUS      = 0x1 ; // STATUS Status of VS1033
byte BASS        = 0x2 ; // BASS Built-in bass/treble control
byte CLOCKF      = 0x3 ; // Clock freq + multiplier
byte DECODE_TIME = 0x4 ; // TIME Decode time in seconds
byte AUDATA      = 0x5 ; // Misc. audio data
byte WRAM        = 0x6 ; // WRAM RAM write/read
byte WRAMADDR    = 0x7 ; // WRAMADDR Base address for RAM write/read
byte HDAT0       = 0x8 ; // HDAT0 Stream header data 0
byte HDAT1       = 0x9 ; // HDAT1 Stream header data 1
byte AIADDR      = 0xA ; // CLKI2AIADDR Start address of application
byte VOL         = 0xB ; // CLKI VOL Volume control
byte AICTRL0     = 0xC ; // CLKI2AICTRL0 Application control register 0
byte AICTRL1     = 0xD ; // CLKI2AICTRL1 Application control register 1
byte AICTRL2     = 0xE ; // CLKI2AICTRL2 Application control register 2
byte AICTRL3     = 0xF ; // CLKI2AICTRL3 Application control register 3 

byte SM_DIFF          = 0 ; //SCIregister << SM_DIFF
byte SM_LAYER12       = 1 ; //SCIregister <<
byte SM_RESET         = 2 ; //SCIregister <<
byte SM_OUTOFWAV      = 3 ; //SCIregister <<
byte SM_EARSPEAKER_LO = 4 ; //SCIregister <<
byte SM_TESTS         = 5 ; //SCIregister <<
byte SM_STREAM        = 6 ; //SCIregister <<
byte SM_EARSPEAKER_HI = 7 ; //SCIregister <<
byte SM_DACT          = 8 ; //SCIregister <<
byte SM_SDIORD        = 9 ; //SCIregister <<
byte SM_SDISHARE      = 10 ; //SCIregister <<
byte SM_SDINEW        = 11 ; //SCIregister <<
byte SM_ADPCM         = 12 ; //SCIregister <<
byte SM_ADPCM_HP      = 13 ; //SCIregister <<
byte SM_LINE          = 14 ; //SCIregister <<
byte SM_CLK           = 15 ; //SCIregister <<

byte defaultMSBbyte = B01010100 ;
byte defaultLSBbyte = B00010000 ;

byte ReceivedMSB ;
byte ReceivedLSB ;

// Setup Normal Serial byte variables
char SerialValue;           // Variable to hold the current read of the Serial.Read() buffer.

void setup()
{
  Serial.begin(38400);
  Serial.println("1/8**********************************************") ;
  Serial.println("2/8**********************************************") ;
  Serial.println("3/8**********************************************") ;
  Serial.println("4/8**********************************************") ;
  Serial.println("5/8**********************************************") ;
  Serial.println("6/8**********************************************") ;
  Serial.println("7/8**********************************************") ;
  Serial.println("8/8**********************************************") ;
  INITPINMODES();
  INITSDCARD();  
  while (digitalRead(SDI_DREQ)!=LOW){Serial.println("SDI_DREQ is still LOW");}  Serial.println("SDI_DREQ is now HIGH");  // Wait until SDI_DREQ is HIGH.
  MP3SCI_COMMAND(SCI_WRITE, MODE, defaultMSBbyte, defaultLSBbyte);
  while(digitalRead(SDI_DREQ) != HIGH){;} MP3VOL(0x90, 0x90);
}

void INITPINMODES()
{
  // * Yellow Wire:  VS1033D MP3 SCI Interface 
  // * Green Wire:  VS1033D MP3 SDI Interface
  pinMode(SCI_xCS, OUTPUT);  digitalWrite(SCI_xCS, HIGH);
  pinMode(SCI_xCS, OUTPUT);  digitalWrite(SDI_xDCS, HIGH);
  pinMode(MP3TO, OUTPUT);
  pinMode(MP3CLK, OUTPUT); digitalWrite(MP3CLK, HIGH);  
  pinMode(SDI_DREQ, INPUT);
  pinMode(MP3FROM, INPUT) ;
   
  // * Blue Wire:  SD card attached to SPI bus
  pinMode(SD_MOSI, OUTPUT);
  pinMode(SD_MISO, INPUT);
  pinMode(SD_CLK, OUTPUT);
  pinMode(SD_CS, OUTPUT);
  
  // * Purple Wire:  LCD and User Interface controls
  pinMode(LCDTX, OUTPUT);
  pinMode(LCDPWR, OUTPUT);
  pinMode(POTBASS, INPUT);
  pinMode(POTTREBLE, INPUT);
  pinMode(POTVOLUME, INPUT);
  pinMode(MULTISWITCH, INPUT);
}

void INITSDCARD()
{
  Serial.print("Initializing SD card...");
  while (!SD.begin(SD_CS)) {Serial.println("SD Card failure... Retrying...");}
  Serial.println("SD Card initialized... Countinuing...");
  delay(1000);
}

void Check4SerialCOMMANDS()
{;
SerialValue = Serial.read() ;   // Do a serial data read.

if (  (SerialValue==('0') or (SerialValue==(char(0)))))    {  ;  }  // Do nothing.     

// Single Directions
if (  (SerialValue==('v') or (SerialValue==(char('v'))))) {  DisplayVolume()    ; return; }  
if (  (SerialValue==('1') or (SerialValue==(char(1)))))   {  MP3VOL(0x33, 0x33) ; return; }  
if (  (SerialValue==('2') or (SerialValue==(char(2)))))   {  MP3VOL(0xDD, 0xDD)  ; return; }  
}

... more to come

void MP3VOL(byte left, byte right)
{ 
  digitalWrite(SCI_xCS,LOW);
  SENDTOSCI(SCI_WRITE);  // WRITE INSTRUCTION
  SENDTOSCI(VOL);        // VOLUME ADDRESS
  SENDTOSCI(left);       // LEFT VOLUME
  SENDTOSCI(right);      // RIGHT VOLUME
  digitalWrite(SCI_xCS,HIGH);
}


void MP3SCI_COMMAND(byte instruction, byte whatregister, byte MSBbyte, byte LSBbyte)
{ 
  // Supports both WRITE and READ commands based on which one is passed to this function. 
  digitalWrite(SCI_xCS,LOW);
  SENDTOSCI(instruction);  
  SENDTOSCI(whatregister);     

  if (instruction == SCI_WRITE) 
    { 
      SENDTOSCI(MSBbyte);  
      SENDTOSCI(LSBbyte);  
    }
  if (instruction == SCI_READ) 
    { 
      ReceivedMSB = LISTENTOSCI();  
      ReceivedLSB = LISTENTOSCI();  
    }
  digitalWrite(SCI_xCS,HIGH);
}

void DisplayVolume()
{
MP3SCI_COMMAND(SCI_READ, VOL, 0, 0);
}

void loop()
{
  // ButtonsOnUserInterface();
  Check4SerialCOMMANDS() ;
  delay(10);
  SD_READBYTES();                                                  // Reads from the SD Card and places what is read into a temporary buffer array.
  while(digitalRead(SDI_DREQ) != HIGH){ Check4SerialCOMMANDS(); }  // Wait until SDI_DREQ is HIGH.
  MP3_SENDDATA();                                                  // Send data from the temporary buffer array into the MP3 player.
}

void MP3_SENDDATA()
{
  int index = 0 ;                                   // Reset the DataBuffer index placeholder to 0.
  digitalWrite(SDI_xDCS, LOW);                      // Activate (Chip Select is active low)
  for  (index = 0 ; index <= buffersize ; index++)  // Set up a for loop to read the data from DataBuffer.
    { SENDTOSDI(DataBuffer[index]); }               // Send the data from the buffer to the mp3
  digitalWrite(SDI_xDCS, HIGH);                     // Deactivate (Chip Select is active low)
}

void SENDTOSDI(byte ThisBYTE)  // SERIAL DATA INTERFACE
{
  for(int ThisBIT = 1; ThisBIT <= 8; ThisBIT++)              // Now, "bit-bang" out the data and clock it out
    { 
      if   (ThisBYTE > 127) { digitalWrite (MP3TO, HIGH) ; } // If the MSB is a 1 then set MOSI high
      else                  { digitalWrite (MP3TO, LOW) ; }  // If the MSB is a 0 then set MOSI low
      digitalWrite (MP3CLK,HIGH) ;                           // Pulse the clock pin high
      ThisBYTE = ThisBYTE << 1 ;                             // Bit-shift the working byte
      digitalWrite(MP3CLK,LOW) ;                             // Pulse the clock pin low
    }
}

void SENDTOSCI(byte ThisBYTE)  // SERIAL CONTROL INTERFACE
{
  for(int ThisBIT = 1; ThisBIT <= 8; ThisBIT++)              // Now, "bit-bang" out the data and clock it out
    { 
      if   (ThisBYTE > 127) { digitalWrite (MP3TO, HIGH) ; } // If the MSB is a 1 then set MOSI high
      else                  { digitalWrite (MP3TO, LOW) ; }  // If the MSB is a 0 then set MOSI low
      digitalWrite (MP3CLK,HIGH) ;                           // Pulse the clock pin high
      ThisBYTE = ThisBYTE << 1 ;                             // Bit-shift the working byte
      digitalWrite(MP3CLK,LOW) ;                             // Pulse the clock pin low
    }
}

byte LISTENTOSCI()  // LISTEN TO SERIAL DATA INTERFACE RESPONSE BYTES
{
  byte tempin = B00000000;
  byte results = B00000000;
  for(int ThisBIT = 1; ThisBIT <= 8; ThisBIT++)          // 
    { 
      digitalWrite (MP3CLK,HIGH) ; delay(2);             // Pulse the clock pin high
      digitalWrite(MP3CLK,LOW) ;  delay(2);              // Pulse the clock pin low
      tempin = digitalRead(MP3FROM) ;
      if   (tempin == HIGH) { results = results << 1 ; } // 
      else                  { results = results << 0 ; } //
    }
  return results ;
}


void OUTPUTDATABUFFER()
{
for (int pos = 0 ; pos <= buffersize; pos++)
  {Serial.println(DataBuffer[pos]);}
}

void SD_READBYTES()
{
delay(10);
File datafile = SD.open("1.wav") ;  // Open a file from the SD Card
if (datafile)                       // If the file was successfully opened (It would have returned a TRUE.)
  { 
    filesize = datafile.size();     // Find out how big the file is
    Serial.print("* SD READ:  ") ; 
    Serial.print(CurrentFilePosition); Serial.print("-"); Serial.print(CurrentFilePosition+buffersize); 
    Serial.print(" of ");  Serial.print(filesize); Serial.print(" ");

    // Read  bytes.  Data Buffer position values are reset each time THIS function runs.
    for (DataBufferPOS = 0 ; DataBufferPOS <= buffersize; DataBufferPOS++)  
      {
        if (CurrentFilePosition >= filesize) {CurrentFilePosition=0; break;}
        datafile.seek(CurrentFilePosition);            // Seek to a position in the file.
        DataBuffer[DataBufferPOS] = datafile.peek() ;  // Read the current file position's data into the DATABUFFER
        Serial.write(datafile.peek() );                // Read the current file position's data to SERIAL
        CurrentFilePosition++ ;
        if (CurrentFilePosition == filesize) {CurrentFilePosition = 0;}
      }
                                           // These 32 bytes have been read.
   datafile.close() ;                      // Close the open file. 
   Serial.print(" ");
   Serial.println("* SD READ:  End of read.") ; 
   return ;                                // Exit this function
  }
else                                       // If the file was NOT successfully opened.
  {                                        // Report to the operator the ERROR condition
    Serial.println("ERROR:  File could not be opened!!  Reinitializing...");
    INITSDCARD()  ;
  }
}

THANKS EVERYONE SO MUCH FOR LOOKING AT THIS... These were my first posts. :slight_smile:

Something went bang?

When posting code, please use the # icon on the editor's toolbar.
I think I've sprained my scrolling finger.

Thanks, AWOL, I've implemented that fix. So, sometimes I throw in the proverbial kitchen sink when I ask questions. Let me clarify. I would like to accomplish SPI both in AND out bound but not via the hardware SPI built into the Arduino. This is because I'm dedicating that to the SD Card reader. Also, I am having trouble with the VS1033d MP3 decoder IC that I bought from Sparkfun. I've updated the code above a bit.

Actually, there was no "bang" but I may have been accidentally supplying the VC1033d with the wrong voltage (5 instead of 2.7.) The circuit was rewired recently for neatness and I used the main ground instead of the "ground" from the LM317 adjustable regulator that I am using. Hopefully everything lives. (I did purchase an extra VS1033d just incase though! ;))

So why did you say there was a big bang if there was no bang at all?
I'm confused.

Wow, seems I mis-titled this thread. I meant to say "Bit-Bang".

I would like to see some good example code of manually performing SPI reads and writes without using the built in hardware/library. The VS1033d uses SPI Mode 0 and I would like to replicate that version in code.