This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

SSI1 Rx problem with EK-TM4C123GXL

Other Parts Discussed in Thread: EK-TM4C123GXL

Hi to everyone,

I would like to run a MP3 encoder IC (VS1003)  with a Tiva Launchpad (EK-TM4C123GXL). I've attached the IC to SSI1 peripheral and have started to write drive. For some reason I can't get the uC to receive data from the VS1003.

So what have I done so far:

I've written an init function (uint8_t VS10xxInit(void)) which is supposed to init the hardware (Line 848 to 901) first. After that I write a test value to one of the available register inside the VS1003. After that I try to read out this register to check that the write/read procedure works (Line 926,927). I can see on the oscilloscope that the data gets send to the VS1003. I can also see as soon as the software gets to the point to write a dummy byte to trigger VS1003 to send data that it puts the just written register value out on the Rx line. For some reason the SSIDataGet (Line 318, 319) function doesn't not receive it and always writes "0" to the variable passed into it.

I hope anyone can help me on this.

Thank you very much!

/*

  VLSI Solution generic microcontroller example player / recorder for
  VS1003.

  v1.00 2012-11-28 HH  First release

*/


#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#include <stdint.h>
#include <stdbool.h>

#include "inc/hw_memmap.h"
#include "inc/hw_types.h"
#include "inc/hw_gpio.h"
#include "driverlib/gpio.h"
#include "driverlib/ssi.h"
#include "driverlib/sysctl.h"
#include "driverlib/rom.h"
#include "driverlib/pin_map.h"
#include "grlib/grlib.h"
#include "utils/uartstdio.h"
#include "VS10xx.h"


//*****************************************************************************
//
//! \addtogroup dac_api
//! @{
//
//*****************************************************************************

#define FILE_BUFFER_SIZE                    512
#define SDI_MAX_TRANSFER_SIZE               32
#define SDI_END_FILL_BYTES                  2050
#define REC_BUFFER_SIZE                     512


/***************************************************
 * Peripheral definitions for VS1003 SPI interface
 * *************************************************/

// SSI port
#define VS1003_SSI_BASE                     SSI1_BASE
#define VS1003_SSI_SYSCTL_PERIPH            SYSCTL_PERIPH_SSI1

// GPIO for SSI pins
#define VS1003_SSI_GPIO_PORT_BASE           GPIO_PORTF_BASE
#define VS1003_SSI_GPIO_SYSCTL_PERIPH       SYSCTL_PERIPH_GPIOF
#define VS1003_SSI_RX                       GPIO_PIN_0
#define VS1003_SSI_TX                       GPIO_PIN_1
#define VS1003_SSI_CLK                      GPIO_PIN_2
#define VS1003_SSI_PINS                     (VS1003_SSI_RX | VS1003_SSI_TX | VS1003_SSI_CLK)
//#define VS1003_SSI_PINS                     (VS1003_SSI_TX | VS1003_SSI_CLK)
//*****************************************************************************
//
// Defines the GPIO pin configuration macros for the pins that are used for
// the SSI function.
//
//*****************************************************************************
#define VS1003_PINCFG_SSICLK                GPIO_PF2_SSI1CLK
#define VS1003_PINCFG_SSIRX                 GPIO_PF0_SSI1RX
#define VS1003_PINCFG_SSITX                 GPIO_PF1_SSI1TX

// GPIO for xRST, BSYNC, DREQ pins
#define VS1003_CTL_GPIO_PORT_BASE           GPIO_PORTC_BASE
#define VS1003_CTL_GPIO_SYSCTL_PERIPH       SYSCTL_PERIPH_GPIOC
#define VS1003_xRST                         GPIO_PIN_4
#define VS1003_xDCS                         GPIO_PIN_5
#define VS1003_xCS                          GPIO_PIN_7
#define VS1003_DREQ                         GPIO_PIN_6
#define VS1003_CTL_PINS                     (VS1003_xRST | VS1003_xDCS | VS1003_xCS)

#define VS1003_SSI_CLOCK                    3000000 // Set SSI1 clock to 6MHz


/* How many transferred bytes between collecting data.
   A value between 1-8 KiB is typically a good value.
   If REPORT_ON_SCREEN is defined, a report is given on screen each time
   data is collected. */
#define REPORT_INTERVAL 4096
#define REPORT_INTERVAL_MIDI 512

