how to record my voice in Vs1003?

Writing software for systems that use VLSI Solution's devices as slave codecs to a host microcontroller.
mf1364
Senior User
Posts: 25
Joined: Sun 2012-09-02 7:53

Re: how to record my voice in Vs1003?

Post by mf1364 » Wed 2014-07-23 10:58

Thank you very much I got it
There is another question I used to used SPI protocol for setting vs registers no I want to know is it possible to use UART protocol to set vs registers instead of SPI ?

User avatar
pasi
VLSI Staff
Posts: 1659
Joined: Thu 2010-07-15 16:04

Re: how to record my voice in Vs1003?

Post by pasi » Wed 2014-07-23 13:29

UART is not prepared to take commands. You would need a special routine for that, and because uploading custom code into the chip requires SCI anyway (or SPI EEPROM), it is not really making things any easier.
Visit https://www.facebook.com/VLSISolution VLSI Solution on Facebook

User avatar
Panu
VLSI Staff. Currently on holiday.
Posts: 2723
Joined: Tue 2010-06-22 13:43

Read 512 bytes from the recording buffer

Post by Panu » Mon 2014-08-04 17:34

There was an email question about how to read 512 bytes of encoded data when the encoder is running. Here's the answer, hopefully correct:

When VS10xx encoder puts more data into the buffer, HDAT1 increases. When you read data from HDAT0, HDAT1decreases. Just make a buffer of 512 bytes. Then do it something like this:

Code: Select all

unsigned char buf[512];
unsigned int need;
unsigned int available;
unsigned char *p;
unsigned int hdat0;

need = 256;
p = buf;

while (need) {
  available = getVSregister(SCI_HDAT1);
  if (available > need) available = need;
  need -= available;
  while (available) {
    hdat0 = getVSregister(SCI_HDAT0);
    *p++ = hdat0 >> 8;
    *p++ = hdat0 & 0xff;
    available--;
  }
}
Now you have 512 bytes in buf[512];, at leat hopefully. I haven't tested the code.

-Panu
Info: Line In and Line Out, VS1000 User interface, Overlay howto, Latest VSIDE, MCU Howto, Youtube
Panu-Kristian Poiksalo, VLSI Solution Oy

m4hd1r
User
Posts: 1
Joined: Mon 2015-10-05 12:31

Re: how to record my voice in Vs1003?

Post by m4hd1r » Mon 2015-10-05 12:48

Hello guys.
I want to record voice using vs1003 and i have some problems.
the recorded file has not any audible sound. there is some random pops in the file.
there is a 12.288MHz xtal and
CLOCKF = 0xc000
AICTRL0 = 12
AICTRL0 = 0
header :

Code: Select all

const unsigned char header[] = {
'R' , 'I' , 'F' , 'F' , // Chunk ID (RIFF)
0x70, 0x70, 0x70, 0x70, // Chunk payload size (calculate after rec!)
'W' , 'A' , 'V' , 'E' , // RIFF resource format type

'f' , 'm' , 't' , ' ' , // Chunk ID (fmt )
0x14, 0x00, 0x00, 0x00, // Chunk payload size (0x14 = 20 bytes)
0x11, 0x00,             // Format Tag (IMA ADPCM)
0x01, 0x00,             // Channels (1)
0x80, 0x3e, 0x00, 0x00, // Sample Rate, 0x3e80 = 16.0kHz
0xd7, 0x0f, 0x00, 0x00, // Average Bytes Per Second
0x00, 0x01,             // Data Block Size (256 bytes) 
0x04, 0x00,             // ADPCM encoded bits per sample (4 bits)
0x02, 0x00,             // Extra data (2 bytes)
0xf9, 0x01,             // Samples per Block (505 samples)

'f' , 'a' , 'c' , 't' , // Chunk ID (fact)
0xc8, 0x01, 0x00, 0x00, // Chunk payload size (456 bytes (zeropad!))
0xff, 0xff, 0xff, 0xff  // Number of Samples (calculate after rec!)
};
and 448 zeros after that and

Code: Select all

