Example Record Code for Arduino

Writing software for systems that use VLSI Solution's devices as slave codecs to a host microcontroller.
admhrv
User
Posts: 11
Joined: Thu 2011-02-17 22:34

Example Record Code for Arduino

Post by admhrv » Thu 2011-02-24 20:56

Hi,
I'm looking for a code example that shows how recording is done on an Arduino board. I'm using a custom PCB with an Arduino clone and would like to implement a high quality WAV or OGG recording. Haven't been able to find a straightforward example yet. What are the best resources for getting started with recording? And which is easier to implement the WAV or OGG recording? The application is for a voice recorder.

Thanks,
Adam

Architect
User
Posts: 1
Joined: Thu 2011-02-24 0:56

Re: Example Record Code for Arduino

Post by Architect » Fri 2011-02-25 0:41

I am also looking for an example of recording IMA ADPCM. I am evaluating arduino compatible shield(vs1053b) using .net micro framework based device . Shield is built using reference schematic from the vs1053b datasheet. Playback works great. Recording I am having issues with.

User avatar
Panu
VLSI Staff
Posts: 2418
Joined: Tue 2010-06-22 13:43

Re: Example Record Code for Arduino

Post by Panu » Sun 2011-02-27 14:23

Ok, here's a small contribution, but first a warning:

Don't use the below code for anything!

The code is several years old, and it is incompatible with current versions of the ogg encoder. But it was working code (several years ago) and things have not changed that much in the encoder... So what I'm basically saying is that in a perfect universe I'd have the time to immediately write a new ogg vorbis recording code based on the vorbis plugin documentation, but since there's no way I have the time right now, I'm thinking that giving even the old code may be helpful for someone to get started.

The code is from the 1053 Modular Player source code at http://www.vlsi.fi/en/support/software/ ... tware.html. I abbreviated it a little: removed the recording decibel level display and the end-of-fragment bailout handling so that it would be a little more comprehensible. But as I said, the procedure for recording has changed, see the vorbis encoder pdf.

One final remark, which has been helpful for at least 2 customers: If you upload the 1053 patch, you MUST play some file before uploading the vorbis encoder plugin. If you start recording right after reset, don't send the (normal) player patch code.

Good Luck, and let's keep in touch...

-Panu

Code: Select all

#include "venc44k2q05.plg"
void LoadUserCode(void) {
  int i = 0;
  ConsoleWrite("\rLoadUserCode.");
  while (i<sizeof(plugin)/sizeof(plugin[0])) {
    unsigned short addr, n, val;
    addr = plugin[i++];
    n = plugin[i++];
    if (n & 0x8000U) { /* RLE run, replicate n samples */
      n &= 0x7FFF;
      val = plugin[i++];
      while (n--) {
        Mp3WriteRegister(addr, val>>8, val & 0xff);
      }
    } else {           /* Copy run, copy n samples */
      while (n--) {
        val = plugin[i++];
        Mp3WriteRegister(addr, val>>8, val & 0xff);
      }
    }
  }
}

Code: Select all