#define min(a,b) (((a)<(b))?(a):(b))

enum AudioFormat {
  afUnknown,
  afRiff,
  afMp3,
  afMidi,
} audioFormat = afUnknown;

const char *afName[] = {
  "unknown",
  "RIFF",
  "MP3",
  "MIDI",
};

enum PlayerStates {
  psPlayback = 0,
  psUserRequestedCancel,
  psCancelSentToVS10xx,
  psStopped
} playerState;

uint8_t adpcmHeader[60] = {
  'R', 'I', 'F', 'F',
  0xFF, 0xFF, 0xFF, 0xFF,
  'W', 'A', 'V', 'E',
  'f', 'm', 't', ' ',
  0x14, 0, 0, 0,          /* 20 */
  0x11, 0,                /* IMA ADPCM */
  0x1, 0,                 /* chan */
  0x0, 0x0, 0x0, 0x0,     /* sampleRate */
  0x0, 0x0, 0x0, 0x0,     /* byteRate */
  0, 1,                   /* blockAlign */
  4, 0,                   /* bitsPerSample */
  2, 0,                   /* byteExtraData */
  0xf9, 0x1,              /* samplesPerBlock = 505 */
  'f', 'a', 'c', 't',     /* subChunk2Id */
  0x4, 0, 0, 0,           /* subChunk2Size */
  0xFF, 0xFF, 0xFF, 0xFF, /* numOfSamples */
  'd', 'a', 't', 'a',
  0xFF, 0xFF, 0xFF, 0xFF
};



//*****************************************************************************
//
//! Plays back an audio file.
//!
//! \param readFp is the offset to the register to write.
//!
//!  This function records an audio file in Ogg, MP3, or WAV formats.e
//!  If recording in WAV format, it updates the RIFF length headers
//!  after recording has finished.
//!
//! \return None.
//
//*****************************************************************************
void Set32(uint8_t *d, uint32_t n) {
  int i;
  for (i=0; i<4; i++) {
    *d++ = (uint8_t)n;
    n >>= 8;
  }
}


//*****************************************************************************
//
//! Plays back an audio file.
//!
//! \param readFp is the offset to the register to write.
//!
//!  This function records an audio file in Ogg, MP3, or WAV formats.e
//!  If recording in WAV format, it updates the RIFF length headers
//!  after recording has finished.
//!
//! \return None.
//
//*****************************************************************************
void Set16(uint8_t *d, uint16_t n) {
  int i;
  for (i=0; i<2; i++) {
    *d++ = (uint8_t)n;
    n >>= 8;
  }
}


//*****************************************************************************
//
//! Writes a register in the DS3231 RTC.
//!
//! \param ucRegister is the offset to the register to write.
//! \param ulData is the data to be written to the DAC register.
//!
//!  This function will write the register passed in ucAddr with the value
//!  passed in to ulData.  The data in ulData is actually 9 bits and the
//!  value in ucAddr is interpreted as 7 bits.
//!
//! \return True on success or false on error.
//
//*****************************************************************************
void VS10xxSciWrite(uint8_t addr, uint16_t data)
{
    //
    // Set xDCS pin to high state
    //
    GPIOPinWrite(VS1003_CTL_GPIO_PORT_BASE, VS1003_xDCS, VS1003_xDCS);

    //
    // Set xCS pin to low state
    //
    GPIOPinWrite(VS1003_CTL_GPIO_PORT_BASE, VS1003_xCS, 0);

    //
    // Wait for any previous SSI operation to finish.
    //
    while(SSIBusy(VS1003_SSI_BASE)){}

    //
    // Send write code
    //
    SSIDataPut(VS1003_SSI_BASE, WRITE_CODE);

    //
    // Wait for any previous SSI operation to finish.
    //
    while(SSIBusy(VS1003_SSI_BASE)){}

    //
    // Send register adress
    //
    SSIDataPut(VS1003_SSI_BASE, addr);

    //
    // Wait for any previous SSI operation to finish.
    //
    while(SSIBusy(VS1003_SSI_BASE)){}

    //
    // Send high byte to VS1003
    //
    SSIDataPut(VS1003_SSI_BASE, (uint8_t) (data >> 8));
    //SSIDataPut(VS1003_SSI_BASE, (uint8_t) data);

    //
    // Wait for any previous SSI operation to finish.
    //
    while(SSIBusy(VS1003_SSI_BASE)){}

    //
    // Send low byte to VS1003
    //
    SSIDataPut(VS1003_SSI_BASE, (uint8_t) data);
    //SSIDataPut(VS1003_SSI_BASE, (uint8_t) (data >> 8));

    //
    // Wait for any previous SSI operation to finish.
    //
    while(SSIBusy(VS1003_SSI_BASE)){}

    //
    // Set xCS pin to high state
    //
    GPIOPinWrite(VS1003_CTL_GPIO_PORT_BASE, VS1003_xCS, VS1003_xCS);

    //
    // Wait until DREQ becomes high state and execution has been compleated
    //
    while (!GPIOPinRead(VS1003_CTL_GPIO_PORT_BASE, VS1003_DREQ));

}


