Thursday, 25 August 2011

Booting into recording Mode

Loading the VS1053 into encoding mode using the PCM encoder.

Although it is not on the datasheet, I think it would be necessary to set the mode register.

The music shield does a Software Reset with the following values...

Mp3WriteRegister (SPI_MODE, 0x08, 0x04); /* Newmode, Reset, No L1-2 */
delay(1);
while (!MP3_DREQ) /* wait for startup */


0x0804 is 0000 1000 0000 0100 (ie the first 0 is written to register bit 15)
SDI-NEWMODE(11) - ON
Soft Reset(2)


It also writes the clock doubler and misc audio data. I dont think this is necessary though as its not mentioned in the data sheet at all. This makes me think that resetting clears the all the registers except the mode register (reset bit is auto cleared). I need to check that Mode(bit 11) stays set ensure SDI NEW mode is entered. Unreliability of serial prints makes it difficult to check. Probably wouldn't hurt to send 0000 1000 0000 0000 0x0800 to be sure.


/* Set clock register, doubler etc. */
  Mp3WriteRegisterWithDelay(SPI_CLOCKF, 0xB8, 0x00); 
  while (!MP3_DREQ);
  Mp3WriteRegister(SPI_AUDATA, 0xAC,0x45);
  while (!MP3_DREQ);



Steps From the DataSheet

  1. Set the VS1053b clock to the highest value just below 55.3 by writing 0xC000 to register SCI_CLOCKF (3)
    Write1053Sci(SCIR_CLOCKF, 0xC0, 0x00); 

  2. Set SCI_BASS (2) to 0.
       

  3. Reset VS1053b by setting bit SM_RESET (2) to 1 in register SCI_MODE (0). At the same time, clear bit SM_ADPCM (12) to 0. Remember that resetting takes time, so don’t do any firther register writes before the DREQ pin has risen.

    This step seems unneccessary as reseting at this point would remove the previous two steps. In the music shield example (Alsso OGG) this step is removed and is also not mention in the PCM recording instructions.

     Write1053Sci(SCIR_MODE, 0x08, 0x04); // 0000 1000 0000 0000 0100
      while(!digitalRead(MP3_DREQ)) ; 




  4. Disable all interrupts except the SCI interrupts.

    In the music shield example the AIADDR register is also cleared. This is also mentioned in the PCM recording datasheet.


    Mp3WriteRegister(SPI_AIADDR, 0x00,0x00);).
    Mp3WriteRegister(SPI_WRAMADDR, 0xC0,0x1A);
    Mp3WriteRegister(SPI_WRAM, 0x00,0x02); 
  5. Load the plugin profile you intend to run (Chapter 4). Note that you will have to redo this each time you want to activate recording.
    This poses a problem as you cant store a file on the Arduino. For the moment I will be using the .plg low quality voice profile. To save hassle I think i will try copying the vector variable to my sketch and reading it that way, avoiding the need for an SD card. The Ogg vorbis encoder will not fit on the arduino uno however the PCM profile is much smaller.

  6. Set bit SM_ADPCM (12) in register SCI_MODE (0) to 1.
    For Mic input
    Write1053Sci(SCIR_MODE, 0x18, 0x00); //0001 1000 0000 0000 for new mode                                                           For Line:                                                                                                        
    Write1053Sci(SCIR_MODE, 0x58, 0x00); //0101 1000 0000 0000 for new mode


  7. Set recording level control registers SCI_AICTRL1 (13) and SCI_AICTRL2 (14). Typical good values for conservative AGC are 0 and 4096, respectively. 

      /* If 0, use AGC */
      Write1053Sci(SCIR_AICTRL1, 0x00, 0x00);
      /* set to 4096 */
      Write1053Sci(SCIR_AICTRL2, 0x10,0x00); // 0001 0000 0000 0000 = 4096 (decimal)




  8. If you want to use a VU meter, write 0x8000 to SCI_AICTRL0 (12) if using a mono profile or 0x8080 is using a stereo profile.
    No Need:
    Write1053Sci(SCIR_AICTRL0, 0x00, 0x00);


  9. Set a proper value ( 0) to SCI_AICTRL3 (15).
     Write1053Sci(SCIR_AICTRL3, 0x00, 0x00)


  10. If you use a profile that support Vox, set Vox registers. For details, see Chapter 2.5.
    Not gonna look into this yet


  11. Activate the encoder by writing 0x34 to register SCI_AIADDR (10).
    Mp3WriteRegister(SPI_AIADDR, 0x00,0x34);
  12. Wait until DREQ pin is high before reading any data. 