const unsigned char header2[] = {
'd' , 'a' , 't' , 'a' , // Chunk ID (data)
0x70, 0x70, 0x70, 0x70  // Chunk payload size (calculate after rec!)
};

and I replace the size values in the header after recording the file.
the following file is a recorded wav file without trimming header
I always wait for 256 words and put them in a 512 byte variable and write them in the file.
but i cant hear anything
is there any thing, except the size related things tags is the header, wrong?
the schematic is in following link
http://server4.eca.ir/eshop/vs1003/Schematic.pdf
Attachments
mp1.wav
(50.5 KiB) Downloaded 103 times

User avatar
pasi
VLSI Staff
Posts: 1659
Joined: Thu 2010-07-15 16:04

Re: how to record my voice in Vs1003?

Post by pasi » Tue 2015-10-06 13:34

You have 4 too few bytes before the "data" chunk. With fact chunk size 0x1c8 the data text should be at 0x1c8 and the data itself start at a sector boundary.

After 4 bytes are added in the middle, the file will actually play, but there is still some issue. Perhaps missing data, because I don't see the IMA ADPCM 0-byte at the correct bytes (4th byte of each block should be 0).
Visit https://www.facebook.com/VLSISolution VLSI Solution on Facebook

paulsin
User
Posts: 3
Joined: Thu 2020-01-30 5:40

Re: how to record my voice in Vs1003?

Post by paulsin » Thu 2020-01-30 5:55

I am trying to record voice using VS1003. After working for some days, I was able to record sound from the LINE_IN. But, it has many distortions. I have attached the audio file. Can anyone help me to solve the problem? I have attached my arduino program also. For testing purposes, I have fixed the file size as 51200 bytes. I have updated the "RIFF" header chunk, "FACT" header chunk and "DATA" header chunk as per 51200 bytes.

Code: Select all


//#include <VS1003ESP12.h>
//#include <ESP8266WiFi.h>
#include <SPI.h>
#include <SD.h>

// Size of the "wav" file set to 100*512 bytes including the header files
const unsigned char RIFFHeader0fn[] = {
    'R' , 'I' , 'F' , 'F' , // Chunk ID (RIFF)
    0xF8, 0xC7, 0x00, 0x00, // Chunk payload size (calculate after rec!)
    'W' , 'A' , 'V' , 'E' , // RIFF resource format type

    'f' , 'm' , 't' , ' ' , // Chunk ID (fmt )
    0x14, 0x00, 0x00, 0x00, // Chunk payload size (0x14 = 20 bytes)
    0x11, 0x00,             // Format Tag (IMA ADPCM)
    0x01, 0x00,             // Channels (1)
    0x80, 0x3e, 0x00, 0x00, // Sample Rate, 0x3e80 = 16.0kHz
    0xd7, 0x0f, 0x00, 0x00, // Average Bytes Per Second
    0x00, 0x01,             // Data Block Size (256 bytes) 
    0x04, 0x00,             // ADPCM encoded bits per sample (4 bits)
    0x02, 0x00,             // Extra data (2 bytes)
    0xf9, 0x01,             // Samples per Block (505 samples)

    'f' , 'a' , 'c' , 't' , // Chunk ID (fact)
    0xc8, 0x01, 0x00, 0x00, // Chunk payload size (456 bytes (zeropad!))
    0x96, 0x86, 0x01, 0x00  // Number of Samples (calculate after rec!)
};

const unsigned char RIFFHeader504fn[] = {
    'd' , 'a' , 't' , 'a' , // Chunk ID (data)
    0x00, 0xC6, 0x00, 0x00, // Chunk payload size (calculate after rec!)
};

// VS1003 SCI Write Command byte is 0x02
#define VS_WRITE_COMMAND 0x02

// VS1003 SCI Read COmmand byte is 0x03
#define VS_READ_COMMAND  0x03

const int xCs = A3;
const int xDcs = A2;
const int xDreq = 4;
const int xReset = A0;

const int sdCs = 10;
const int ctrlBtn = 2;

int loopCount = 0;