//*****************************************************************************
//
//! Writes a register in the DS3231 RTC.
//!
//! \param ucRegister is the offset to the register to write.
//! \param ulData is the data to be written to the DAC register.
//!
//!  This function will write the register passed in ucAddr with the value
//!  passed in to ulData.  The data in ulData is actually 9 bits and the
//!  value in ucAddr is interpreted as 7 bits.
//!
//! \return True on success or false on error.
//
//*****************************************************************************
uint16_t VS10xxSciRead(uint8_t addr)
{

    uint32_t ui8ByteHigh;
    uint32_t ui8ByteLow;

    //
    // Set xCS pin to low state
    //
    GPIOPinWrite(VS1003_CTL_GPIO_PORT_BASE, VS1003_xCS, 0);

    //
    // Wait for any previous SSI operation to finish.
    //
    while(SSIBusy(VS1003_SSI_BASE)){}

    //
    // Set VS1003 into read mode
    //
    SSIDataPut(VS1003_SSI_BASE, READ_CODE); // READ_CODE: 0x03 (00000011)

    //
    // Wait for any previous SSI operation to finish.
    //
    while(SSIBusy(VS1003_SSI_BASE)){}

    //
    // Send register address
    //
    SSIDataPut(VS1003_SSI_BASE, addr);

    //
    // Wait for any previous SSI operation to finish.
    //
    while(SSIBusy(VS1003_SSI_BASE)){}

    //
    // Read high byte
    //
    SSIDataPut(VS1003_SSI_BASE, 0);             // write dummy byte
    SSIDataGet(VS1003_SSI_BASE, &ui8ByteHigh);  // read data frm rx fifo
    //SSIDataGetNonBlocking(VS1003_SSI_BASE, &ui8ByteHigh);  // read data frm rx fifo

    //
    // Wait for any previous SSI operation to finish.
    //
    while(SSIBusy(VS1003_SSI_BASE)){}

    //
    // Read low byte
    //
    SSIDataPut(VS1003_SSI_BASE, 0);             // write dummy data
    SSIDataGet(VS1003_SSI_BASE, &ui8ByteLow);   // read data frm rx fifo

    //
    // Wait for any previous SSI operation to finish.
    //
    while(SSIBusy(VS1003_SSI_BASE)){}

    //
    // Set xCS pin to high state
    //
    GPIOPinWrite(VS1003_CTL_GPIO_PORT_BASE, VS1003_xCS, VS1003_xCS);


   return ( (uint16_t) ((ui8ByteHigh << 8) | ui8ByteLow) );

}


//*****************************************************************************
//
//! Writes a register in the DS3231 RTC.
//!
//! \param ucRegister is the offset to the register to write.
//! \param ulData is the data to be written to the DAC register.
//!
//!  This function will write the register passed in ucAddr with the value
//!  passed in to ulData.  The data in ulData is actually 9 bits and the
//!  value in ucAddr is interpreted as 7 bits.
//!
//! \return True on success or false on error.
//
//*****************************************************************************
int VS10xxSdiWrite(const uint8_t *data, uint8_t bytes)
{
    uint8_t ui8i;

    //
    // Check max. number of bytes to be transfered
    //
    if(bytes > 32)
    {
        return -1;  // Error: Too many bytes to transfer
    }

    //
    // Set xCS pin to high state
    //
    GPIOPinWrite(VS1003_CTL_GPIO_PORT_BASE, VS1003_xCS, VS1003_xCS);

    //
    // Set xDCS pin to low state
    //
    GPIOPinWrite(VS1003_CTL_GPIO_PORT_BASE, VS1003_xDCS, 0);


    //
    // Send data array to VS1003
    //
    for (ui8i = 0; ui8i < bytes; ui8i++)
    {
        //
        // Wait until DREQ becomes high state
        //
        while (!GPIOPinRead(VS1003_CTL_GPIO_PORT_BASE, VS1003_DREQ));

        //
        // Wait for any previous SSI operation to finish.
        //
        while(SSIBusy(VS1003_SSI_BASE)){}

        //
        // Send one byte to VS1003
        //
        SSIDataPut(VS1003_SSI_BASE, data[ui8i]);
    }

    //
    // Wait for any previous SSI operation to finish.
    //
    while(SSIBusy(VS1003_SSI_BASE)){}

    //
    // Set BSYNC pin to high state
    //
    GPIOPinWrite(VS1003_CTL_GPIO_PORT_BASE, VS1003_xDCS, VS1003_xDCS);

    return 0;
}


