Use the TLV320 with in-built I2S object to stream audio data from an SD Card and send it to the TLV320 CODEC for audio playback

Dependencies:   I2SSlave mbed TLV320

Files at this revision

API Documentation at this revision

Comitter:
d_worrall
Date:
Fri Aug 05 10:07:47 2011 +0000
Child:
1:9ea0cc2fa567
Commit message:
version 2.0

Changed in this revision

FATFileSystem.lib Show annotated file Show diff for this revision Revisions of this file
I2SSlave/I2SSlave.cpp Show annotated file Show diff for this revision Revisions of this file
I2SSlave/I2SSlave.h Show annotated file Show diff for this revision Revisions of this file
SDHCFileSystem/SDHCFileSystem.cpp Show annotated file Show diff for this revision Revisions of this file
SDHCFileSystem/SDHCFileSystem.h Show annotated file Show diff for this revision Revisions of this file
TLV320/TLV320.cpp Show annotated file Show diff for this revision Revisions of this file
TLV320/TLV320.h Show annotated file Show diff for this revision Revisions of this file
main.cpp Show annotated file Show diff for this revision Revisions of this file
mbed.bld Show annotated file Show diff for this revision Revisions of this file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/FATFileSystem.lib	Fri Aug 05 10:07:47 2011 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/mbed_unsupported/code/fatfilesystem/
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/I2SSlave/I2SSlave.cpp	Fri Aug 05 10:07:47 2011 +0000
@@ -0,0 +1,306 @@
+/******************************************************
+ * I2SSlave.cpp: I2S port abstraction library cpp file for NXP LPC1768
+ *
+ * Written by:
+ * mbed Team     -   15th July 2011
+ * Daniel Worrall
+ *
+ * History
+ * version 1.31
+******************************************************/
+#include "I2SSlave.h"
+/*Global Functions*/
+FunctionPointer akjnh3489v8ncv;
+
+extern "C" void I2S_IRQHandler(void){                   //this is a very special function so can remain outside
+    akjnh3489v8ncv.call();
+}
+/******************************************************
+ * Function name:   I2SSlave
+ *
+ * Description:     class constructor
+ *
+ * Parameters:      PinName tx_sda, PinName tx_ws, PinName clk, PinName rx_sda, PinName rx_ws
+ * Returns:         none
+******************************************************/
+//Constructor
+I2SSlave::I2SSlave(PinName tx_sda, PinName tx_ws, PinName clk, PinName rx_sda, PinName rx_ws){
+    storePins_(tx_sda, tx_ws, clk, rx_sda, rx_ws);
+    format(16, STEREO);                                 //this also invokes initialize so no need to call it twice
+}
+//Public functions
+/******************************************************
+ * Function name:   format()
+ *
+ * Description:     sets the bit length for writing and stereo or mono mode
+ *
+ * Parameters:      int bit, bool mode
+ * Returns:         none
+******************************************************/
+void I2SSlave::format(int bit, bool mode){
+    bit_ = bit;
+    mode_ = mode;
+    initialize_(tx_sda_, tx_ws_, clk_, rx_sda_, rx_ws_);
+}
+/******************************************************
+ * Function name:   write()
+ *
+ * Description:     load buffer to write to I2S port
+ *
+ * Parameters:      long *buffer
+ * Returns:         none
+******************************************************/
+void I2SSlave::write(int* buffer, int from, int length){
+    int to = from + length;
+    for(int i = from; i < to; ++i){
+        LPC_I2S->I2STXFIFO = buffer[i];
+    }
+}
+/******************************************************
+ * Function name:   start()
+ *
+ * Description:     attach streamOut_ function to ticker interrupt
+ *
+ * Parameters:      none
+ * Returns:         none
+******************************************************/
+void I2SSlave::start(int mode){
+    switch(mode){
+        case(0):
+             LPC_I2S->I2SIRQ |= (0 << 0);           //disable receive interrupt
+             LPC_I2S->I2SIRQ |= (0 << 1);           //disable transmit interrupt
+             break;
+        case(1):
+            LPC_I2S->I2SIRQ |= (0 << 0);            //disable receive interrupt
+            LPC_I2S->I2SIRQ |= (1 << 1);            //enable transmit interrupt
+            LPC_I2S->I2SIRQ |= (0 << 16);           //set I2STXFIFO depth to 0 words
+            break;
+        case(2):
+            LPC_I2S->I2SIRQ |= (1 << 0);            //enable receive interrupt
+            LPC_I2S->I2SIRQ |= (0 << 1);            //disable transmit interrupt
+            LPC_I2S->I2SIRQ |= (4 << 8);            //set I2SRXFIFO depth to 4 words
+            break;
+        case(3):
+            LPC_I2S->I2SIRQ |= (1 << 0);            //enable receive interrupt
+            LPC_I2S->I2SIRQ |= (4 << 8);            //set I2SRXFIFO depth to 4 words
+            LPC_I2S->I2SIRQ |= (1 << 1);            //enable transmit interrupt
+            LPC_I2S->I2SIRQ |= (0 << 16);           //set I2STXFIFO depth to 0 words
+            break;
+        default:
+            break;
+    }
+    NVIC_SetPriority(I2S_IRQn, 0);
+    NVIC_EnableIRQ(I2S_IRQn);                       //enable I2S interrupt in the NVIC 
+}
+/******************************************************
+ * Function name:   stop()
+ *
+ * Description:     detach streamOut_ from ticker
+ *
+ * Parameters:      none
+ * Returns:         none
+******************************************************/
+void I2SSlave::stop(void){
+    NVIC_DisableIRQ(I2S_IRQn);           
+}
+/******************************************************
+ * Function name:   read()
+ *
+ * Description:     reads FIFORX buffer into [int32_t rxBuffer[8]]
+ *
+ * Parameters:      none
+ * Returns:         none
+******************************************************/
+void I2SSlave::read(void){
+    rxBuffer[0] = LPC_I2S->I2SRXFIFO;
+    rxBuffer[1] = LPC_I2S->I2SRXFIFO;
+    rxBuffer[2] = LPC_I2S->I2SRXFIFO;
+    rxBuffer[3] = LPC_I2S->I2SRXFIFO;
+}
+/******************************************************
+ * Function name:   status_()
+ *
+ * Description:     Read I2SSTATE register
+ *
+ * Parameters:      none
+ * Returns:         int
+******************************************************/
+int I2SSlave::status(void){
+    return LPC_I2S->I2SSTATE;
+}
+//Private functions
+/******************************************************
+ * Function name:   initialize()
+ *
+ * Description:     initialises I2S port 
+ *
+ * Parameters:      PinName tx_sda, PinName tx_ws, PinName clk, PinName rx_sda, PinName rx_ws
+ * Returns:         0 =  successful initialisation
+                   -1 = initialisation failure
+******************************************************/
+int I2SSlave::initialize_(PinName tx_sda, PinName tx_ws, PinName clk, PinName rx_sda, PinName rx_ws){
+    setPins_(tx_sda, tx_ws, clk, rx_sda, rx_ws);        //designate pins
+    LPC_SC->PCONP |= (1 << 27);
+    //configure input/output register
+    format_(bit_, mode_);           
+    //set mbed as SLAVE  
+    LPC_I2S->I2SDAO |= (1 << 5);
+    LPC_I2S->I2SDAI |= (1 << 5);
+    //clock mode
+    setClocks_(4);
+    //set slave mode
+    modeConfig_();
+    //set receiver mode
+    LPC_I2S->I2SRXMODE |= (1 << 1);
+    //slave mode
+    LPC_I2S->I2STXRATE = 0;
+    LPC_I2S->I2SRXRATE = 0;
+    //Start
+    LPC_I2S->I2SDAO |= (0 << 3);          
+    LPC_I2S->I2SDAI |= (0 << 3);
+    LPC_I2S->I2SDAO |= (0 << 4);          
+    LPC_I2S->I2SDAI |= (0 << 4);
+    LPC_I2S->I2SDAO |= (0 << 15);          
+    return 0;
+}
+/******************************************************
+ * Function name:   setClocks_()
+ *
+ * Description:     Set the division setting on the internal clocks
+ *
+ * Parameters:      int divideBy
+ * Returns:         nothing
+******************************************************/
+void I2SSlave::setClocks_(int divideBy){
+    switch(divideBy){
+        case 1:
+            LPC_SC->PCLKSEL1 |= (1 << 22); 
+            LPC_SC->PCLKSEL1 |= (0 << 23);     
+            break;
+        case 2:
+            LPC_SC->PCLKSEL1 |= (0 << 22);
+            LPC_SC->PCLKSEL1 |= (1 << 23);
+            break;
+        case 4:
+            LPC_SC->PCLKSEL1 |= (0 << 22);
+            LPC_SC->PCLKSEL1 |= (0 << 23);
+            break;
+        case 8:
+            LPC_SC->PCLKSEL1 |= (1 << 22);
+            LPC_SC->PCLKSEL1 |= (1 << 23);
+            break;
+        default:
+            break;
+    }
+}
+/******************************************************
+ * Function name:   setPins_()
+ *
+ * Description:     set external pin configuration
+ *
+ * Parameters:      PinName tx_sda, PinName tx_ws, PinName clk, PinName rx_sda, PinName rx_ws
+ * Returns:         none
+******************************************************/
+void I2SSlave::setPins_(PinName tx_sda, PinName tx_ws, PinName clk, PinName rx_sda, PinName rx_ws){
+    if(rx_ws == p29){
+        LPC_PINCON->PINSEL0 |= (1 << 10);   //set p29 as receive word select line
+    } else {
+        LPC_PINCON->PINSEL1 |= (2 << 16);   //set p16 as receive word select line
+    }
+    if(rx_sda == p8){
+        LPC_PINCON->PINSEL0 |= (1 << 12);   //set p8 as receive serial data line
+    } else {
+        LPC_PINCON->PINSEL1 |= (2 << 18);   //set p17 as receive serial data line
+    }
+    LPC_PINCON->PINSEL0 |= (1 << 14);       //set p7 as transmit clock line (only one of these)    
+    LPC_PINCON->PINSEL0 |= (1 << 16);       //set p6 as word select line (only one of these)   
+    LPC_PINCON->PINSEL0 |= (1 << 18);       //set p5 as transmit serial data line (only one of these)
+    LPC_PINCON->PINSEL0 |= (0 << 8);        //clear rx_clk
+}
+/******************************************************
+ * Function name:   format_()
+ *
+ * Description:     sets the bit length for writing and stereo or mono mode
+ *
+ * Parameters:      int bit, bool mode
+ * Returns:         none
+******************************************************/
+void I2SSlave::format_(int bit, bool mode){
+    uint32_t bps= ((bit+1)*8)-1;
+    LPC_I2S->I2SDAO &= (0x00 << 6);
+    LPC_I2S->I2SDAO |= (bps << 6);
+    //set bit length
+    switch(bit){
+        case 8:
+            LPC_I2S->I2SDAO &= 0xfffffffc;
+            break;
+        case 16:
+            LPC_I2S->I2SDAO &= (0 << 1);
+            LPC_I2S->I2SDAO |= (1 << 0);           
+            break;
+        case 32:
+            LPC_I2S->I2SDAO &= (0 << 1);
+            LPC_I2S->I2SDAO |= (3 << 0);
+            break;
+        default:
+            break;
+    }
+    //set audio mode
+    if(mode == STEREO){
+        LPC_I2S->I2SDAO |= (0 << 2);
+    } else {
+        LPC_I2S->I2SDAO |= (1 << 2);
+    }
+    //set transmitter and receiver setting to be the same
+    LPC_I2S->I2SDAI &= (0x00 << 6);
+    LPC_I2S->I2SDAI |= (bps << 6);
+    //set bit length
+    switch(bit){
+        case 8:
+            LPC_I2S->I2SDAI &= 0xfffffffc;
+            break;
+        case 16:
+            LPC_I2S->I2SDAI &= (0 << 1);
+            LPC_I2S->I2SDAI |= (1 << 0);
+            break;
+        case 32:
+            LPC_I2S->I2SDAI &= (0 << 1);
+            LPC_I2S->I2SDAI |= (3 << 0);
+            break;
+        default:
+            break;
+    }
+    //set audio mode
+    if(mode == STEREO){
+        LPC_I2S->I2SDAI |= (0 << 2);
+    } else {
+        LPC_I2S->I2SDAI |= (1 << 2);
+    }
+}
+/******************************************************
+ * Function name:   modeConfig_()
+ *
+ * Description:     Set slave mode
+ *
+ * Parameters:      none
+ * Returns:         none
+******************************************************/
+void I2SSlave::modeConfig_(void){
+    LPC_I2S->I2STXMODE |= (0x0 << 0);
+    LPC_I2S->I2SRXMODE |= (0x0 << 0);
+}
+/******************************************************
+ * Function name:   storePins_()
+ *
+ * Description:     set external pin configuration
+ *
+ * Parameters:      PinName tx_sda, PinName tx_ws, PinName clk, PinName rx_sda, PinName rx_ws
+ * Returns:         none
+******************************************************/
+void I2SSlave::storePins_(PinName tx_sda, PinName tx_ws, PinName clk, PinName rx_sda, PinName rx_ws){
+    tx_sda_ = tx_sda;
+    tx_ws_ = tx_ws;
+    clk_ = clk;
+    rx_sda_ = rx_sda;
+    rx_ws_ = rx_ws;
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/I2SSlave/I2SSlave.h	Fri Aug 05 10:07:47 2011 +0000
@@ -0,0 +1,170 @@
+/******************************************************
+ * I2SSlave.h: I2S port abstraction library header file for NXP LPC1768
+ *
+ * Written by:
+ * mbed Team     -   15th July 2011
+ * Daniel Worrall
+ *
+ * History
+ * version 1.31
+******************************************************/
+
+#include "mbed.h"
+#include "math.h"
+
+#ifndef __MBED_I2SSLAVE_H__
+#define __MBED_I2SSLAVE_H__
+
+/** I2S class defined on the LPC1768 port
+ *
+ */
+extern FunctionPointer akjnh3489v8ncv;
+class I2SSlave{
+
+    public:
+        //Constructor
+        /** Create an I2S object
+         *
+         * @param tx_sda Transmitter serial data line
+         * @param tx_ws Transmitter word select line
+         * @param clk Shared transmitter/receiver clock line
+         * @param rx_sda Receiver serial data line
+         * @param rx_ws Receiver word select line
+         */
+        I2SSlave(PinName tx_sda, PinName tx_ws, PinName clk, PinName rx_sda, PinName rx_ws);
+        /** Set the data transmission format
+         *
+         * @param bit Set the number of bits per write
+         * @param mode Set STEREO (0) or MONO (1) mode
+         */
+        void format(int bit, bool mode);
+        /** Write a buffer to the I2S port
+         *
+         * @param buffer Address of buffer to pass to I2S port
+         * @param from Start position in buffer to read from
+         * @param length Length of buffer (MUST not exceed 8 words, each 32 bits long)
+         *
+         * Note: sending 8 words to the TXFIFO will trigger an interrupt!
+         */
+        void write(int* buffer, int from,  int length);
+        /** Activate I2S port for data streaming 
+         *
+         * @param mode Mode to enable - NONE, TRANSMIT only, RECEIVE only, BOTH
+         * Enables tx/rx interrupts
+         */
+        void start(int mode);
+        /** Deactivate I2S port from data streaming 
+         *
+         * Disable all interrupts
+         */
+        void stop(void);
+        /** Load receive FIFO data into receiver buffer
+         *
+         */
+        void read(void);
+        /** Attach a void/void function or void/void static memeber function to an interrupt generated by the I2SxxFIFOs
+         *
+         * @param function Function to attach
+         *
+         * e.g. myI2sObject.attach(&myfunction);
+         * OR   myI2sObject.attach(&myClass::myStaticMemberFunction);
+         */
+        void attach(void(*fptr)(void)){
+            akjnh3489v8ncv.attach(fptr);
+        }
+        /** Attach a nonstatic void/void member function to an interrupt generated by the I2SxxFIFOs
+         *
+         * @param tptr Object pointer
+         * @param mptr Member function pointer
+         *
+         * e.g. myI2sObject.attach(&myObject, &myClass::myNonstaticMemberFunction); where myObject is an object of myClass
+         */
+        template<typename T>
+        void attach(T *tptr, void(T::*mptr)(void)){
+            akjnh3489v8ncv.attach(tptr, mptr);
+        }
+        /** Return contents of I2S status register
+         *
+         * @returns Content of I2SSTATE register
+         *
+         * bit0: receive/transmit interrupt active
+         * bit1: receive/transmit DMA request 1
+         * bit2: receive/transmit DMA request 2
+         * bit[11:8]: receive FIFO level
+         * bit[19:16]: transmit FIFO level
+         */
+        int status(void);
+        
+        //Receiver buffer
+        int rxBuffer[4];
+        //defines
+        #define STEREO  0
+        #define MONO    1
+        
+        #define I2SFIFO_EMPTY    0
+        #define I2SFIFO_FULL     8
+        
+        #define RAM_LENGTH  1024
+        #define RAM_LIMIT   (RAM_LENGTH - 1) 
+        #define PTR_MAX     ((RAM_LENGTH / 8) - 1)
+        
+        #define NONE        0
+        #define TRANSMIT    1
+        #define RECEIVE     2
+        #define BOTH        3
+
+    private:        
+        /** I2S intitalize function
+         *
+         * @param tx_sda Transmitter serial data line
+         * @param tx_ws Transmitter word select line
+         * @param clk Shared transmitter/receiver clock line
+         * @param rx_sda Receiver serial data line
+         * @param rx_ws Receiver word select line
+         * @return Returns 0 for successful initialisation, -1 for an error
+         */
+        int initialize_(PinName tx_sda, PinName tx_ws, PinName clk, PinName rx_sda, PinName rx_ws);
+        /** Set internal clock divide by rate
+         *
+         * @param divideBy Divide by 1, 2, 4 or 8
+         */
+        void setClocks_(int divideBy);
+        /** Set up the pins on the processor itself
+         *
+         * @param tx_sda Transmitter serial data line
+         * @param tx_ws Transmitter word select line
+         * @param clk Shared transmitter/receiver clock line
+         * @param rx_sda Receiver serial data line
+         * @param rx_ws Receiver word select line
+         */
+        void setPins_(PinName tx_sda, PinName tx_ws, PinName clk, PinName rx_sda, PinName rx_ws);
+        /** Set the data transmission format 
+         *
+         * @param bit Set the number of bits per write
+         * @param mode Set STEREO (0) or MONO (1) mode
+         */
+        void format_(int bit, bool mode);
+        /** Set slave mode
+         *
+         */
+        void modeConfig_(void);
+        /** Store PinName values
+         * 
+         * @param tx_sda Transmitter serial data line
+         * @param tx_ws Transmitter word select line
+         * @param clk Shared transmitter/receiver clock line
+         * @param rx_sda Receiver serial data line
+         * @param rx_ws Receiver word select line
+         */
+        void storePins_(PinName tx_sda, PinName tx_ws, PinName clk, PinName rx_sda, PinName rx_ws);
+        //variables
+        int bit_;
+        bool mode_;
+        PinName tx_sda_; 
+        PinName tx_ws_; 
+        PinName clk_;
+        PinName rx_sda_;
+        PinName rx_ws_;
+};
+
+#endif /*__MBED_I2S_H__*/
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/SDHCFileSystem/SDHCFileSystem.cpp	Fri Aug 05 10:07:47 2011 +0000
@@ -0,0 +1,495 @@
+/* mbed SDFileSystem Library, for providing file access to SD cards
+ * Copyright (c) 2008-2010, sford
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+/* Introduction
+ * ------------
+ * SD and MMC cards support a number of interfaces, but common to them all
+ * is one based on SPI. This is the one I'm implmenting because it means
+ * it is much more portable even though not so performant, and we already 
+ * have the mbed SPI Interface!
+ *
+ * The main reference I'm using is Chapter 7, "SPI Mode" of: 
+ *  http://www.sdcard.org/developers/tech/sdcard/pls/Simplified_Physical_Layer_Spec.pdf
+ *
+ * SPI Startup
+ * -----------
+ * The SD card powers up in SD mode. The SPI interface mode is selected by
+ * asserting CS low and sending the reset command (CMD0). The card will 
+ * respond with a (R1) response.
+ *
+ * CMD8 is optionally sent to determine the voltage range supported, and 
+ * indirectly determine whether it is a version 1.x SD/non-SD card or 
+ * version 2.x. I'll just ignore this for now.
+ *
+ * ACMD41 is repeatedly issued to initialise the card, until "in idle"
+ * (bit 0) of the R1 response goes to '0', indicating it is initialised.
+ *
+ * You should also indicate whether the host supports High Capicity cards,
+ * and check whether the card is high capacity - i'll also ignore this
+ *
+ * SPI Protocol
+ * ------------
+ * The SD SPI protocol is based on transactions made up of 8-bit words, with
+ * the host starting every bus transaction by asserting the CS signal low. The
+ * card always responds to commands, data blocks and errors.
+ * 
+ * The protocol supports a CRC, but by default it is off (except for the 
+ * first reset CMD0, where the CRC can just be pre-calculated, and CMD8)
+ * I'll leave the CRC off I think! 
+ * 
+ * Standard capacity cards have variable data block sizes, whereas High 
+ * Capacity cards fix the size of data block to 512 bytes. I'll therefore
+ * just always use the Standard Capacity cards with a block size of 512 bytes.
+ * This is set with CMD16.
+ *
+ * You can read and write single blocks (CMD17, CMD25) or multiple blocks 
+ * (CMD18, CMD25). For simplicity, I'll just use single block accesses. When
+ * the card gets a read command, it responds with a response token, and then 
+ * a data token or an error.
+ * 
+ * SPI Command Format
+ * ------------------
+ * Commands are 6-bytes long, containing the command, 32-bit argument, and CRC.
+ *
+ * +---------------+------------+------------+-----------+----------+--------------+
+ * | 01 | cmd[5:0] | arg[31:24] | arg[23:16] | arg[15:8] | arg[7:0] | crc[6:0] | 1 |
+ * +---------------+------------+------------+-----------+----------+--------------+
+ *
+ * As I'm not using CRC, I can fix that byte to what is needed for CMD0 (0x95)
+ *
+ * All Application Specific commands shall be preceded with APP_CMD (CMD55).
+ *
+ * SPI Response Format
+ * -------------------
+ * The main response format (R1) is a status byte (normally zero). Key flags:
+ *  idle - 1 if the card is in an idle state/initialising 
+ *  cmd  - 1 if an illegal command code was detected
+ *
+ *    +-------------------------------------------------+
+ * R1 | 0 | arg | addr | seq | crc | cmd | erase | idle |
+ *    +-------------------------------------------------+
+ *
+ * R1b is the same, except it is followed by a busy signal (zeros) until
+ * the first non-zero byte when it is ready again.
+ *
+ * Data Response Token
+ * -------------------
+ * Every data block written to the card is acknowledged by a byte 
+ * response token
+ *
+ * +----------------------+
+ * | xxx | 0 | status | 1 |
+ * +----------------------+
+ *              010 - OK!
+ *              101 - CRC Error
+ *              110 - Write Error
+ *
+ * Single Block Read and Write
+ * ---------------------------
+ *
+ * Block transfers have a byte header, followed by the data, followed
+ * by a 16-bit CRC. In our case, the data will always be 512 bytes.
+ *  
+ * +------+---------+---------+- -  - -+---------+-----------+----------+
+ * | 0xFE | data[0] | data[1] |        | data[n] | crc[15:8] | crc[7:0] | 
+ * +------+---------+---------+- -  - -+---------+-----------+----------+
+ */
+ 
+ /*
+ * Comment: Changes for SDHC support till 32GB 
+ * Name:    KB
+ * Date:    07/24/2010
+ * Release: 0.1
+ */
+ 
+#include "SDHCFileSystem.h"
+
+#define DEBUG
+#define SD_COMMAND_TIMEOUT 5000
+
+
+SDFileSystem::SDFileSystem(PinName mosi, PinName miso, PinName sclk, PinName cs, const char* name) :
+  FATFileSystem(name), _spi(mosi, miso, sclk), _cs(cs) {
+      _cs = 1; 
+}
+
+#define R1_IDLE_STATE           (1 << 0)
+#define R1_ERASE_RESET          (1 << 1)
+#define R1_ILLEGAL_COMMAND      (1 << 2)
+#define R1_COM_CRC_ERROR        (1 << 3)
+#define R1_ERASE_SEQUENCE_ERROR (1 << 4)
+#define R1_ADDRESS_ERROR        (1 << 5)
+#define R1_PARAMETER_ERROR      (1 << 6)
+
+// Types
+//  - v1.x Standard Capacity
+//  - v2.x Standard Capacity
+//  - v2.x High Capacity
+//  - Not recognised as an SD Card
+
+#define SDCARD_FAIL 0
+#define SDCARD_V1   1
+#define SDCARD_V2   2
+#define SDCARD_V2HC 3
+
+int SDFileSystem::initialise_card() {
+    // Set to 100kHz for initialisation, and clock card with cs = 1
+    _spi.frequency(100000); 
+    _cs = 1;
+    for(int i=0; i<16; i++) {   
+        _spi.write(0xFF);
+    }
+
+    // send CMD0, should return with all zeros except IDLE STATE set (bit 0)
+    if(_cmd(0, 0) != R1_IDLE_STATE) { 
+        fprintf(stderr, "No disk, or could not put SD card in to SPI idle state\n");
+        return SDCARD_FAIL;
+    }
+
+    // send CMD8 to determine whther it is ver 2.x
+    int r = _cmd8();
+    if(r == R1_IDLE_STATE) {
+        return initialise_card_v2();
+    } else if(r == (R1_IDLE_STATE | R1_ILLEGAL_COMMAND)) {
+        return initialise_card_v1();
+    } else {
+        fprintf(stderr, "Not in idle state after sending CMD8 (not an SD card?)\n");
+        return SDCARD_FAIL;
+    }
+}
+
+int SDFileSystem::initialise_card_v1() {
+    for(int i=0; i<SD_COMMAND_TIMEOUT; i++) {
+        _cmd(55, 0); 
+        if(_cmd(41, 0) == 0) { 
+            cdv = 512;
+            #ifdef DEBUG 
+            printf("\n\rInit: SEDCARD_V1\n\r");
+            #endif
+            return SDCARD_V1;
+        }
+    }
+
+    fprintf(stderr, "Timeout waiting for v1.x card\n");
+    return SDCARD_FAIL;
+}
+
+int SDFileSystem::initialise_card_v2() {
+    
+    for(int i=0; i<SD_COMMAND_TIMEOUT; i++) {
+        wait_ms(50);
+        _cmd58();
+        _cmd(55, 0); 
+        if(_cmd(41, 0x40000000) == 0) { 
+            _cmd58();
+            #ifdef DEBUG
+            printf("\n\rInit: SDCARD_V2\n\r");
+            #endif
+            cdv = 1;
+            return SDCARD_V2;
+        }
+    }
+
+    fprintf(stderr, "Timeout waiting for v2.x card\n");
+    return SDCARD_FAIL;
+}
+
+int SDFileSystem::disk_initialize() {
+
+    int i = initialise_card();
+    #ifdef DEBUG 
+    printf("init card = %d\n", i);
+    #endif
+    _sectors = _sd_sectors();
+
+    // Set block length to 512 (CMD16)
+    if(_cmd(16, 512) != 0) {
+        fprintf(stderr, "Set 512-byte block timed out\n");
+        return 1;
+    }
+        
+    _spi.frequency(20000000); // Set to 1MHz for data transfer
+    return 0;
+}
+
+int SDFileSystem::disk_write(const char *buffer, int block_number) {
+    // set write address for single block (CMD24)
+    if(_cmd(24, block_number * cdv) != 0) {
+        return 1;
+    }
+
+    // send the data block
+    _write(buffer, 512);    
+    return 0;    
+}
+
+int SDFileSystem::disk_read(char *buffer, int block_number) {        
+    // set read address for single block (CMD17)
+    if(_cmd(17, block_number * cdv) != 0) {
+        return 1;
+    }
+    
+    // receive the data
+    _read(buffer, 512);
+    return 0;
+}
+
+int SDFileSystem::disk_status() { return 0; }
+int SDFileSystem::disk_sync() { return 0; }
+int SDFileSystem::disk_sectors() { return _sectors; }
+
+// PRIVATE FUNCTIONS
+
+int SDFileSystem::_cmd(int cmd, int arg) {
+    _cs = 0; 
+
+    // send a command
+    _spi.write(0x40 | cmd);
+    _spi.write(arg >> 24);
+    _spi.write(arg >> 16);
+    _spi.write(arg >> 8);
+    _spi.write(arg >> 0);
+    _spi.write(0x95);
+
+    // wait for the repsonse (response[7] == 0)
+    for(int i=0; i<SD_COMMAND_TIMEOUT; i++) {
+        int response = _spi.write(0xFF);
+        if(!(response & 0x80)) {
+            _cs = 1;
+            _spi.write(0xFF);
+            return response;
+        }
+    }
+    _cs = 1;
+    _spi.write(0xFF);
+    return -1; // timeout
+}
+int SDFileSystem::_cmdx(int cmd, int arg) {
+    _cs = 0; 
+
+    // send a command
+    _spi.write(0x40 | cmd);
+    _spi.write(arg >> 24);
+    _spi.write(arg >> 16);
+    _spi.write(arg >> 8);
+    _spi.write(arg >> 0);
+    _spi.write(0x95);
+
+    // wait for the repsonse (response[7] == 0)
+    for(int i=0; i<SD_COMMAND_TIMEOUT; i++) {
+        int response = _spi.write(0xFF);
+        if(!(response & 0x80)) {
+            return response;
+        }
+    }
+    _cs = 1;
+    _spi.write(0xFF);
+    return -1; // timeout
+}
+
+
+int SDFileSystem::_cmd58() {
+    _cs = 0; 
+    int arg = 0;
+    
+    // send a command
+    _spi.write(0x40 | 58);
+    _spi.write(arg >> 24);
+    _spi.write(arg >> 16);
+    _spi.write(arg >> 8);
+    _spi.write(arg >> 0);
+    _spi.write(0x95);
+
+    // wait for the repsonse (response[7] == 0)
+    for(int i=0; i<SD_COMMAND_TIMEOUT; i++) {
+        int response = _spi.write(0xFF);
+        if(!(response & 0x80)) {
+            int ocr = _spi.write(0xFF) << 24;
+            ocr |= _spi.write(0xFF) << 16;
+            ocr |= _spi.write(0xFF) << 8;
+            ocr |= _spi.write(0xFF) << 0;
+//            printf("OCR = 0x%08X\n", ocr);
+            _cs = 1;
+            _spi.write(0xFF);
+            return response;
+        }
+    }
+    _cs = 1;
+    _spi.write(0xFF);
+    return -1; // timeout
+}
+
+int SDFileSystem::_cmd8() {
+    _cs = 0; 
+    
+    // send a command
+    _spi.write(0x40 | 8); // CMD8
+    _spi.write(0x00);     // reserved
+    _spi.write(0x00);     // reserved
+    _spi.write(0x01);     // 3.3v
+    _spi.write(0xAA);     // check pattern
+    _spi.write(0x87);     // crc
+
+    // wait for the repsonse (response[7] == 0)
+    for(int i=0; i<SD_COMMAND_TIMEOUT * 1000; i++) {
+        char response[5];
+        response[0] = _spi.write(0xFF);
+        if(!(response[0] & 0x80)) {
+                for(int j=1; j<5; j++) {
+                    response[i] = _spi.write(0xFF);
+                }
+                _cs = 1;
+                _spi.write(0xFF);
+                return response[0];
+        }
+    }
+    _cs = 1;
+    _spi.write(0xFF);
+    return -1; // timeout
+}
+
+int SDFileSystem::_read(char *buffer, int length) {
+    _cs = 0;
+
+    // read until start byte (0xFF)
+    while(_spi.write(0xFF) != 0xFE);
+
+    // read data
+    for(int i=0; i<length; i++) {
+        buffer[i] = _spi.write(0xFF);
+    }
+    _spi.write(0xFF); // checksum
+    _spi.write(0xFF);
+
+    _cs = 1;    
+    _spi.write(0xFF);
+    return 0;
+}
+
+int SDFileSystem::_write(const char *buffer, int length) {
+    _cs = 0;
+    
+    // indicate start of block
+    _spi.write(0xFE);
+    
+    // write the data
+    for(int i=0; i<length; i++) {
+        _spi.write(buffer[i]);
+    }
+    
+    // write the checksum
+    _spi.write(0xFF); 
+    _spi.write(0xFF);
+
+    // check the repsonse token
+    if((_spi.write(0xFF) & 0x1F) != 0x05) {
+        _cs = 1;
+        _spi.write(0xFF);        
+        return 1;
+    }
+
+    // wait for write to finish
+    while(_spi.write(0xFF) == 0);
+
+    _cs = 1; 
+    _spi.write(0xFF);
+    return 0;
+}
+
+static int ext_bits(char *data, int msb, int lsb) {
+    int bits = 0;
+    int size = 1 + msb - lsb; 
+    for(int i=0; i<size; i++) {
+        int position = lsb + i;
+        int byte = 15 - (position >> 3);
+        int bit = position & 0x7;
+        int value = (data[byte] >> bit) & 1;
+        bits |= value << i;
+    }
+    return bits;
+}
+
+int SDFileSystem::_sd_sectors() {
+
+    int c_size, c_size_mult, read_bl_len;
+    int block_len, mult, blocknr, capacity;       
+    int blocks, hc_c_size;
+    uint64_t hc_capacity;
+     
+    // CMD9, Response R2 (R1 byte + 16-byte block read)
+    if(_cmdx(9, 0) != 0) {
+        fprintf(stderr, "Didn't get a response from the disk\n");
+        return 0;
+    }
+    
+    char csd[16];    
+    if(_read(csd, 16) != 0) {
+        fprintf(stderr, "Couldn't read csd response from disk\n");
+        return 0;
+    }
+
+    // csd_structure : csd[127:126]
+    // c_size        : csd[73:62]
+    // c_size_mult   : csd[49:47]
+    // read_bl_len   : csd[83:80] - the *maximum* read block length
+   
+    int csd_structure = ext_bits(csd, 127, 126);
+    
+    #ifdef DEBUG 
+    printf("\n\rCSD_STRUCT = %d\n", csd_structure);
+    #endif
+     
+    switch (csd_structure){
+     case 0:
+      cdv = 512;
+      c_size = ext_bits(csd, 73, 62);
+      c_size_mult = ext_bits(csd, 49, 47);
+      read_bl_len = ext_bits(csd, 83, 80);
+     
+      block_len = 1 << read_bl_len;
+      mult = 1 << (c_size_mult + 2);
+      blocknr = (c_size + 1) * mult;
+      capacity = blocknr * block_len;
+      blocks = capacity / 512;
+      #ifdef DEBUG 
+      printf("\n\rSDCard\n\rc_size: %.4X \n\rcapacity: %.ld \n\rsectors: %d\r\n", c_size, capacity, blocks);
+      #endif
+      break;
+    
+     case 1:
+      cdv = 1;
+      hc_c_size = ext_bits(csd, 63, 48);
+      int hc_read_bl_len = ext_bits(csd, 83, 80);
+      hc_capacity = hc_c_size+1;   
+      blocks = (hc_c_size+1)*1024;
+      #ifdef DEBUG 
+      printf("\n\rSDHC Card \n\rhc_c_size: %.4X \n\rcapacity: %.lld \n\rsectors: %d\r\n", hc_c_size, hc_capacity*512*1024, blocks);
+      #endif
+      break;
+   
+    default:    
+       fprintf(stderr, "This disk tastes funny! I only know about type 0 CSD structures\n");
+     return 0;
+     //break;
+    };
+ return blocks;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/SDHCFileSystem/SDHCFileSystem.h	Fri Aug 05 10:07:47 2011 +0000
@@ -0,0 +1,86 @@
+/* mbed SDFileSystem Library, for providing file access to SD cards
+ * Copyright (c) 2008-2010, sford
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef MBED_SDHCFILESYSTEM_H
+#define MBED_SDHCFILESYSTEM_H
+
+#include "mbed.h"
+#include "FATFileSystem.h"
+
+/* Double Words */
+typedef unsigned long long uint64_t;
+typedef long long sint64_t;
+
+/** Access the filesystem on an SD Card using SPI
+ *
+ * @code
+ * #include "mbed.h"
+ * #include "SDFileSystem.h"
+ *
+ * SDFileSystem sd(p5, p6, p7, p12, "sd"); // mosi, miso, sclk, cs
+ *  
+ * int main() {
+ *     FILE *fp = fopen("/sd/myfile.txt", "w");
+ *     fprintf(fp, "Hello World!\n");
+ *     fclose(fp);
+ * }
+ */
+class SDFileSystem : public FATFileSystem {
+public:
+
+    /** Create the File System for accessing an SD Card using SPI
+     *
+     * @param mosi SPI mosi pin connected to SD Card
+     * @param miso SPI miso pin conencted to SD Card
+     * @param sclk SPI sclk pin connected to SD Card
+     * @param cs   DigitalOut pin used as SD Card chip select
+     * @param name The name used to access the virtual filesystem
+     */
+    SDFileSystem(PinName mosi, PinName miso, PinName sclk, PinName cs, const char* name);
+    virtual int disk_initialize();
+    virtual int disk_write(const char *buffer, int block_number);
+    virtual int disk_read(char *buffer, int block_number);    
+    virtual int disk_status();
+    virtual int disk_sync();
+    virtual int disk_sectors();
+
+protected:
+
+    int _cmd(int cmd, int arg);
+    int _cmdx(int cmd, int arg);
+    int _cmd8();
+    int _cmd58();
+    int initialise_card();
+    int initialise_card_v1();
+    int initialise_card_v2();
+    
+    int _read(char *buffer, int length);
+    int _write(const char *buffer, int length);
+    int _sd_sectors();
+    int _sectors;
+    
+    SPI _spi;
+    DigitalOut _cs; 
+    int cdv;    
+};
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/TLV320/TLV320.cpp	Fri Aug 05 10:07:47 2011 +0000
@@ -0,0 +1,344 @@
+ /******************************************************
+ * TLV320.cpp: Texas instruments TLV320AIC23B library NXP LPC1768
+ *
+ * Written by:
+ * mbed Team
+ * Ioannis Kedros       -   10th January 2011  
+ * (basic functionality incurred) 
+ * Daniel Worrall       -   15th July 2011
+ * (I2SSlave implementation and API restructuring)
+ *
+ * History
+ * version 2.29
+******************************************************/
+#include "mbed.h"
+#include "TLV320.h"
+
+TLV320::TLV320(PinName sda, PinName scl, int addr, PinName tx_sda, PinName tx_ws, PinName clk, PinName rx_sda, PinName rx_ws)
+                         : mAddr(addr), mI2c_(sda, scl), mI2s_(tx_sda, tx_ws, clk, rx_sda, rx_ws){
+    mI2c_.frequency(150000);
+    reset();                                //TLV resets
+    power(0x07);                            //Power Up the TLV320, but not the MIC, ADC and LINE
+    format(16, STEREO);                     //16Bit I2S protocol format, STEREO
+    frequency(44100);                       //Default sample frequency is 44.1kHz
+    bypass(false);                          //Do not bypass device
+    mute(false);                            //Not muted
+    activateDigitalInterface_();            //The digital part of the chip is active
+    outputVolume(0.6, 0.6);                 //Headphone volume to the default state
+    rxBuffer = &mI2s_.rxBuffer[0];
+} 
+//Public Functions
+/******************************************************
+ * Function name:   inputVolume()
+ *
+ * Description:     set line in volume for left and right channels
+ *
+ * Parameters:      float leftVolumeIn, float rightVolumeIn
+ * Returns:         int 0 (success), -1 (value out of range)
+******************************************************/
+int TLV320::inputVolume(float leftVolumeIn, float rightVolumeIn){
+    //check values are in range
+    if((leftVolumeIn < 0.0)||leftVolumeIn > 1.0) return -1;
+    if((rightVolumeIn < 0.0)||rightVolumeIn > 1.0) return -1;
+    //convert float to encoded char
+    char left = (char)31*leftVolumeIn;          
+    char right = (char)31*rightVolumeIn;
+    //Left Channel
+    cmd[1] = left | (0 << 7);                           //set volume
+    cmd[0] = LEFT_LINE_INPUT_CHANNEL_VOLUME_CONTROL;    //set address
+    mI2c_.write(mAddr, cmd, 2);                         //send
+    //Right Channel
+    cmd[1] = right | (0 << 7);                          //set volume
+    cmd[0] = RIGHT_LINE_INPUT_CHANNEL_VOLUME_CONTROL;   //set address
+    mI2c_.write(mAddr, cmd, 2);                         //send
+    return 0;
+}
+/******************************************************
+ * Function name:   outputVolume()
+ *
+ * Description:     Set headphone (line out) volume for left an right channels
+ *
+ * Parameters:      float leftVolumeOut, float rightVolumeOut
+ * Returns:         int 0 (success), -1 (value out of range)
+******************************************************/
+int TLV320::outputVolume(float leftVolumeOut, float rightVolumeOut){
+    //check values are in range
+    if((leftVolumeOut < 0.0)||leftVolumeOut > 1.0) return -1;
+    if((rightVolumeOut < 0.0)||rightVolumeOut > 1.0) return -1;
+    //convert float to encoded char
+    char left = (char)(79*leftVolumeOut)+0x30;
+    char right = (char)(79*rightVolumeOut)+0x30;
+    //Left Channel
+    cmd[1] = left | (1 << 7);                           //set volume
+    cmd[0] = LEFT_CHANNEL_HEADPHONE_VOLUME_CONTROL;     //set address
+    mI2c_.write(mAddr, cmd, 2);                         //send
+    //Right Channel
+    cmd[1] = right | (1 << 7);                          //set volume
+    cmd[0] = RIGHT_CHANNEL_HEADPHONE_VOLUME_CONTROL;    //set address
+    mI2c_.write(mAddr, cmd, 2);                         //send
+    return 0;
+}
+/******************************************************
+ * Function name:   bypass()
+ *
+ * Description:     Send TLV320 into bypass mode, i.e. connect input to output 
+ *
+ * Parameters:      bool bypassVar
+ * Returns:         none
+******************************************************/
+void TLV320::bypass(bool bypassVar){
+    if(bypassVar == true)
+        cmd[1] = (1 << 3) | (0 << 4) | (0 << 5);//bypass enabled, DAC disabled, sidetone insertion disabled
+    else
+        cmd[1] = (0 << 3) | (1 << 4);           //bypass disabled, DAC enabled
+    cmd[1] |= (0 << 2);
+    cmd[0] = ANALOG_AUDIO_PATH_CONTROL;         //set address
+    mI2c_.write(mAddr, cmd, 2);                 //send
+}
+/******************************************************
+ * Function name:   mute()
+ *
+ * Description:     Send TLV320 into mute mode
+ *
+ * Parameters:      bool softMute
+ * Returns:         none
+******************************************************/
+void TLV320::mute(bool softMute){   
+    if(softMute == true) cmd[1] = 0x08;         //set instruction to mute
+    else cmd[1] = 0x00;                         //set instruction to NOT mute
+     
+    cmd[0] = DIGITAL_AUDIO_PATH_CONTROL;        //set address  
+    mI2c_.write(mAddr, cmd, 2);                 //send
+}    
+/******************************************************
+ * Function name:   power()
+ *
+ * Description:     Switch TLV320 on/off
+ *
+ * Parameters:      bool powerUp
+ * Returns:         none
+******************************************************/      
+void TLV320::power(bool powerUp){
+    if(powerUp == true) cmd[1] = 0x00;          //everything on
+    else cmd[1] = 0xFF;                         //everything off
+    
+    cmd[0] = POWER_DOWN_CONTROL;                //set address
+    mI2c_.write(mAddr, cmd, 2);                  //send
+}
+/******************************************************
+ * Function name:   power()
+ *
+ * Description:     Switch on individual devices on TLV320
+ *
+ * Parameters:      int device
+ * Returns:         none
+******************************************************/
+void TLV320::power(int device){
+    cmd[1] = (char)device;                      //set user defined commands
+    cmd[0] = POWER_DOWN_CONTROL;                //set address
+    mI2c_.write(mAddr, cmd, 2);                 //send
+}
+/******************************************************
+ * Function name:   format()
+ *
+ * Description:     Set interface format
+ *
+ * Parameters:      char length, bool mode
+ * Returns:         none
+******************************************************/      
+void TLV320::format(char length, bool mode){  
+    char modeSet = (1 << 6);   
+    modeSet |= (1 << 5);                        //swap left and right channels
+    
+    switch (length)                             //input data into instruction byte
+    {
+        case 16:
+            cmd[1] = modeSet | 0x02; 
+            break;
+        case 20:
+            cmd[1] = modeSet | 0x06;
+            break;
+        case 24:
+            cmd[1] = modeSet | 0x0A;
+            break;
+        case 32:
+            cmd[1] = modeSet | 0x0E;
+            break;
+        default:
+            break;
+    }
+    mI2s_.format(length, mode);
+    cmd[0] = DIGITAL_AUDIO_INTERFACE_FORMAT;        //set address
+    mI2c_.write(mAddr, cmd, 2);                     //send
+}
+/******************************************************
+ * Function name:   frequency()
+ *
+ * Description:     Set sample frequency
+ *
+ * Parameters:      int hz
+ * Returns:         int 0 (success), -1 (value not recognised)
+******************************************************/
+int TLV320::frequency(int hz){
+    char rate;
+    switch(hz){
+        case 8000:
+            rate = 0x03; 
+            break;
+        case 8021:
+            rate = 0x0B;
+            break;
+        case 32000:
+            rate = 0x06;
+            break;
+        case 44100:
+            rate = 0x08; 
+            break;
+        case 48000:
+            rate = 0x00; 
+            break;
+        case 88200:
+            rate = 0x0F;  
+            break;
+        case 96000:
+            rate = 0x07;
+            break;
+        default:
+            return -1;
+    }
+    char clockInChar = (0 << 6);
+    char clockModeChar = (1 << 0);
+
+    cmd[1] = (rate << 2) | clockInChar | clockModeChar;      //input data into instruciton byte
+    cmd[0] = SAMPLE_RATE_CONTROL;           //set address  
+    mI2c_.write(mAddr, cmd, 2);              //send
+    return 0;
+}   
+/******************************************************
+ * Function name:   reset()
+ *
+ * Description:     Reset TLV320
+ *
+ * Parameters:      none
+ * Returns:         none
+******************************************************/        
+void TLV320::reset(void){
+    cmd[0] = RESET_REGISTER;                //set address
+    cmd[1] = 0x00;                          //this resets the entire device
+    mI2c_.write(mAddr, cmd, 2);               
+}
+/******************************************************
+ * Function name:   start()
+ *
+ * Description:     Enable interrupts on the I2S port
+ *
+ * Parameters:      int mode
+ * Returns:         none
+******************************************************/
+void TLV320::start(int mode){
+    mI2s_.start(mode);
+}
+/******************************************************
+ * Function name:   stop()
+ *
+ * Description:     Disable interrupts on the I2S port
+ *
+ * Parameters:      none
+ * Returns:         none
+******************************************************/
+void TLV320::stop(void){
+    mI2s_.stop();
+}
+/******************************************************
+ * Function name:   write()
+ *
+ * Description:     Write (part of) a buffer to the I2S port
+ *
+ * Parameters:      int *buffer, int from, int length
+ * Returns:         none
+******************************************************/
+void TLV320::write(int *buffer, int from, int length){
+    mI2s_.write(buffer, from, length);
+}
+/******************************************************
+ * Function name:   read()
+ *
+ * Description:     Place I2SRXFIFO in rxBuffer
+ *
+ * Parameters:      none
+ * Returns:         none
+******************************************************/
+void TLV320::read(void){
+    mI2s_.read();
+}
+/******************************************************
+ * Function name:   attach()
+ *
+ * Description:     Attach a void/void function or void/void static member function to IRQHandler
+ *
+ * Parameters:      none
+ * Returns:         none
+******************************************************/
+void TLV320::attach(void(*fptr)(void)){
+    mI2s_.attach(fptr);
+}
+//Private Functions
+/******************************************************
+ * Function name:   setSampleRate_()
+ *
+ * Description:     Clocking control
+ *
+ * Parameters:      char rate, bool clockIn, bool clockMode, bool bOSR
+ * Returns:         none
+******************************************************/
+void TLV320::setSampleRate_(char rate, bool clockIn, bool clockMode, bool bOSR){
+    char clockInChar;
+    char clockModeChar;
+    char baseOverSamplingRate;
+    if(bOSR){
+        baseOverSamplingRate = (1 << 0);
+    } else {
+        baseOverSamplingRate = (0 << 0);
+    }
+    if(clockIn){
+        clockInChar = (1 << 6);
+    } else {
+        clockInChar = (0 << 6);
+    }
+    if(clockMode){
+        clockModeChar = 0x01;
+    } else {
+        clockModeChar = 0x00;
+    }
+    cmd[1] = (rate << 2) | clockInChar | clockModeChar | baseOverSamplingRate;      //input data into instruciton byte
+    cmd[0] = SAMPLE_RATE_CONTROL;               //set address  
+    mI2c_.write(mAddr, cmd, 2);                 //send
+}
+/******************************************************
+ * Function name:   activateDigitalInterface_()
+ *
+ * Description:     Activate digital part of chip
+ *
+ * Parameters:      none
+ * Returns:         none
+******************************************************/
+void TLV320::activateDigitalInterface_(void){
+    cmd[1] = 0x01;                          //Activate  
+    cmd[0] = DIGITAL_INTERFACE_ACTIVATION;  //set address
+    mI2c_.write(mAddr, cmd, 2);             //send
+}
+/******************************************************
+ * Function name:   deactivateDigitalInterface_
+ *
+ * Description:     Deactivate digital part of chip
+ *
+ * Parameters:      none
+ * Returns:         none
+******************************************************/
+//Digital interface deactivation 
+void TLV320::deactivateDigitalInterface_(void){
+    cmd[1] = 0x00;                          //Deactivate
+    cmd[0] = DIGITAL_INTERFACE_ACTIVATION;  //set address
+    mI2c_.write(mAddr, cmd, 2);             //send
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/TLV320/TLV320.h	Fri Aug 05 10:07:47 2011 +0000
@@ -0,0 +1,187 @@
+ /******************************************************
+ * TLV320.h: Texas instruments TLV320AIC23B library NXP LPC1768
+ *
+ * Written by:
+ * mbed Team
+ * Ioannis Kedros       -   10th January 2011  
+ * (basic functionality incurred) 
+ * Daniel Worrall       -   15th July 2011
+ * (I2SSlave implementation and API restructuring)
+ *
+ * History
+ * version 2.29
+******************************************************/
+
+#ifndef MBED_TLV320_H
+#define MBED_TLV320_H
+
+#include "mbed.h"
+#include "I2SSlave.h"
+
+/** TLV320 class, defined on the I2C master bus
+*
+*/
+
+class TLV320
+{        
+    public:
+        //constructor
+        /** Create a TLV320 object defined on the I2C port
+        *  
+        * @param sda Serial data pin (p9 or p28)
+        * @param scl Serial clock pin (p10 or p27)
+        * @param addr Object address
+        */
+        TLV320(PinName sda, PinName scl, int addr, PinName tx_sda, PinName tx_ws, PinName clk, PinName rx_sda, PinName rx_ws);
+        /** Power up/down
+        *
+        * @param powerUp 0 = power down, 1 = power up
+        */
+        void power(bool powerUp);
+        /** Overloaded power() function
+        *
+        * @param device Call individual devices to power up/down
+        * Device power      0x00 = On 0x80 = Off
+        * Clock             0x00 = On 0x40 = Off
+        * Oscillator        0x00 = On 0x20 = Off
+        * Outputs           0x00 = On 0x10 = Off
+        * DAC               0x00 = On 0x08 = Off
+        * ADC               0x00 = On 0x04 = Off
+        * Microphone input  0x00 = On 0x02 = Off
+        * Line input        0x00 = On 0x01 = Off
+        */
+        void power(int device);
+        /** Set I2S interface bit length and mode
+        *
+        * @param length Set bit length to 16, 20, 24 or 32 bits
+        * @param mode Set STEREO (0), MONO (1)
+        */
+        void format(char length, bool mode);
+        /** Set sample frequency
+         *
+         * @param frequency Sample frequency of data in Hz
+         * @return Returns an integer 0 = success, -1 = unrecognnised frequency
+         * 
+         * The TLV320 supports the following frequencies: 8kHz, 8.021kHz, 32kHz, 44.1kHz, 48kHz, 88.2kHz, 96kHz
+         * Default is 44.1kHz
+         */
+        int frequency(int hz);
+        /** Reset TLV320
+        *
+        */
+        void reset(void);
+        /** Start streaming i.e. enable interrupts
+         *
+         * @param mode Enable interrupts for NONE, TRANSMIT only, RECEIVE only, BOTH
+         */
+        void start(int mode);
+        /** Stop streaming i.e. disable all interrupts
+         *
+         */
+        void stop(void);
+        /** Write [length] 32 bit words in buffer to I2S port
+         *
+         * @param *buffer Address of buffer to be written
+         * @param from Start position in buffer to read from
+         * @param length Number of words to be written (MUST not exceed 4)
+         */
+        void write(int *buffer, int from, int length);
+        /** Read 4 x (32bit) words into rxBuffer
+         *
+         */
+        void read(void);
+        /** Attach a void/void function or void/void static member funciton to an interrupt generated by the I2SxxFIFOs
+         *
+         * @param function Function to attach
+         *
+         * e.g. myTlv320Object.attach(&myfunction);
+         * OR   myTlv320Object.attach(&myClass::myStaticMemberFunction);
+         */
+        void attach(void(*fptr)(void));
+        /** Attach a nonstatic void/void member function to an interrupt generated by the I2SxxFIFOs
+         *
+         * @param tptr Object pointer
+         * @param mptr Member function pointer
+         *
+         * e.g. myTlv320Object.attach(&myObject, &myClass::myNonstaticMemberFunction); where myObject is an object of myClass
+         */
+        template<typename T>
+        void attach(T *tptr, void(T::*mptr)(void)){
+            mI2s_.attach(tptr, mptr);
+        }
+                /** Line in volume control i.e. record volume
+        *
+        * @param leftVolumeIn Left line-in volume 
+        * @param rightVolumeIn Right line-in volume
+        * @return Returns 0 for success, -1 if parameters are out of range
+        * Parameters accept a value, where 0.0 < parameter < 1.0 and where 0.0 maps to -34.5dB 
+        * and 1.0 maps to +12dB (0.74 = 0 dB default).
+        */
+        int inputVolume(float leftVolumeIn, float rightVolumeIn);
+        /** Headphone out volume control
+        *
+        * @param leftVolumeOut Left line-out volume
+        * @param rightVolumeOut Right line-out volume
+        * @return Returns 0 for success, -1 if parameters are out of range
+        * Parameters accept a value, where 0.0 < parameter < 1.0 and where 0.0 maps to -73dB (mute) 
+        * and 1.0 maps to +6dB (0.5 = default)
+        */
+        int outputVolume(float leftVolumeOut, float rightVolumeOut);
+       /** Analog audio path control
+        *
+        * @param bypassVar Route analogue audio direct from line in to headphone out
+        */
+        void bypass(bool bypassVar);
+        /**Digital audio path control
+        *
+        * @param softMute Mute output
+        */
+        void mute(bool softMute);
+        //Receive buffer
+        
+        int *rxBuffer;
+        
+    protected:
+        char cmd[2];    //the address and command for TLV320 internal registers
+        int mAddr;      //register write address
+    private:
+        I2C mI2c_;      //MUST use the I2C port
+        I2SSlave mI2s_;
+        Ticker I2sTick;
+        void io(void);   
+       /** Sample rate control
+        *
+        * @param rate Set the sampling rate as per datasheet section 3.3.2
+        * @param clockIn Set the clock in divider MCLK, MCLK_DIV2
+        * @param clockMode Set clock mode CLOCK_NORMAL, CLOCK_USB
+        */
+        void setSampleRate_(char rate, bool clockIn, bool mode, bool bOSR); 
+       /** Digital interface activation
+        *
+        */
+        void activateDigitalInterface_(void);
+        /** Digital interface deactivation
+        *
+        */
+        void deactivateDigitalInterface_(void);
+
+        //TLV320AIC23B register addresses as defined in the TLV320AIC23B datasheet
+        #define LEFT_LINE_INPUT_CHANNEL_VOLUME_CONTROL  (0x00 << 1)
+        #define RIGHT_LINE_INPUT_CHANNEL_VOLUME_CONTROL (0x01 << 1)
+        #define LEFT_CHANNEL_HEADPHONE_VOLUME_CONTROL   (0x02 << 1)
+        #define RIGHT_CHANNEL_HEADPHONE_VOLUME_CONTROL  (0x03 << 1)
+        #define ANALOG_AUDIO_PATH_CONTROL               (0x04 << 1)
+        #define DIGITAL_AUDIO_PATH_CONTROL              (0x05 << 1)
+        #define POWER_DOWN_CONTROL                      (0x06 << 1)
+        #define DIGITAL_AUDIO_INTERFACE_FORMAT          (0x07 << 1)
+        #define SAMPLE_RATE_CONTROL                     (0x08 << 1)
+        #define DIGITAL_INTERFACE_ACTIVATION            (0x09 << 1)
+        #define RESET_REGISTER                          (0x0F << 1)
+        
+        #define CLOCK_NORMAL        0
+        #define CLOCK_USB           1
+        #define MCLK                0
+        #define MCLK_DIV2           1
+};
+
+#endif
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main.cpp	Fri Aug 05 10:07:47 2011 +0000
@@ -0,0 +1,68 @@
+#include "mbed.h"
+#include "SDHCFileSystem.h"
+#include "TLV320.h"
+ 
+TLV320 audio(p9, p10, 52, p5, p6, p7, p8, p29); //TLV320 object
+SDFileSystem sd(p11, p12, p13, p14, "sd");      //SD Card object
+InterruptIn volumeSet(p17);                     
+AnalogIn aIn(p19); 
+FILE *infp;                                     //File pointer object
+/* Buffers */
+int circularBuffer[4096];    
+volatile int readPointer = 0;
+volatile int theta = 0;
+/* Wav file header data, for setting up the transfer protocol */
+short channels;
+long sampleRate;
+short wordWidth;
+/* Function to set volume*/
+void setVolume(void){
+    audio.outputVolume(aIn, aIn);                
+}
+/* Function to read from circular buffer and send data to TLV320 */
+void play(void){ 
+        audio.write(circularBuffer, readPointer, 8);      
+        //Pointer fun :-)
+        readPointer += 8;
+        readPointer &= 0xfff;
+        theta -= 8;
+}
+/* Function to load circular buffer from SD Card */
+void fillBuffer(void){
+    while(!feof(infp)){                                         //fill the circular buffer until the end of the file
+        static volatile int writePointer = 0;
+        if(theta < 4096){
+            fread(&circularBuffer[writePointer], 4, 4, infp);   //read 4 integers into the circular buffer at a time
+            //More pointer fun :D
+            theta+=4;
+            writePointer+=4;
+            writePointer &= 0xfff;
+        }
+    }
+}
+/* main */
+int main(){   
+    infp = fopen("/sd/test.wav", "r");      //open file
+        if(infp == NULL){                   //make sure it's been opened
+        perror("Error opening file!");
+        exit(1);
+    }
+    /* Parse wav file header */
+    fseek(infp, 22, SEEK_SET);                      
+    fread(&channels, 2, 1, infp);
+    fseek(infp, 24, SEEK_SET);
+    fread(&sampleRate, 4, 1, infp);
+    fseek(infp, 34, SEEK_SET);
+    fread(&wordWidth, 2, 1, infp);
+    
+    volumeSet.rise(&setVolume);             //attach set volume function to digital input
+    audio.power(0x07);                      //power up TLV apart from analogue input
+    audio.frequency(sampleRate);            //set sample frequency
+    audio.format(wordWidth, (2-channels));  //set transfer protocol
+    audio.attach(&play);                    //attach interrupt handler to send data to TLV320
+    for(int j = 0; j < 4096; ++j){          //upon interrupt generation
+        circularBuffer[j] = 0;              //clear circular buffer
+    }
+    audio.start(TRANSMIT);                  //interrupt come from the I2STXFIFO only
+    fillBuffer();                           //continually fill circular buffer
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed.bld	Fri Aug 05 10:07:47 2011 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/mbed_official/code/mbed/builds/63bcd7ba4912