bool recorded = false;
bool recording = false;

File myFile;
File wavFile;
char fileName[] = "wavFile5.WAV";
String wavFileName = "wavFile5.WAV";
byte data[4];

// SCI Registers

const uint8_t SCI_MODE = 0x0;
const uint8_t SCI_STATUS = 0x1;
const uint8_t SCI_BASS = 0x2;
const uint8_t SCI_CLOCKF = 0x3;
const uint8_t SCI_DECODE_TIME = 0x4;
const uint8_t SCI_AUDATA = 0x5;
const uint8_t SCI_WRAM = 0x6;
const uint8_t SCI_WRAMADDR = 0x7;
const uint8_t SCI_HDAT0 = 0x8;
const uint8_t SCI_HDAT1 = 0x9;
const uint8_t SCI_AIADDR = 0xa;
const uint8_t SCI_VOL = 0xb;
const uint8_t SCI_AICTRL0 = 0xc;
const uint8_t SCI_AICTRL1 = 0xd;
const uint8_t SCI_AICTRL2 = 0xe;
const uint8_t SCI_AICTRL3 = 0xf;
const uint8_t SCI_num_registers = 0xf;

// SCI_MODE bits

const uint8_t SM_DIFF = 0;
const uint8_t SM_LAYER12 = 1;
const uint8_t SM_RESET = 2;
const uint8_t SM_OUTOFWAV = 3;
const uint8_t SM_EARSPEAKER_LO = 4;
const uint8_t SM_TESTS = 5;
const uint8_t SM_STREAM = 6;
const uint8_t SM_EARSPEAKER_HI = 7;
const uint8_t SM_DACT = 8;
const uint8_t SM_SDIORD = 9;
const uint8_t SM_SDISHARE = 10;
const uint8_t SM_SDINEW = 11;
const uint8_t SM_ADPCM = 12;
const uint8_t SM_ADCPM_HP = 13;
const uint8_t SM_LINE_IN = 14;

//unsigned char HelloMP3[] = {
//0xFF,0xF2,0x40,0xC0,0x19,0xB7,0x00,0x14,0x02,0xE6,0x5C, /* ..@.......\ */
//};

uint16_t w = 0, idx = 0, t=0;
unsigned char db[512];

void control_mode_on(void)
{
  digitalWrite(xDcs, HIGH);
  digitalWrite(xCs,LOW);
}

void await_data_request(void)
{
  while ( !digitalRead(xDreq) );
}

void control_mode_off(void)
{
  digitalWrite(xCs, HIGH);
}

uint16_t read_register(uint8_t _reg)
{
  uint16_t result;
  //await_data_request();
  control_mode_on();
  delayMicroseconds(1); // tXCSS
  SPI.transfer(VS_READ_COMMAND); // Read operation
  SPI.transfer(_reg); // Which register
  result = SPI.transfer(0xff) << 8; // read high byte
  result |= SPI.transfer(0xff); // read low byte
  delayMicroseconds(1); // tXCSH
  await_data_request();
  control_mode_off();
  return result;
}

uint16_t read_register_my_own(uint8_t _reg)
{
  while(!digitalRead(xDreq));
  digitalWrite(xCs, LOW);
  SPI.transfer(VS_READ_COMMAND);
  SPI.transfer(_reg);
  unsigned char response1 = SPI.transfer(0xFF);
  unsigned char response2 = SPI.transfer(0xFF);
  digitalWrite(xCs, HIGH);
  return ((unsigned int) response1 << 8) | (response2 & 0xFF);
}

void write_register(uint8_t _reg, uint16_t _value)
{
  control_mode_on();
  delayMicroseconds(1); // tXCSS
  SPI.transfer(VS_WRITE_COMMAND); // Write operation
  SPI.transfer(_reg); // Which register
  SPI.transfer(_value >> 8); // Send hi byte
  SPI.transfer(_value & 0xff); // Send lo byte
  delayMicroseconds(1); // tXCSH
  await_data_request();
  control_mode_off();
}