//*****************************************************************************
//
//! Writes a register in the DS3231 RTC.
//!
//! \param ucRegister is the offset to the register to write.
//! \param ulData is the data to be written to the DAC register.
//!
//!  This function will write the register passed in ucAddr with the value
//!  passed in to ulData.  The data in ulData is actually 9 bits and the
//!  value in ucAddr is interpreted as 7 bits.
//!
//! \return True on success or false on error.
//
//*****************************************************************************
void VS10xxSwReset(void)
{
    VS10xxSciWrite(SCI_MODE, SM_SDINEW | SM_RESET);
}


//*****************************************************************************
//
//! Plays back an audio file.
//!
//! \param readFp is the offset to the register to write.
//!
//!  This function records an audio file in Ogg, MP3, or WAV formats.e
//!  If recording in WAV format, it updates the RIFF length headers
//!  after recording has finished.
//!
//! \return None.
//
//*****************************************************************************
void VS10xxFilePlay(FILE *readFp)
{
  static uint8_t playBuf[FILE_BUFFER_SIZE];
  uint32_t bytesInBuffer;                                       // How many bytes in buffer left
  uint32_t pos=0;                                               // File position
  long nextReportPos=0;                                         // File pointer where to next collect/report
  int i;
  int c;
  int volLevel;
/*
#ifdef PLAYER_USER_INTERFACE
  int volLevel = VS10xxSciRead(SCI_VOL) & 0xFF;                 // Assume both channels at same level
  int c;
#endif
*/

  playerState = psPlayback;                                     // Set state to normal playback

  VS10xxSciWrite(SCI_DECODE_TIME, 0);                           // Reset DECODE_TIME


  /******************************************************************************************
   * Main playback loop
   ******************************************************************************************/

  while ((bytesInBuffer = fread(playBuf, 1, FILE_BUFFER_SIZE, readFp)) > 0 && playerState != psStopped)
  {
    uint8_t *bufP = playBuf;

    while (bytesInBuffer && playerState != psStopped)
    {
      {
        int t = min(SDI_MAX_TRANSFER_SIZE, bytesInBuffer);

        // This is the heart of the algorithm: on the following line
        // actual audio data gets sent to VS10xx.
        VS10xxSdiWrite(bufP, t);

        bufP += t;
        bytesInBuffer -= t;
        pos += t;
      }

      /* If the user has requested cancel, set VS10xx SM_OUTOFWAV bit */
      if (playerState == psUserRequestedCancel) {
        if (audioFormat == afMp3 || audioFormat == afUnknown) {
          playerState = psStopped;
        } else {
          unsigned short oldMode;
          playerState = psCancelSentToVS10xx;
          UARTprintf("\nSetting SM_OUTOFWAV at file offset %ld\n", pos);
          oldMode = VS10xxSciRead(SCI_MODE);
          VS10xxSciWrite(SCI_MODE, oldMode | SM_OUTOFWAV);
        }
      }

      /* If VS10xx SM_OUTOFWAV bit has been set, see if it has gone
         through. If it is, it is time to stop playback. */
      if (playerState == psCancelSentToVS10xx) {
        unsigned short mode = VS10xxSciRead(SCI_MODE);
        if (!(mode & SM_OUTOFWAV)) {
          UARTprintf("SM_OUTOFWAV has cleared at file offset %ld\n", pos);
          playerState = psStopped;
        }
      }


      /* If playback is going on as normal, see if we need to collect and
         possibly report */
      if (playerState == psPlayback && pos >= nextReportPos) {
#ifdef REPORT_ON_SCREEN
        uint16_t sampleRate;
        uint16_t h1 = VS10xxSciRead(SCI_HDAT1);
#endif

        nextReportPos += (audioFormat == afMidi || audioFormat == afUnknown) ?
          REPORT_INTERVAL_MIDI : REPORT_INTERVAL;

#ifdef REPORT_ON_SCREEN
        if (h1 == 0x7665) {
          audioFormat = afRiff;
        } else if (h1 == 0x4d54) {
          audioFormat = afMidi;
        } else if ((h1 & 0xffe6) == 0xffe2) {
          audioFormat = afMp3;
        } else {
          audioFormat = afUnknown;
        }

        sampleRate = VS10xxSciRead(SCI_AUDATA);

        UARTprintf("\r%ldKiB "
               "%1ds %dHz %s %s"
               " %04x   ",
               pos/1024,
               VS10xxSciRead(SCI_DECODE_TIME),
               sampleRate & 0xFFFE, (sampleRate & 1) ? "stereo" : "mono",
               afName[audioFormat], h1
               );
          
        fflush(stdout);
#endif /* REPORT_ON_SCREEN */
      }
    } /* if (playerState == psPlayback && pos >= nextReportPos) */
  


    /* User interface. This can of course be completely removed and
       basic playback would still work. */

#ifdef PLAYER_USER_INTERFACE
    /* GetUICommand should return -1 for no command and -2 for CTRL-C */
   // c = GetUICommand();
    switch (c) {

      /* Volume adjustment */
    case '-':
      if (volLevel < 255) {
        volLevel++;
        VS10xxSciWrite(SCI_VOL, volLevel*0x101);
      }
      break;
    case '+':
      if (volLevel) {
        volLevel--;
        VS10xxSciWrite(SCI_VOL, volLevel*0x101);
      }
      break;

      /* Show some interesting registers */
    case '_':
      UARTprintf("\nvol %1.1fdB, MODE %04x, ST %04x, "
             "HDAT1 %04x HDAT0 %04x\n",
             -0.5*volLevel,
             VS10xxSciRead(SCI_MODE),
             VS10xxSciRead(SCI_STATUS),
             VS10xxSciRead(SCI_HDAT1),
             VS10xxSciRead(SCI_HDAT0));
      break;

      /* Ask player nicely to stop playing the song. */
    case 'q':
      if (playerState == psPlayback)
        playerState = psUserRequestedCancel;
      break;

      /* Forceful and ugly exit. For debug uses only. */
    case 'Q':
      //RestoreUIState();
      UARTprintf("\n");
      exit(EXIT_SUCCESS);
      break;

      /* Toggle differential mode */
    case 'd':
      {
        uint16_t t = VS10xxSciRead(SCI_MODE) ^ SM_DIFF;
        UARTprintf("\nDifferential mode %s\n", (t & SM_DIFF) ? "on" : "off");
        VS10xxSciWrite(SCI_MODE, t);
      }
      break;

      /* Show help */
    case '?':
      UARTprintf("\nInteractive VS1003 file player keys:\n"
             "- +\tVolume down / up\n"
             "_\tShow current settings\n"
             "q Q\tQuit current song / program\n"
             "d\tToggle Differential\n"
             );
      break;

      /* Unknown commands or no command at all */
    default:
      if (c < -1) {
        UARTprintf("Ctrl-C, aborting\n");
        fflush(stdout);
        //RestoreUIState();
        exit(EXIT_FAILURE);
      }
      if (c >= 0) {
        UARTprintf("\nUnknown char '%c' (%d)\n", isprint(c) ? c : '.', c);
      }
      break;
    } /* switch (c) */
#endif /* PLAYER_USER_INTERFACE */
  } /* while ((bytesInBuffer = fread(...)) > 0 && playerState != psStopped) */


  
#ifdef PLAYER_USER_INTERFACE
  //RestoreUIState();
#endif /* PLAYER_USER_INTERFACE */

  UARTprintf("\nSending %d footer %d's... ", SDI_END_FILL_BYTES, 0);
  fflush(stdout);

  /* Earlier we collected endFillByte. Now, just in case the file was
     broken, or if a cancel playback command has been given, write
     lots of endFillBytes. */
  memset(playBuf, 0, sizeof(playBuf));
  for (i=0; i<SDI_END_FILL_BYTES; i+=SDI_MAX_TRANSFER_SIZE) {
    VS10xxSdiWrite(playBuf, SDI_MAX_TRANSFER_SIZE);
  }

  /* If SM_OUTOFWAV is on at this point, there is some weirdness going
     on. Reset the IC just in case. */
  if (VS10xxSciRead(SCI_MODE) & SM_OUTOFWAV) {
    VS10xxSwReset();
  }

  /* That's it. Now we've played the file as we should, and left VS10xx
     in a stable state. It is now safe to call this function again for
     the next song, and again, and again... */
  UARTprintf("ok\n");
}