unsigned char Record(){
  xdata unsigned char blockNumber;
  xdata unsigned long sectorCount;
  xdata unsigned long lastSector;
  bit stopRecording = 0;
  bit continueRecording = 0;
  char newDisplayValue ;  
  blockNumber = 0;
  sectorCount = 1;

  playingState = PS_RECORDING; //Inform the world that rec mode is on.

 
  // Locate free space
  /** This recording function can only save data into a continuous
      area on disk. The Fragment Table fragment[] is used in a special way
      for recording (to save microcontroller RAM space).
      fragment[0].start is the first disk sector of the file
      fragment[0].length will contain the number of disk sectors for the file.

      \bug In case of fragmented filesystem, this version will not
      function properly.
  */
  // Locate a free sector on storage. Uses global u_int freeSector
  freeSector = 0;
  ScanForFreeSector(); sectorAddress.l = freeSector;
  fragment[0].start = freeSector;
  lastSector = freeSector;
  dataBufPtr = diskSect.raw.buf;
  blockNumber = 0;
  ConsoleWrite("\rRecording, push button to stop..."); 


  // Kick vs10xx into action!
  Mp3SoftResetWithoutPatch();
  Mp3WriteRegister(SPI_CLOCKF,  0xc0,0x00); Delay(1); while(!MP3_DREQ);
  Mp3WriteRegister(SPI_BASS, 0x00,0x00); Delay(1); while(!MP3_DREQ);
  Mp3WriteRegister(SPI_AIADDR, 0x00,0x00);
  Mp3WriteRegister(SPI_WRAMADDR, 0xC0,0x1A);
  Mp3WriteRegister(SPI_WRAM, 0x00,0x02);
  LoadUserCode();
  Mp3WriteRegister(SPI_MODE, 0x58,0x00); Delay(1); while(!MP3_DREQ);
  Mp3WriteRegister(SPI_AICTRL0, 0x00,0x00); Delay(1); while(!MP3_DREQ);
  Mp3WriteRegister(SPI_AICTRL1, 0x00,0x00); Delay(1); while(!MP3_DREQ);
  Mp3WriteRegister(SPI_AICTRL2, 0x10,0x00); Delay(1); while(!MP3_DREQ);
  Mp3WriteRegister(SPI_AICTRL3, 0x00,0x00); Delay(1); while(!MP3_DREQ);
  Mp3WriteRegister(SPI_AIADDR, 0x00,0x34);Delay(1); while(!MP3_DREQ);


  while(!stopRecording){
  
    //Delay(100);
  
    { 
      if (KEY_BUTTON) { //Request to stop recording
      	Mp3WriteRegister(SPI_AICTRL3, 0x00,0x01);
      }
      
      // Ok to stop recording?
      if (Mp3ReadRegister(SPI_AICTRL3) & 1){
	stopRecording = 1;
      }
      
      AvailableProcessorTime();  // Handle UI    
    }
    
    if (Mp3ReadRegister(SPI_HDAT1) > 255){ 
      //there is a data block to be read...
      GREEN_LED = LED_ON;
      blockNumber++;
      dataBufPtr = diskSect.raw.buf;
      
      for (temp.c=0;temp.c<128;temp.c++){
	data unsigned int i;
	i = Mp3ReadRegister(SPI_HDAT0);		
	*dataBufPtr++ = (i>>8);
	*dataBufPtr++ = (i&0xff);
	i = Mp3ReadRegister(SPI_HDAT0);		
	*dataBufPtr++ = (i>>8);
	*dataBufPtr++ = (i&0xff);
      }
      
      //Release SCI chip select, we might want to use MMC card
      Mp3DeselectControl();

      RED_LED = LED_ON;
      blockNumber = 0;
      sectorCount++;
      WriteDiskSector(sectorAddress.l);
     

      RED_LED = LED_OFF;
      GREEN_LED = LED_OFF;

      //if there was data to read
    } else {
      Delay(1);
    }

  }//while not button - stop recording when BUTTON is pressed
  

  while (Mp3ReadRegister(SPI_HDAT1) > 0){ 
    int n = Mp3ReadRegister(SPI_HDAT1);
    n -= 256;
    

    //there is a data block to be read...
    GREEN_LED = LED_ON;
    blockNumber++;
    dataBufPtr = diskSect.raw.buf;
    
    for (temp.c=0;temp.c<128;temp.c++){
      data unsigned int i;
      i = Mp3ReadRegister(SPI_HDAT0);		
      *dataBufPtr++ = (i>>8);
      *dataBufPtr++ = (i&0xff);
      i = Mp3ReadRegister(SPI_HDAT0);		
      *dataBufPtr++ = (i>>8);
      *dataBufPtr++ = (i&0xff);
    }
    
    if (n<0) {
      for (temp.c = 0; temp.c<(-n); temp.c++){
	*--dataBufPtr = 0;
	*--dataBufPtr = 0;
      }
    }
      

    //Release SCI chip select, we might want to use MMC card
    Mp3DeselectControl();
    
    RED_LED = LED_ON;
    blockNumber = 0;
    sectorCount++;
    WriteDiskSector(sectorAddress.l);
    
    RED_LED = LED_OFF;
    GREEN_LED = LED_OFF;
    
    if (n<0){
      break;
    }
    
  }
  

  fragment[0].length = sectorCount;    
  ConsoleWrite("Registering... FStart:");
  ConsolePutUInt(fragment[0].start);
  ConsoleWrite("Registering... Size:");
  ConsolePutUInt(fragment[0].length);
  //Create FAT records.
  fragment[1].start = 0x0fffffff; //fragment 0 is the only fragment
  WriteClusterChain(); //register newly created file in FAT FS

  /** \todo second FAT table update */
  
  sectorAddress.l = 0; //force sector reload for next access
  
  Mp3SoftReset();
  return PS_NEXT_SONG;
  
}

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

admhrv
User
Posts: 11
Joined: Thu 2011-02-17 22:34

Re: Example Record Code for Arduino