void data_mode_on(void)
{
  digitalWrite(xCs, HIGH);
  digitalWrite(xDcs, LOW);
}

void data_mode_off(void)
{
  digitalWrite(xDcs, HIGH);
}

void setVolume(uint8_t vol)
{
  uint16_t value = vol;
  value <<= 8;
  value |= vol;

  write_register(SCI_VOL, value); // VOL
}

void record(void)
{

  digitalWrite(xReset, LOW);
  digitalWrite(xCs, HIGH);
  digitalWrite(xDcs, HIGH);

  digitalWrite(xReset, HIGH);

  //SPI.setDataMode(SPI_MODE0);
  //SPI.setBitOrder(MSBFIRST);
  //SPI.setClockDivider(SPI_CLOCK_DIV64); 
  SPI.beginTransaction(SPISettings(400000, MSBFIRST, SPI_MODE0));
  
  write_register(SCI_VOL, 0x0000);
  write_register(SCI_BASS, 0);
  write_register(SCI_CLOCKF, 0x4430);

  write_register(SCI_AICTRL0, 6);
  delay(100);
  /* Rec level: 1024 = 1. If 0, use AGC */
  write_register(SCI_AICTRL1, 1024);
  delay(100);
  /* Maximum AGC level: 1024 = 1. Only used if SCI_AICTRL1 is set to 0. */
  //write_register(SCI_AICTRL2, 0);
  //delay(100);
  
  /* Miscellaneous bits that also must be set before recording. */
  //write_register(SCI_AICTRL3, 0);

  //write_register(SCI_MODE, _BV(SM_LINE_IN) | _BV(SM_RESET) | _BV(SM_SDINEW));
  write_register(SCI_MODE, 0x5804);
}

void disableVS1003(void)
{
  digitalWrite(xCs, HIGH);   
  digitalWrite(sdCs, LOW);
}

void enableVS1003(void)
{
  digitalWrite(xCs, LOW);
  digitalWrite(sdCs, HIGH);     
}

void setup () {

  pinMode(sdCs, OUTPUT);
  // digitalWrite(sdCs, HIGH);

  // Keep the chip in reset until we are ready
  pinMode(xReset, OUTPUT);
  pinMode(xCs, OUTPUT);
  pinMode(xDcs, OUTPUT);
  pinMode(xDreq, INPUT); 
  pinMode(ctrlBtn, INPUT);

  // initiate SPI
  SPI.begin();
  //SPI.setClockDivider(SPI_CLOCK_DIV64);
  //SPI.beginTransaction(SPISettings(250000, MSBFIRST, SPI_MODE0));

  // initiate a serial port at 57600
  Serial.begin(115200);

  disableVS1003();

  while(!SD.begin(sdCs))
  {
    Serial.println("SD initialization failed..");
  }

  if(SD.exists(fileName))
  {
    SD.remove(fileName);
  }

  (myFile = SD.open(fileName, FILE_WRITE)) ? Serial.println("SD opening successfull") : Serial.println("SD opening failed");

  myFile.seek(0);
  
  myFile.write(RIFFHeader0fn, sizeof(RIFFHeader0fn));

  Serial.println(myFile.size());

  // Write '0' (0x30) from address 51 to 503 
  for (int i = 0; i<452; i++)
  {
    myFile.write('0');
  }

  Serial.println(myFile.size());

  // write second RIFF header from 504 to 511
  myFile.write(RIFFHeader504fn, sizeof(RIFFHeader504fn));

  Serial.println(myFile.size());

  myFile.close();

  (myFile = SD.open(fileName, FILE_WRITE)) ? Serial.println("SD opening successfull") : Serial.println("SD opening failed");

  enableVS1003();

  record();
}