//*****************************************************************************
//
//! Records a file
//!
//! \param ucRegister is the offset to the register to write.
//! \param ulData is the data to be written to the DAC register.
//!
//!  This function records an audio file in Ogg, MP3, or WAV formats.e
//!  If recording in WAV format, it updates the RIFF length headers
//!  after recording has finished.
//!
//! \return None.
//
//*****************************************************************************
void VS10xxFileRecord(FILE *writeFp) {
  static uint8_t recBuf[REC_BUFFER_SIZE];
  uint32_t nextReportPos=0;      // File pointer where to next collect/report
  uint32_t fileSize = 0;
  int volLevel = VS10xxSciRead(SCI_VOL) & 0xFF;
  int c;
  uint32_t adpcmBlocks = 0;
  uint16_t sampleRate;
  uint16_t divReg;

  playerState = psPlayback;

  UARTprintf("VS1003RecordFile\n");

  /* Initialize recording */

  /* Set clock to a known, high value. */
  VS10xxSciWrite(SCI_CLOCKF, HZ_TO_SC_FREQ(12288000) | SC_MULT_03_40X | SC_ADD_03_00X);


  /* Voice quality ADPCM recording at 8 kHz.
     This will result in a 32.44 kbit/s bitstream. */
  sampleRate = 8000;
  /* Calculate closest possible value for divider register */
  divReg = (int)((4.0*12288000)/256/sampleRate+0.5);
  /* Calculate back what sample rate we actually got */
  sampleRate = 4*12288000/(256*divReg);

  VS10xxSciWrite(SCI_RECRATE,   divReg);
  VS10xxSciWrite(SCI_RECGAIN,        0); /* 1024 = gain 1, 0 = AGC */
  /* Values according to VS1003b Datasheet Chapter "Adding a RIFF Header" */
  Set32(adpcmHeader+24, sampleRate);
  Set32(adpcmHeader+28, (uint32_t)sampleRate*256/505);
  fwrite(adpcmHeader, sizeof(adpcmHeader), 1, writeFp);
  fileSize = sizeof(adpcmHeader);

  /* Start the encoder */
  VS10xxSciWrite(SCI_MODE, VS10xxSciRead(SCI_MODE) | SM_ADPCM | SM_RESET);


#ifdef RECORDER_USER_INTERFACE
  //SaveUIState();
#endif /* RECORDER_USER_INTERFACE */

  while (playerState != psStopped) {
    int n;

#ifdef RECORDER_USER_INTERFACE
    {
      //c = GetUICommand();
      
      switch(c) {
      case 'q':
        UARTprintf("\nSwitching encoder off...\n");
        playerState = psStopped;
        break;
      case '-':
        if (volLevel < 255) {
          volLevel++;
          VS10xxSciWrite(SCI_VOL, volLevel*0x101);
        }
        break;
      case '+':
        if (volLevel) {
          volLevel--;
          VS10xxSciWrite(SCI_VOL, volLevel*0x101);
        }
        break;
      case '_':
        UARTprintf("\nvol %4.1f\n", -0.5*volLevel);
        break;
      case '?':
        UARTprintf("\nInteractive VS1003 file recorder keys:\n"
               "- +\tVolume down / up\n"
               "_\tShow current settings\n"
               "q\tQuit recording\n"
               );
        break;
      default:
        if (c < -1) {
          UARTprintf("Ctrl-C, aborting\n");
          fflush(stdout);
          //RestoreUIState();
          exit(EXIT_FAILURE);
        }
        if (c >= 0) {
          UARTprintf("\nUnknown char '%c' (%d)\n", isprint(c) ? c : '.', c);
        }
        break;  
      }
      
    }
#endif /* RECORDER_USER_INTERFACE */


    /* See if there is some data available */
    if ((n = VS10xxSciRead(SCI_RECWORDS)) > REC_BUFFER_SIZE) {
      int i;
      uint8_t *rbp = recBuf;

      /* Always writes one or two IMA ADPCM block(s) at a time */
      n = REC_BUFFER_SIZE/2;
      adpcmBlocks += 2;

      for (i=0; i<n; i++) {
        uint16_t w = VS10xxSciRead(SCI_RECDATA);
        *rbp++ = (uint8_t)(w >> 8);
        *rbp++ = (uint8_t)(w & 0xFF);
      }
      fwrite(recBuf, 1, 2*n, writeFp);
      fileSize += 2*n;
    }

    if (fileSize - nextReportPos >= REPORT_INTERVAL) {
      nextReportPos += REPORT_INTERVAL;
      UARTprintf("\r%ldKiB ", fileSize/1024);
      UARTprintf("%uHz mono RIFF ", sampleRate);
      fflush(stdout);
    }
  } /* while (playerState != psStopped) */

  
  /* Update file sizes according to VS1003b Datasheet Chapter
     "Adding a RIFF Header" */
  fseek(writeFp, 0, SEEK_SET);
  Set32(adpcmHeader+4, fileSize-8);
  Set32(adpcmHeader+48, adpcmBlocks*505);
  Set32(adpcmHeader+56, fileSize-60);
  fwrite(adpcmHeader, sizeof(adpcmHeader), 1, writeFp);


#ifdef RECORDER_USER_INTERFACE
 // RestoreUIState();
#endif /* RECORDER_USER_INTERFACE */

  /* Finally, reset the VS10xx software, including realoading the
     patches package, to make sure everything is set up properly. */
  //VSTestInitSoftware();

  UARTprintf("ok\n");
}