Post by admhrv » Mon 2011-02-28 3:40

Thanks Panu. I'll give this a try. It looks similar to what Seeed implemented on their music shield:
http://code.google.com/p/musicshield/

And I noticed in there notes that they don't suggest using an Atmega328 because it doesn't have enough RAM. But I didn't come across any RAM requirements in the VS1053 datasheets. Are there any microcontroller RAM requirements for recording IMA WAV or OGG files? I'm using a 328 in my prototype and wanted to make sure it was compatible. Thanks.

User avatar
Panu
VLSI Staff
Posts: 2418
Joined: Tue 2010-06-22 13:43

Re: Example Record Code for Arduino

Post by Panu » Mon 2011-02-28 8:14

Hi!
Are there any microcontroller RAM requirements for recording IMA WAV or OGG files?
My code only uses a 512-byte disk sector buffer plus some global variables, it all fits in less than 1Kbyte of RAM and I haven't had any problems.

Any memory requirement comes from the need to buffer the data when the SD card is busy. The SD spec a couple of years ago allowed the SD card to busy stall for 200 milliseconds. But I've seen SD cards with a little longer delay times also (maybe 400 ms). With uncompressed wav it's an issue, but I haven't had any problems with Vorbis or IMA.

It looks similar to what Seeed implemented on their music shield:
Haha, checked it out, that's my code tweaked to fit the Arduino! Great that it's useful for something! :D

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

admhrv
User
Posts: 11
Joined: Thu 2011-02-17 22:34

Re: Example Record Code for Arduino

Post by admhrv » Mon 2011-02-28 20:00

Looks like the memory issue they mentioned pertains to the flash and not RAM. Loading the "venc44k2q05.plg" onto the 328 flash won't work because it's about 30K, which is the full capacity of the chip. I'm going to try loading this from the SD card instead. The Seeed studio filesystem code seems a little problematic too. Will also work on porting this over to the standard Arduino SDFat library. May be a bit tricky, it's my first time working with lower level coding like this.

For the profiles, is there any reason to choose the "venc44k2q05.plg" over the 01, 02, 03, or 04 variants?

Thanks.

User avatar
Panu
VLSI Staff
Posts: 2418
Joined: Tue 2010-06-22 13:43

Re: Example Record Code for Arduino

Post by Panu » Tue 2011-03-01 15:49

For the profiles, is there any reason to choose the "venc44k2q05.plg" over the 01, 02, 03, or 04 variants?
No, it's just a quality vs file size tradeoff, use what suits you best.

I'm not sure when the data rate gets so big that you need to start worrying about buffering the data because of SD card busy periods... hopefully never with Vorbis.
Will also work on porting this over to the standard Arduino SDFat library. May be a bit tricky, it's my first time working with lower level coding like this.
It's great fun! Just remember to be careful and take it one small step at a time. Verify your progress (using debug strings etc) after each small step. I suggest you make a separate, complete backup copy of your code always when you've added to its functionality, at least once per hour, so you can backtrace your steps.

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

admhrv
User
Posts: 11
Joined: Thu 2011-02-17 22:34

Re: Example Record Code for Arduino

Post by admhrv » Thu 2011-03-03 6:11

Panu, I tried a variation of your code and my VS1053 is not working right now. There is now response from the DREQ pin and I'm unable to run the "sine test" or the "hello" example. The last action was loading the user code. After that the chip is no longer responding to any commands.
I tried hardware reset, waited one second, and tried again. Still, no response. Is there an explanation for why this could have happened? And how can it be resolved?

admhrv
User
Posts: 11
Joined: Thu 2011-02-17 22:34

Re: Example Record Code for Arduino

Post by admhrv » Thu 2011-03-03 6:24

More info on the issue: When I try to read DREQ, it is resetting the microcontroller. ?

User avatar
Panu
VLSI Staff
Posts: 2418
Joined: Tue 2010-06-22 13:43

Re: Example Record Code for Arduino

Post by Panu » Thu 2011-03-03 11:47

Hi!

VS1053 does not have any programmable memory, so any settings you make cannot survive over a power-down power-up cycle. So (unless the chip is damaged) I guess it must be an I/O sensitivity (some signal is just at the edge of its working region).

- Please verify that you have the TEST pin pulled high?
- Check the SPI clock phase and polarity (experiment with different settings)
- Check the chip select signals.

> When I try to read DREQ, it is resetting the microcontroller. ?
Can you please elaborate on that?

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

Post Reply

Who is online

Users browsing this forum: No registered users