void loop() {

  int RECBUFFSIZE = 128;
  if(digitalRead(ctrlBtn) == true)
  {
    while(loopCount < 99)
    {
      //wait until 512 bytes become available
      do {
        t = read_register_my_own(SCI_HDAT1);
        //Serial.print("data words to read: ");
        //Serial.println(t);
        //delay(100);
      } while (t < 256 || t >= 896);
    
      //Serial.println("Reading data...");
      while (idx < 512)
      {
        uint16_t w = read_register_my_own(SCI_HDAT0);
        db[idx++] = w >> 8;
        db[idx++] = w & 0xFF;
      }
      
      //Serial.println("Finished reading data...");
      idx = 0;
      //Serial.println("Writing to disk...");
      //disableVS1003();
      myFile.write(db, sizeof(db));
      //enableVS1003();
      //Serial.println("Finished writing to disk..");
      myFile.flush();

      recording = true;
      loopCount++;
      
    }
  }
   
  if(digitalRead(ctrlBtn) == false && recording == true)
  {
    recording = false;


    Serial.println("Finished...");

  }
}[attachment=0]WAVFILE5.WAV[/attachment]

Attachments
WAVFILE5.WAV
(50 KiB) Downloaded 7 times

User avatar
pasi
VLSI Staff
Posts: 1659
Joined: Thu 2010-07-15 16:04

Re: how to record my voice in Vs1003?

Post by pasi » Thu 2020-01-30 12:38

paulsin wrote:
Thu 2020-01-30 5:55
I have updated the "RIFF" header chunk, "FACT" header chunk and "DATA" header chunk as per 51200 bytes.
The structure of the file seems correct, but we see discontinuity at the borders of the IMA ADPCM frames. This points to some kind of data corruption.

The usual issues we have ruled out:
* CR/LF conversions - text mode file operations can do conversions to 0x0a and 0x0c, adding bytes or changing 0x0a to 0x0c or vice versa. This isn't the case in your file. We don't see inserted or removed bytes, and both 0x0a and 0x0c exist in the file on their own.
* No repeated words.

It looks like the only explanation is bit errors in the data. Bit errors will quickly cause the IMA ADPCM state to run away and the amplitude explodes, then reset again at the start of the next IMA ADPCM frame.

What is your SPI speed? Also check the clock polarity you are using.

We suggest you test your SCI routines: write all possible 16-bit values to a SCI register (e.g. AICTRL0) and read them back and compare.
Visit https://www.facebook.com/VLSISolution VLSI Solution on Facebook

paulsin
User
Posts: 3
Joined: Thu 2020-01-30 5:40

Re: how to record my voice in Vs1003?

Post by paulsin » Thu 2020-01-30 17:24

The usual issues we have ruled out:
* CR/LF conversions - text mode file operations can do conversions to 0x0a and 0x0c, adding bytes or changing 0x0a to 0x0c or vice versa. This isn't the case in your file. We don't see inserted or removed bytes, and both 0x0a and 0x0c exist in the file on their own.
* No repeated words.
I didn't understand this. Which is the suitable SPI speed?

User avatar
pasi
VLSI Staff
Posts: 1659
Joined: Thu 2010-07-15 16:04

Re: how to record my voice in Vs1003?

Post by pasi » Fri 2020-01-31 11:07

paulsin wrote:
Thu 2020-01-30 17:24
Which is the suitable SPI speed?
You seem to use 2.0x clock, so the highest SPI speed that will work is about 2*12.2888/7 = 3.5Mbit/s.

If your SPI speed is 3.5Mbit/s or lower and you have the SPI in the correct clock edge mode, your operations should work, assuming that your data and clock lines behave the same. (I.e. not significantly different capacitances or other sources of delay.)
Visit https://www.facebook.com/VLSISolution VLSI Solution on Facebook

paulsin
User
Posts: 3
Joined: Thu 2020-01-30 5:40

Re: how to record my voice in Vs1003?

Post by paulsin » Sun 2020-02-16 6:24

My attempt to record voice using VS1003 is successful. But, there is much noise in Auto Gain Mode. I am using a 16Mhz microcontroller. My SCI_CLOCKF is 0x4430,
SCI_AICTRL0 is 12,
SCI_AICTRL1 is 0
SPI speed is 250000
I have attached the recorded audio. Can anyone help me to reduce the noise?
Attachments
WAVFILE6.WAV
(57.5 KiB) Downloaded 1 time

Post Reply