//*****************************************************************************
//
//! Writes a register in the DS3231 RTC.
//!
//! \param ucRegister is the offset to the register to write.
//! \param ulData is the data to be written to the DAC register.
//!
//!  This function will write the register passed in ucAddr with the value
//!  passed in to ulData.  The data in ulData is actually 9 bits and the
//!  value in ucAddr is interpreted as 7 bits.
//!
//! \return True on success or false on error.
//
//*****************************************************************************
uint8_t VS10xxInit(void)
{
    //
    // Enable the peripherals used by this driver
    //
    SysCtlPeripheralEnable(VS1003_SSI_SYSCTL_PERIPH);
    SysCtlPeripheralEnable(VS1003_SSI_GPIO_SYSCTL_PERIPH);
    SysCtlPeripheralEnable(VS1003_CTL_GPIO_SYSCTL_PERIPH);

    // PD2 f�r SSI1Rx
    //SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOD);
    //GPIOPinConfigure(GPIO_PD2_SSI1RX);
    //GPIOPinTypeSSI(GPIO_PORTD_BASE, GPIO_PIN_0);

    //
    // Select the SSI function for the appropriate pins
    //
    GPIOPinConfigure(VS1003_PINCFG_SSICLK);
    GPIOPinConfigure(VS1003_PINCFG_SSIRX);
    GPIOPinConfigure(VS1003_PINCFG_SSITX);

    //
    // Configure the pins for the SSI function
    //
    GPIOPinTypeSSI(VS1003_SSI_GPIO_PORT_BASE, VS1003_SSI_PINS);

    //
    // Configure VS1003 xRST ,xDCS and xCS control pins as GPIO output
    //
    GPIOPinTypeGPIOOutput(VS1003_CTL_GPIO_PORT_BASE, VS1003_CTL_PINS);

    //
    // Configure VS1003 DREQ control pins as GPIO output
    //
    GPIOPinTypeGPIOInput(VS1003_CTL_GPIO_PORT_BASE, VS1003_DREQ);

    //
    // Disable VS1003
    //
    GPIOPinWrite(VS1003_CTL_GPIO_PORT_BASE, VS1003_xRST, 0);

    //
    // Configure the SSI port
    //
    //
    SSIDisable(VS1003_SSI_BASE);
    SSIConfigSetExpClk( VS1003_SSI_BASE,
                        SysCtlClockGet(),
                        SSI_FRF_MOTO_MODE_3,
                        SSI_MODE_MASTER,
                        VS1003_SSI_CLOCK,
                        8);

    SSIEnable(VS1003_SSI_BASE);

    //
    // Enable VS1003
    //
    GPIOPinWrite(VS1003_CTL_GPIO_PORT_BASE, VS1003_xRST, VS1003_xRST);

    uint16_t ret;    // Test variable

     /* Start initialization with a dummy read, which makes sure our
        microcontoller chips selects and everything are where they
        are supposed to be and that VS10xx's SCI bus is in a known state. */
     VS10xxSciRead(SCI_MODE);

     /* First real operation is a software reset. After the software
        reset we know what the status of the IC is. You need, depending
        on your application, either set or not set SM_SDISHARE. See the
        Datasheet for details. */
     //WriteSci(SCI_MODE, SM_SDINEW|SM_SDISHARE|SM_TESTS|SM_RESET);
     VS10xxSciWrite(SCI_MODE, SM_SDINEW | SM_RESET);

     /* A quick sanity check: write to two registers, then test if we
        get the same results. Note that if you use a too high SPI
        speed, the MSB is the most likely to fail when read again. */
     //VS10xxSciWrite(SCI_HDAT0, 0xABAD); // 10101011 10101101 00001000
     //ret = VS10xxSciRead(SCI_HDAT0);

     //VS10xxSciWrite(SCI_HDAT1, 0x1DEA); // 00011101 11101010 00001001


     VS10xxSciWrite(SCI_BASS, 0x020A);   // 00000010 00000010 00001000
     ret = VS10xxSciRead(SCI_BASS);

     /*
     if (ReadSci(SCI_HDAT0) != 0xABAD || ReadSci(SCI_HDAT1) != 0x1DEA) {
       UARTprintf("There is something wrong with VS10xx\n");
       return 1;
     }
     */

     /* Set the clock. Until this point we need to run SPI slow so that
        we do not exceed the maximum speeds mentioned in
        Chapter SPI Timing Diagram in the Datasheet. */
     VS10xxSciWrite(SCI_CLOCKF, HZ_TO_SC_FREQ(12288000) | SC_MULT_03_30X | SC_ADD_03_10X);


     /* Now when we have upped the VS10xx clock speed, the microcontroller
        SPI bus can run faster. Do that before you start playing or
        recording files. */

     /* Set volume level at -6 dB of maximum */
     VS10xxSciWrite(SCI_VOL, 0x0c0c);

     /* We're ready to go. */
     return 0;
}

