Dependents:   playback FTSESpeech i2s_audio_echo i2s_audio_sampler ... more

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers I2SSlave.cpp Source File

I2SSlave.cpp

00001 /**
00002 * @author Daniel Worrall
00003 *
00004 * @section LICENSE
00005 *
00006 * Copyright (c) 2011 mbed
00007 *
00008 * Permission is hereby granted, free of charge, to any person obtaining a copy
00009 * of this software and associated documentation files (the "Software"), to deal
00010 * in the Software without restriction, including without limitation the rights
00011 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
00012 * copies of the Software, and to permit persons to whom the Software is
00013 * furnished to do so, subject to the following conditions:
00014 *
00015 * The above copyright notice and this permission notice shall be included in
00016 * all copies or substantial portions of the Software.
00017 *
00018 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
00019 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
00020 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
00021 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
00022 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
00023 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
00024 * THE SOFTWARE.
00025 *
00026 * @section DESCRIPTION
00027 *    I2S port abstraction library cpp file for NXP LPC1768
00028 *
00029 */ 
00030 #include "I2SSlave.h"
00031 /*Global Functions*/
00032 FunctionPointer akjnh3489v8ncv;
00033 
00034 extern "C" void I2S_IRQHandler(void){                   //this is a very special function so can remain outside
00035     akjnh3489v8ncv.call();
00036 }
00037 /******************************************************
00038  * Function name:   I2SSlave
00039  *
00040  * Description:     class constructor
00041  *
00042  * Parameters:      PinName tx_sda, PinName tx_ws, PinName clk, PinName rx_sda, PinName rx_ws
00043  * Returns:         none
00044 ******************************************************/
00045 //Constructor
00046 I2SSlave::I2SSlave(PinName tx_sda, PinName tx_ws, PinName clk, PinName rx_sda, PinName rx_ws){
00047     storePins_(tx_sda, tx_ws, clk, rx_sda, rx_ws);
00048     format(16, STEREO);                                 //this also invokes initialize so no need to call it twice
00049 }
00050 //Public functions
00051 /******************************************************
00052  * Function name:   format()
00053  *
00054  * Description:     sets the bit length for writing and stereo or mono mode
00055  *
00056  * Parameters:      int bit, bool mode
00057  * Returns:         none
00058 ******************************************************/
00059 void I2SSlave::format(int bit, bool mode){
00060     bit_ = bit;
00061     mode_ = mode;
00062     initialize_(tx_sda_, tx_ws_, clk_, rx_sda_, rx_ws_);
00063 }
00064 /******************************************************
00065  * Function name:   write()
00066  *
00067  * Description:     load buffer to write to I2S port
00068  *
00069  * Parameters:      long *buffer
00070  * Returns:         none
00071 ******************************************************/
00072 void I2SSlave::write(int* buffer, int from, int length){
00073     int to = from + length;
00074     for(int i = from; i < to; ++i){
00075         LPC_I2S->I2STXFIFO = buffer[i];
00076     }
00077 }
00078 /******************************************************
00079  * Function name:   start()
00080  *
00081  * Description:     attach streamOut_ function to ticker interrupt
00082  *
00083  * Parameters:      none
00084  * Returns:         none
00085 ******************************************************/
00086 void I2SSlave::start(int mode){
00087     switch(mode){
00088         case(0):
00089              LPC_I2S->I2SIRQ |= (0 << 0);           //disable receive interrupt
00090              LPC_I2S->I2SIRQ |= (0 << 1);           //disable transmit interrupt
00091              break;
00092         case(1):
00093             LPC_I2S->I2SIRQ |= (0 << 0);            //disable receive interrupt
00094             LPC_I2S->I2SIRQ |= (1 << 1);            //enable transmit interrupt
00095             LPC_I2S->I2SIRQ |= (0 << 16);           //set I2STXFIFO depth to 0 words
00096             break;
00097         case(2):
00098             LPC_I2S->I2SIRQ |= (1 << 0);            //enable receive interrupt
00099             LPC_I2S->I2SIRQ |= (0 << 1);            //disable transmit interrupt
00100             LPC_I2S->I2SIRQ |= (4 << 8);            //set I2SRXFIFO depth to 4 words
00101             break;
00102         case(3):
00103             LPC_I2S->I2SIRQ |= (1 << 0);            //enable receive interrupt
00104             LPC_I2S->I2SIRQ |= (4 << 8);            //set I2SRXFIFO depth to 4 words
00105             LPC_I2S->I2SIRQ |= (1 << 1);            //enable transmit interrupt
00106             LPC_I2S->I2SIRQ |= (0 << 16);           //set I2STXFIFO depth to 0 words
00107             break;
00108         default:
00109             break;
00110     }
00111     NVIC_SetPriority(I2S_IRQn, 0);
00112     NVIC_EnableIRQ(I2S_IRQn);                       //enable I2S interrupt in the NVIC 
00113 }
00114 /******************************************************
00115  * Function name:   stop()
00116  *
00117  * Description:     detach streamOut_ from ticker
00118  *
00119  * Parameters:      none
00120  * Returns:         none
00121 ******************************************************/
00122 void I2SSlave::stop(void){
00123     NVIC_DisableIRQ(I2S_IRQn);           
00124 }
00125 /******************************************************
00126  * Function name:   read()
00127  *
00128  * Description:     reads FIFORX buffer into [int32_t rxBuffer[8]]
00129  *
00130  * Parameters:      none
00131  * Returns:         none
00132 ******************************************************/
00133 void I2SSlave::read(void){
00134     rxBuffer[0] = LPC_I2S->I2SRXFIFO;
00135     rxBuffer[1] = LPC_I2S->I2SRXFIFO;
00136     rxBuffer[2] = LPC_I2S->I2SRXFIFO;
00137     rxBuffer[3] = LPC_I2S->I2SRXFIFO;
00138 }
00139 /******************************************************
00140  * Function name:   status_()
00141  *
00142  * Description:     Read I2SSTATE register
00143  *
00144  * Parameters:      none
00145  * Returns:         int
00146 ******************************************************/
00147 int I2SSlave::status(void){
00148     return LPC_I2S->I2SSTATE;
00149 }
00150 //Private functions
00151 /******************************************************
00152  * Function name:   initialize()
00153  *
00154  * Description:     initialises I2S port 
00155  *
00156  * Parameters:      PinName tx_sda, PinName tx_ws, PinName clk, PinName rx_sda, PinName rx_ws
00157  * Returns:         0 =  successful initialisation
00158                    -1 = initialisation failure
00159 ******************************************************/
00160 int I2SSlave::initialize_(PinName tx_sda, PinName tx_ws, PinName clk, PinName rx_sda, PinName rx_ws){
00161     setPins_(tx_sda, tx_ws, clk, rx_sda, rx_ws);        //designate pins
00162     LPC_SC->PCONP |= (1 << 27);
00163     //configure input/output register
00164     format_(bit_, mode_);           
00165     //set mbed as SLAVE  
00166     LPC_I2S->I2SDAO |= (1 << 5);
00167     LPC_I2S->I2SDAI |= (1 << 5);
00168     //clock mode
00169     setClocks_(4);
00170     //set slave mode
00171     modeConfig_();
00172     //set receiver mode
00173     LPC_I2S->I2SRXMODE |= (1 << 1);
00174     //slave mode
00175     LPC_I2S->I2STXRATE = 0;
00176     LPC_I2S->I2SRXRATE = 0;
00177     //Start
00178     LPC_I2S->I2SDAO |= (0 << 3);          
00179     LPC_I2S->I2SDAI |= (0 << 3);
00180     LPC_I2S->I2SDAO |= (0 << 4);          
00181     LPC_I2S->I2SDAI |= (0 << 4);
00182     LPC_I2S->I2SDAO |= (0 << 15);          
00183     return 0;
00184 }
00185 /******************************************************
00186  * Function name:   setClocks_()
00187  *
00188  * Description:     Set the division setting on the internal clocks
00189  *
00190  * Parameters:      int divideBy
00191  * Returns:         nothing
00192 ******************************************************/
00193 void I2SSlave::setClocks_(int divideBy){
00194     switch(divideBy){
00195         case 1:
00196             LPC_SC->PCLKSEL1 |= (1 << 22); 
00197             LPC_SC->PCLKSEL1 |= (0 << 23);     
00198             break;
00199         case 2:
00200             LPC_SC->PCLKSEL1 |= (0 << 22);
00201             LPC_SC->PCLKSEL1 |= (1 << 23);
00202             break;
00203         case 4:
00204             LPC_SC->PCLKSEL1 |= (0 << 22);
00205             LPC_SC->PCLKSEL1 |= (0 << 23);
00206             break;
00207         case 8:
00208             LPC_SC->PCLKSEL1 |= (1 << 22);
00209             LPC_SC->PCLKSEL1 |= (1 << 23);
00210             break;
00211         default:
00212             break;
00213     }
00214 }
00215 /******************************************************
00216  * Function name:   setPins_()
00217  *
00218  * Description:     set external pin configuration
00219  *
00220  * Parameters:      PinName tx_sda, PinName tx_ws, PinName clk, PinName rx_sda, PinName rx_ws
00221  * Returns:         none
00222 ******************************************************/
00223 void I2SSlave::setPins_(PinName tx_sda, PinName tx_ws, PinName clk, PinName rx_sda, PinName rx_ws){
00224     if(rx_ws == p29){
00225         LPC_PINCON->PINSEL0 |= (1 << 10);   //set p29 as receive word select line
00226     } else {
00227         LPC_PINCON->PINSEL1 |= (2 << 16);   //set p16 as receive word select line
00228     }
00229     if(rx_sda == p8){
00230         LPC_PINCON->PINSEL0 |= (1 << 12);   //set p8 as receive serial data line
00231     } else {
00232         LPC_PINCON->PINSEL1 |= (2 << 18);   //set p17 as receive serial data line
00233     }
00234     LPC_PINCON->PINSEL0 |= (1 << 14);       //set p7 as transmit clock line (only one of these)    
00235     LPC_PINCON->PINSEL0 |= (1 << 16);       //set p6 as word select line (only one of these)   
00236     LPC_PINCON->PINSEL0 |= (1 << 18);       //set p5 as transmit serial data line (only one of these)
00237     LPC_PINCON->PINSEL0 |= (0 << 8);        //clear rx_clk
00238 }
00239 /******************************************************
00240  * Function name:   format_()
00241  *
00242  * Description:     sets the bit length for writing and stereo or mono mode
00243  *
00244  * Parameters:      int bit, bool mode
00245  * Returns:         none
00246 ******************************************************/
00247 void I2SSlave::format_(int bit, bool mode){
00248     uint32_t bps= ((bit+1)*8)-1;
00249     LPC_I2S->I2SDAO &= (0x00 << 6);
00250     LPC_I2S->I2SDAO |= (bps << 6);
00251     //set bit length
00252     switch(bit){
00253         case 8:
00254             LPC_I2S->I2SDAO &= 0xfffffffc;
00255             break;
00256         case 16:
00257             LPC_I2S->I2SDAO &= (0 << 1);
00258             LPC_I2S->I2SDAO |= (1 << 0);           
00259             break;
00260         case 32:
00261             LPC_I2S->I2SDAO &= (0 << 1);
00262             LPC_I2S->I2SDAO |= (3 << 0);
00263             break;
00264         default:
00265             break;
00266     }
00267     //set audio mode
00268     if(mode == STEREO){
00269         LPC_I2S->I2SDAO |= (0 << 2);
00270     } else {
00271         LPC_I2S->I2SDAO |= (1 << 2);
00272     }
00273     //set transmitter and receiver setting to be the same
00274     LPC_I2S->I2SDAI &= (0x00 << 6);
00275     LPC_I2S->I2SDAI |= (bps << 6);
00276     //set bit length
00277     switch(bit){
00278         case 8:
00279             LPC_I2S->I2SDAI &= 0xfffffffc;
00280             break;
00281         case 16:
00282             LPC_I2S->I2SDAI &= (0 << 1);
00283             LPC_I2S->I2SDAI |= (1 << 0);
00284             break;
00285         case 32:
00286             LPC_I2S->I2SDAI &= (0 << 1);
00287             LPC_I2S->I2SDAI |= (3 << 0);
00288             break;
00289         default:
00290             break;
00291     }
00292     //set audio mode
00293     if(mode == STEREO){
00294         LPC_I2S->I2SDAI |= (0 << 2);
00295     } else {
00296         LPC_I2S->I2SDAI |= (1 << 2);
00297     }
00298 }
00299 /******************************************************
00300  * Function name:   modeConfig_()
00301  *
00302  * Description:     Set slave mode
00303  *
00304  * Parameters:      none
00305  * Returns:         none
00306 ******************************************************/
00307 void I2SSlave::modeConfig_(void){
00308     LPC_I2S->I2STXMODE |= (0x0 << 0);
00309     LPC_I2S->I2SRXMODE |= (0x0 << 0);
00310 }
00311 /******************************************************
00312  * Function name:   storePins_()
00313  *
00314  * Description:     set external pin configuration
00315  *
00316  * Parameters:      PinName tx_sda, PinName tx_ws, PinName clk, PinName rx_sda, PinName rx_ws
00317  * Returns:         none
00318 ******************************************************/
00319 void I2SSlave::storePins_(PinName tx_sda, PinName tx_ws, PinName clk, PinName rx_sda, PinName rx_ws){
00320     tx_sda_ = tx_sda;
00321     tx_ws_ = tx_ws;
00322     clk_ = clk;
00323     rx_sda_ = rx_sda;
00324     rx_ws_ = rx_ws;
00325 }