Wednesday, 24 August 2011

VS1053 SPI Specs

Loading the VS1053 and starting the Ogg Vorbis encoder requires communicating with the board via SDI interface.


SDI Connections:


Connected via 4 pins on VS1053

  • MOSI – Master-out, Slave-in. This line carries data from our Arduino to the SPI-controlled device(s);
  • MISO – Master-in, Slave out. This line carries data from the SPI-controlled device(s) back to the Arduino;
  • SS – Slave-select. This line tells the device on the bus we wish to communicate with it. Each SPI device needs a unique SS line back to the Arduino. This line is LOW when communicating over the bus and high when finished.
  • SCK – Serial clock.
VS1053 to Arduino Connections:

  • SS – digital 9 (OUTPUT). You can use other digital pins, but 10 is generally the default as it is next to the other SPI pins. 10 is reserved for the MicroSD library so i will use 9
  • MOSI – digital 11 - doesn't need to be set
  • MISO – digital 12 - doesn't need to be set
  • SCK – digital 13 doesn't need to be set
Also Need
  • (BSYNC if needed... see modes) - any pin (OUTPUT) - using 2
  • DREQ - any pin (INPUT) - using 3
The pins on the Arduino are set. Apparently those digital pins are optimised for SDI and cant be changed.

SPI Arduino Commands
Begin() - wake up the bus
end() - shut down the bus
setBitOrder() - msb Of lsb
setClockDivider()
setDataMode() - using mode0 for this application.
transfer() - transfer the byte, also returns the register value if a read command is used. In this case pass 0xff (all 1's)


SPI VS1053 Commands
Read:

First, XCS line is pulled low to select the device.
Then the READ opcode (0x3) is transmitted via the SI line 
Then followed by an 8-bit word address. After the address has been read in, any further data on SI is ignored by the chip. The 16-bit data corresponding to the received address will be shifted out onto the SO line.
XCS should be driven high after data has been shifted out.
DREQ is driven low for a short while when in a read operation by the chip. This is a very short time and doesn’t require special user attention. 


   unsigned short resultvalue = 0;
    unsigned char h = 0;
    unsigned char l = 0;


Mp3DeselectData(); // BYSNC High
Mp3SelectControl();// CS  low
SPI.transfer(VS_READ_COMMAND); //send read command
SPI.transfer(addressbyte); //send register address
        
    //be careful: when read 0xff,dump it,and read agin
    //while((h = SPIGetChar())== 0xff);
     h = SPIGetChar();
         
    //while((l = VsReadByte())== 0xff);
     l = SPIGetChar();
        
     resultvalue = ((h << 8) | l);


     Mp3DeselectControl(); // CS High
    return resultvalue;



  unsigned char SPIGetChar(){ 
    unsigned char returned = SPI.transfer(0xFF); // transfer dummy data
    return returned; /* Return the received byte */
  
  }


Write:

First, XCS line is pulled low to select the device. 
Then the WRITE opcode (0x2) is transmitted via the SI line 
Then followed by an 8-bit word address.


After the word has been shifted in and the last clock has been sent, XCS should be pulled high to end the WRITE sequence.

After the last bit has been sent, DREQ is driven low for the duration of the register update. Wait for DREQ to go high before performing another write.


  Mp3DeselectData(); // BYSNC High
  Mp3SelectControl();  //CS Low
  //SPIPutCharWithoutWaiting(VS_WRITE_COMMAND); 
  SPI.transfer(VS_WRITE_COMMAND); 
  //delay(1);
  SPI.transfer((addressbyte)); 


  SPI.transfer((highbyte)); 
  SPI.transfer((lowbyte)); 
  SPIWait(); 
  Mp3DeselectControl(); //CS Low


This follows the sequnce from the music shield code. In my interpretation of the datasheet CS should be driven low after the words have been transfered as oppose to after DREQ has returned high (signally update is complete)




The issues i faced is controlling the BYSNC Pin. From what I can tell I am using SDI new mode, in which the BSYNC signal is automatically generated. However, all the code examples write a value to this pin before a read or write command. The Music Shield example pulls the pin high as stated in the datasheet, however other examples pull it low.


VS1053 SDI Modes
Two modes available (native and compatibility mode) controlled by SM_SDINEW(11) in MODE(0) register. The modes vary in the way they achieve bit sync.


In native mode:
SM-SDINEW is set to 1 and bit sync is achieved by internally by XDCS. Page 19 on vs1053 datasheet indicates that this is just using the select pin.




In VS1002 native modes (SM NEWMODE is 1), byte synchronisation is achieved by XDCS. The state of XDCS may not change while a data byte transfer is in progress. To always maintain data synchronisation even if there may be glitches in the boards using VS1053b, it is recommended to turn XDCS every now and then, for instance once after every disk data block, just to make sure the host and VS1053b are in sync.
If SM SDISHARE is 1, the XDCS signal is internally generated by inverting the XCS input. 




In compatibility mode:
the BSYNC pin is used. BYSNC must be high on the first sample and if left high at the end on the first byte (8 bits) transfer, will cause the receiver to stay active and receive the next byte. Only 1 byte can be transfered at a time. This explains why all the register write example code take 2 paramaters. Each register entry must be sent as two 8-bit words.



When VS1053b is running in VS1001 compatibility mode, a BSYNC signal must be generated to ensure correct bit-alignment of the input bitstream. The first DCLK sampling edge (rising or falling, depending on selected polarity), during which the BSYNC is high, marks the first bit of a byte (LSB, if LSB-first order is used, MSB, if MSB-first order is used). If BSYNC is ’1’ when the last bit is received, the receiver stays active and next 8 bits are also received. 


Tuesday, 9 August 2011

Generating Midi Signals

Using the Arduino to send various midi signals to the SV10XX board.

Chanel Setup:
Before sending the channel must be configured. I hage not tried without this code to see if there is a default.

Set Volume:
talkMIDI(0xB0, 0x07, 120);     //0xB0 is channel message, set channel volume to near max (127)

Set Midi Bank:
talkMIDI(0xB0, 0, 0x00);    //Default bank GM1

Set Instrument:
talkMIDI(0xC0, instrument, 0);     //Set instrument number. 0xC0 is a 1 data byte command

It seems that in each of the commands changing the integer after the Upper care letter selects different channels, up to a max a 16.

NoteOn()/NoteOff()
Once this is done the noteOn() or noteOff() methods can be used with the parameters:

 //Note on channel 1 (0x90), some note value (note), middle velocity (0x45):
 noteOn(0, note, 60);

It is worthwhile nothing that some instruments dont require a note off. Drums for instance only last a set duration however wind instruments or synth will play until the noteOff is sent. Multiple noteOn message can be sent at once.

It is possible to change the instrument by sending multiple "Set Instrument" instructions however trying to working out which not to turn off can be difficult. The instrument doesn't not need to be set for the note off, the note value must match up though.

For multiple instruments creating different channels and setting an instrument to each channel seemed to be a better solution.

Using the percussion instruments requires accessing a different midi bank

  talkMIDI(0xB0, 0, 0x78); //Bank select: drums
   talkMIDI(0xC0, 5, 0); //Set instrument number
   noteOn(0, 36, 60); //Play note on channel 1 (0x90), some note value (note), middle velocity (60):

Monday, 8 August 2011

VS10XX Midi Keyboard


Date: 8th August, 2011

Aim: to connect and configure the VS10XX Midi/Mp3 shield to output an analogue audio signal based on input from the ADK keyboard module. basically trying to create a 5 note keyboard.

Equipment:
Arduino Uno
Spark-fun shield
Spark-fun VS10XX
ADKeyboard Module
Spectrum Shield (Optional, saves cutting headphones or a cable)
Board pins
Connecting cables
3.5mm Stereo adaptor

Setup:
Refer to CS10XX Midi Test blog and Note Keyboard Blog as this test basically combines both of those.




Arduino To VS10XX Connections:
Arduino 5V -> VCC
Arduino Ground -> Ground
Arduino D3 ->RX
Arduino d4 -> Reset
Arduino d10 -> I/O 1

VS10XX to Headphone Connections:
VS10XX Left -> headphone adaptor left
VS10XX Right -> headphone adaptor right
VS10XX GBUF -> headphone adaptor ground

Initially I cut the end off a 3.5mm stereo to 3.5mm stereo cable and soldered the wires directly onto some old pins creating a very makeshift way of connect the VS10XX to a stereo input. However I realised this could be achieved using the Spectrum shield. By soldering 3 pins onto the shield's audio input I was able to run the VS20XX audio output through the shields 3.5mm headphone jack. Essentially this saves cutting the end off a cable or set of headphones.

Code:
VS10XX/Midi Example/Midi_Keyboard

I basically combined the code from the ADKeyboard test and midi test. Each button press causes the Arduino to send a serial message to the VS10XX to create a note. This code only looks at the change in state of the button so the action of changing the button from off to on triggers a tone.

Results:
Running the output from the VS10XX input my laptop I was able to hear the sounds I expected. The midi messages sent by the Arduino were being converted into real analogue sounds byt eh VS10XX. I used garage band on my laptop as an amplifier as recorded and monitoring the input level is very simple.

VS10XX Real Time Midi mode

Date: 8th August, 2011

Aim: to connect and configure the VS10XX Midi/Mp3 shield to output an analogue audio signal based on midi messages.

Equipment:
Arduino Uno
Spark-fun shield
Spark-fun VS10XX
Board pins
Connecting cables
3.5mm Stereo adaptor

Setup:

To begin I soldered board pins along all the sockets on the VS10XX. Although I didn't need all the pins it was easier to do them all in one go. However, there are various warnings instructing unused pins should be left unplugged. I have not encountered any problems thus far however touching the board while in use causes static and a crash.



Arduino To VS10XX Connections:
Arduino 5V -> VCC
Arduino Ground -> Ground
Arduino D3 ->RX
Arduino d4 -> Reset
Arduino d10 -> I/O 1

VS10XX to Headphone Connections:
VS10XX Left -> headphone adaptor left
VS10XX Right -> headphone adaptor right
VS10XX GBUF -> headphone adaptor ground

Code:
VS10XX/Midi Example/Midi_Sound_Test

Using the base code from the Spark-Fun midi example the Arduino resets the VS10XX via the D4 pin and sends Midi signals through a soft serial port on the D3 pin. The VS10XX turns this midi commands into an analogue output that can be ran straight into a headphone or amp. This code simply plays through the various instruments.

To make the VS10XX boot in Real Time Midi mode I/O01 is set to High via pin10 out power-up.

Results:
Running the output from the VS10XX input my laptop I was able to hear the sounds I expected. The midi messages sent by the Arduino were being converted into real analogue sounds byt eh VS10XX. I used garage band on my laptop as an amplifier as recorded and monitoring the input level is very simple. From here I will need to remove the test tones and create midi signals based on a sensor input.

Note Keyboard


Date: 5 August 2011

Aim: Using the ADKeyboard to create a basic keyboard that plays a tone over the
buzzer speaker.

Config:
ADK Keyboard to anolgue input 1
LCD to D11
Speaker to D6

Code: ADKeyboard/MusicKeyboard/

Each button causes a different voltage to be returned to analogue input. The current reading is compared to the set voltages and the tone plays while the button is held. The LCD shows, d,r,m,f,s mainly for fun. It worth noting the LCD draws to much power and results in the speaker quality dropping dramatically. The code has pin13 as a status LED if the LCD is to be removed.

Also of note, if the LCD is unplugged the sketch doesn't run. If the LCD is not connect the sLCD object must be commented out of the code. This most likely has something to do with needing to push the LCD's reset button whenever a new sketch is uploaded to the Arduino.