//*****************************************************************************
//
// Close the Doxygen group.
//! @}
//
//*****************************************************************************
































/***************************************************************
 ****************************************************************/

/*
  Main function that activates either playback or recording.
*/
/*
int VSTestHandleFile(const char *fileName, int record) {
  if (!record) {
    FILE *fp = fopen(fileName, "rb");
    UARTprintf("Play file %s\n", fileName);
    if (fp) {
      VS1003PlayFile(fp);
    } else {
      UARTprintf("Failed opening %s for reading\n", fileName);
      return -1;
    }
  } else {
    FILE *fp = fopen(fileName, "wb");
    UARTprintf("Record file %s\n", fileName);
    if (fp) {
      VS1003RecordFile(fp);
    } else {
      UARTprintf("Failed opening %s for writing\n", fileName);
      return -1;
    }
  }
  return 0;
}






















*/


  • Hello Mathias

    SSI requires that for every SSIDataPut a SSIDataGet is also done so that the RXFIFO is cleared. This way when an actual data is to be expected, the RXFIFO is empty and read will return the data to the calling process. I see that in your code there are quite some SSIDataPut without SSIDataGet.

    Regards
    Amit
  • In addition to Amit's sound advice - poster must recall that "SPI" performs (both) read & write via the same clock signal (although possibly a different clock edge). As Amit notes - lack of "binding" SSIDataGet to each SSIDataPut is your likely issue. (and now you know why that's the case...)
  • Hi Amit,

    thanks you very much for the quick response. I've just tested it without any success. After some search in the datasheet I've seen that PF0 is muxed with NMI signal and is therefore a locked pin. I've tried to unlock it and change the mux to be SSI1Rx signal. Also here, no success. Could you give me advice on how to unlock PF0 and mux it in a way that is works as SSI1Rx, please.

    Many thanks!!!

  • Hello Mathias,

    The following resource shall be useful in some common issues and tips.

    e2e.ti.com/.../374640

    Regards
    Amit