Thi s library works either for lpc1768 or lpc4088 QSB

Fork of I2SSlave by Suga koubou

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 #if defined(TARGET_LPC1768) || defined(TARGET_LPC2368)
00076         LPC_I2S->I2STXFIFO = buffer[i];
00077 #elif defined(TARGET_LPC4088)
00078         LPC_I2S->TXFIFO = buffer[i];
00079 #endif
00080     }
00081 }
00082 /******************************************************
00083  * Function name:   start()
00084  *
00085  * Description:     attach streamOut_ function to ticker interrupt
00086  *
00087  * Parameters:      none
00088  * Returns:         none
00089 ******************************************************/
00090 void I2SSlave::start(int mode){
00091 #if defined(TARGET_LPC1768) || defined(TARGET_LPC2368)
00092     switch(mode){
00093         case(0):
00094              LPC_I2S->I2SIRQ |= (0 << 0);           //disable receive interrupt
00095              LPC_I2S->I2SIRQ |= (0 << 1);           //disable transmit interrupt
00096              break;
00097         case(1):
00098             LPC_I2S->I2SIRQ |= (0 << 0);            //disable receive interrupt
00099             LPC_I2S->I2SIRQ |= (1 << 1);            //enable transmit interrupt
00100             LPC_I2S->I2SIRQ |= (0 << 16);           //set I2STXFIFO depth to 0 words
00101             break;
00102         case(2):
00103             LPC_I2S->I2SIRQ |= (1 << 0);            //enable receive interrupt
00104             LPC_I2S->I2SIRQ |= (0 << 1);            //disable transmit interrupt
00105             LPC_I2S->I2SIRQ |= (4 << 8);            //set I2SRXFIFO depth to 4 words
00106             break;
00107         case(3):
00108             LPC_I2S->I2SIRQ |= (1 << 0);            //enable receive interrupt
00109             LPC_I2S->I2SIRQ |= (4 << 8);            //set I2SRXFIFO depth to 4 words
00110             LPC_I2S->I2SIRQ |= (1 << 1);            //enable transmit interrupt
00111             LPC_I2S->I2SIRQ |= (0 << 16);           //set I2STXFIFO depth to 0 words
00112             break;
00113         default:
00114             break;
00115 #elif defined(TARGET_LPC4088)
00116     switch(mode){
00117         case(0):
00118              LPC_I2S->IRQ |= (0 << 0);           //disable receive interrupt
00119              LPC_I2S->IRQ |= (0 << 1);           //disable transmit interrupt
00120              break;
00121         case(1):
00122             LPC_I2S->IRQ |= (0 << 0);            //disable receive interrupt
00123             LPC_I2S->IRQ |= (1 << 1);            //enable transmit interrupt
00124             LPC_I2S->IRQ |= (0 << 16);           //set I2STXFIFO depth to 0 words
00125             break;
00126         case(2):
00127             LPC_I2S->IRQ |= (1 << 0);            //enable receive interrupt
00128             LPC_I2S->IRQ |= (0 << 1);            //disable transmit interrupt
00129             LPC_I2S->IRQ |= (4 << 8);            //set I2SRXFIFO depth to 4 words
00130             break;
00131         case(3):
00132             LPC_I2S->IRQ |= (1 << 0);            //enable receive interrupt
00133             LPC_I2S->IRQ |= (4 << 8);            //set I2SRXFIFO depth to 4 words
00134             LPC_I2S->IRQ |= (1 << 1);            //enable transmit interrupt
00135             LPC_I2S->IRQ |= (0 << 16);           //set I2STXFIFO depth to 0 words
00136             break;
00137         default:
00138             break;
00139     }
00140 #endif
00141     NVIC_SetPriority(I2S_IRQn, 0);
00142     NVIC_EnableIRQ(I2S_IRQn);                       //enable I2S interrupt in the NVIC 
00143 }
00144 /******************************************************
00145  * Function name:   stop()
00146  *
00147  * Description:     detach streamOut_ from ticker
00148  *
00149  * Parameters:      none
00150  * Returns:         none
00151 ******************************************************/
00152 void I2SSlave::stop(void){
00153     NVIC_DisableIRQ(I2S_IRQn);           
00154 }
00155 /******************************************************
00156  * Function name:   read()
00157  *
00158  * Description:     reads FIFORX buffer into [int32_t rxBuffer[8]]
00159  *
00160  * Parameters:      none
00161  * Returns:         none
00162 ******************************************************/
00163 void I2SSlave::read(void){
00164 #if defined(TARGET_LPC1768) || defined(TARGET_LPC2368)
00165     rxBuffer[0] = LPC_I2S->I2SRXFIFO;
00166     rxBuffer[1] = LPC_I2S->I2SRXFIFO;
00167     rxBuffer[2] = LPC_I2S->I2SRXFIFO;
00168     rxBuffer[3] = LPC_I2S->I2SRXFIFO;
00169 #elif defined(TARGET_LPC4088)
00170     rxBuffer[0] = LPC_I2S->RXFIFO;
00171     rxBuffer[1] = LPC_I2S->RXFIFO;
00172     rxBuffer[2] = LPC_I2S->RXFIFO;
00173     rxBuffer[3] = LPC_I2S->RXFIFO;
00174 #endif
00175 }
00176 /******************************************************
00177  * Function name:   status_()
00178  *
00179  * Description:     Read I2SSTATE register
00180  *
00181  * Parameters:      none
00182  * Returns:         int
00183 ******************************************************/
00184 int I2SSlave::status(void){
00185 #if defined(TARGET_LPC1768) || defined(TARGET_LPC2368)
00186     return LPC_I2S->I2SSTATE;
00187 #elif defined(TARGET_LPC4088)
00188     return LPC_I2S->STATE;
00189 #endif
00190 }
00191 //Private functions
00192 /******************************************************
00193  * Function name:   initialize()
00194  *
00195  * Description:     initialises I2S port 
00196  *
00197  * Parameters:      PinName tx_sda, PinName tx_ws, PinName clk, PinName rx_sda, PinName rx_ws
00198  * Returns:         0 =  successful initialisation
00199                    -1 = initialisation failure
00200 ******************************************************/
00201 int I2SSlave::initialize_(PinName tx_sda, PinName tx_ws, PinName clk, PinName rx_sda, PinName rx_ws){
00202     setPins_(tx_sda, tx_ws, clk, rx_sda, rx_ws);        //designate pins
00203     LPC_SC->PCONP |= (1 << 27);
00204     //configure input/output register
00205     format_(bit_, mode_);           
00206 #if defined(TARGET_LPC1768) || defined(TARGET_LPC2368)
00207     //set mbed as SLAVE  
00208     LPC_I2S->I2SDAO |= (1 << 5);
00209     LPC_I2S->I2SDAI |= (1 << 5);
00210     //clock mode
00211     setClocks_(4);
00212     //set slave mode
00213     modeConfig_();
00214     //set receiver mode
00215     LPC_I2S->I2SRXMODE |= (1 << 1);
00216     //slave mode
00217     LPC_I2S->I2STXRATE = 0;
00218     LPC_I2S->I2SRXRATE = 0;
00219     //Start
00220     LPC_I2S->I2SDAO |= (0 << 3);          
00221     LPC_I2S->I2SDAI |= (0 << 3);
00222     LPC_I2S->I2SDAO |= (0 << 4);          
00223     LPC_I2S->I2SDAI |= (0 << 4);
00224     LPC_I2S->I2SDAO |= (0 << 15);          
00225 #elif defined(TARGET_LPC4088)
00226     //set mbed as SLAVE  
00227     LPC_I2S->DAO |= (1 << 5);
00228     LPC_I2S->DAI |= (1 << 5);
00229     //clock mode
00230     setClocks_(4);
00231     //set slave mode
00232     modeConfig_();
00233     //set receiver mode
00234     LPC_I2S->RXMODE |= (1 << 1);
00235     //slave mode
00236     LPC_I2S->TXRATE = 0;
00237     LPC_I2S->RXRATE = 0;
00238     //Start
00239     LPC_I2S->DAO |= (0 << 3);          
00240     LPC_I2S->DAI |= (0 << 3);
00241     LPC_I2S->DAO |= (0 << 4);          
00242     LPC_I2S->DAI |= (0 << 4);
00243     LPC_I2S->DAO |= (0 << 15);          
00244 #endif
00245     return 0;
00246 }
00247 /******************************************************
00248  * Function name:   setClocks_()
00249  *
00250  * Description:     Set the division setting on the internal clocks
00251  *
00252  * Parameters:      int divideBy
00253  * Returns:         nothing
00254 ******************************************************/
00255 void I2SSlave::setClocks_(int divideBy){
00256 #if defined(TARGET_LPC1768) || defined(TARGET_LPC2368)
00257     switch(divideBy){
00258         case 1:
00259             LPC_SC->PCLKSEL1 |= (1 << 22); 
00260             LPC_SC->PCLKSEL1 |= (0 << 23);     
00261             break;
00262         case 2:
00263             LPC_SC->PCLKSEL1 |= (0 << 22);
00264             LPC_SC->PCLKSEL1 |= (1 << 23);
00265             break;
00266         case 4:
00267             LPC_SC->PCLKSEL1 |= (0 << 22);
00268             LPC_SC->PCLKSEL1 |= (0 << 23);
00269             break;
00270         case 8:
00271             LPC_SC->PCLKSEL1 |= (1 << 22);
00272             LPC_SC->PCLKSEL1 |= (1 << 23);
00273             break;
00274         default:
00275             break;
00276     }
00277 #elif defined(TARGET_LPC4088)
00278     switch(divideBy){
00279         case 1:
00280             LPC_SC->PCLKSEL |= (1 << 22); 
00281             LPC_SC->PCLKSEL |= (0 << 23);     
00282             break;
00283         case 2:
00284             LPC_SC->PCLKSEL |= (0 << 22);
00285             LPC_SC->PCLKSEL |= (1 << 23);
00286             break;
00287         case 4:
00288             LPC_SC->PCLKSEL |= (0 << 22);
00289             LPC_SC->PCLKSEL |= (0 << 23);
00290             break;
00291         case 8:
00292             LPC_SC->PCLKSEL |= (1 << 22);
00293             LPC_SC->PCLKSEL |= (1 << 23);
00294             break;
00295         default:
00296             break;
00297     }
00298 #endif
00299 }
00300 /******************************************************
00301  * Function name:   setPins_()
00302  *
00303  * Description:     set external pin configuration
00304  *
00305  * Parameters:      PinName tx_sda, PinName tx_ws, PinName clk, PinName rx_sda, PinName rx_ws
00306  * Returns:         none
00307 ******************************************************/
00308 void I2SSlave::setPins_(PinName tx_sda, PinName tx_ws, PinName clk, PinName rx_sda, PinName rx_ws){
00309 #if defined(TARGET_LPC1768) || defined(TARGET_LPC2368)
00310 
00311 
00312     printf(" *** TAGET LPC1768 || LPC2368 ***");
00313 
00314 
00315     if(rx_ws == p29){
00316         LPC_PINCON->PINSEL0 |= (1 << 10);   //set p29 as receive word select line
00317     } else {
00318         LPC_PINCON->PINSEL1 |= (2 << 16);   //set p16 as receive word select line
00319     }
00320     if(rx_sda == p8){
00321         LPC_PINCON->PINSEL0 |= (1 << 12);   //set p8 as receive serial data line
00322     } else {
00323         LPC_PINCON->PINSEL1 |= (2 << 18);   //set p17 as receive serial data line
00324     }
00325     LPC_PINCON->PINSEL0 |= (1 << 14);       //set p7 as transmit clock line (only one of these)    
00326     LPC_PINCON->PINSEL0 |= (1 << 16);       //set p6 as word select line (only one of these)   
00327     LPC_PINCON->PINSEL0 |= (1 << 18);       //set p5 as transmit serial data line (only one of these)
00328     LPC_PINCON->PINSEL0 |= (0 << 8);        //clear rx_clk
00329 #elif defined(TARGET_LPC4088)
00330 
00331     printf(" *** TAGET LPC4088 ***");
00332 
00333     if(rx_ws == p33){
00334         LPC_IOCON->P0_5  = (LPC_IOCON->P0_5  & ~7) | 1;   //set p33 as receive word select line
00335     } else {
00336         LPC_IOCON->P0_24 = (LPC_IOCON->P0_24 & ~7) | 2;   //set p16 as receive word select line
00337     }
00338     if(rx_sda == p14){
00339         LPC_IOCON->P0_6  = (LPC_IOCON->P0_6  & ~7) | 1;   //set p14 as receive serial data line
00340     } else {
00341         LPC_IOCON->P0_25 = (LPC_IOCON->P0_25 & ~7) | 2;   //set p17 as receive serial data line
00342     }
00343     LPC_IOCON->P0_7  = (LPC_IOCON->P0_7  & ~7) | 1;       //set p13 as transmit clock line (only one of these)    
00344     LPC_IOCON->P0_8  = (LPC_IOCON->P0_8  & ~7) | 1;       //set p12 as word select line (only one of these)   
00345     LPC_IOCON->P0_9  = (LPC_IOCON->P0_9  & ~7) | 1;       //set p11 as transmit serial data line (only one of these)
00346     LPC_IOCON->P0_23 = (LPC_IOCON->P0_4  & ~7);           // p15 clear rx_clk
00347     LPC_IOCON->P0_23 = (LPC_IOCON->P0_23 & ~7);           // p15clear rx_clk
00348 #endif
00349 }
00350 /******************************************************
00351  * Function name:   format_()
00352  *
00353  * Description:     sets the bit length for writing and stereo or mono mode
00354  *
00355  * Parameters:      int bit, bool mode
00356  * Returns:         none
00357 ******************************************************/
00358 void I2SSlave::format_(int bit, bool mode){
00359     uint32_t bps= ((bit+1)*8)-1;
00360 #if defined(TARGET_LPC1768) || defined(TARGET_LPC2368)
00361     LPC_I2S->I2SDAO &= (0x00 << 6);
00362     LPC_I2S->I2SDAO |= (bps << 6);
00363     //set bit length
00364     switch(bit){
00365         case 8:
00366             LPC_I2S->I2SDAO &= 0xfffffffc;
00367             break;
00368         case 16:
00369             LPC_I2S->I2SDAO &= (0 << 1);
00370             LPC_I2S->I2SDAO |= (1 << 0);           
00371             break;
00372         case 32:
00373             LPC_I2S->I2SDAO &= (0 << 1);
00374             LPC_I2S->I2SDAO |= (3 << 0);
00375             break;
00376         default:
00377             break;
00378     }
00379     //set audio mode
00380     if(mode == STEREO){
00381         LPC_I2S->I2SDAO |= (0 << 2);
00382     } else {
00383         LPC_I2S->I2SDAO |= (1 << 2);
00384     }
00385     //set transmitter and receiver setting to be the same
00386     LPC_I2S->I2SDAI &= (0x00 << 6);
00387     LPC_I2S->I2SDAI |= (bps << 6);
00388     //set bit length
00389     switch(bit){
00390         case 8:
00391             LPC_I2S->I2SDAI &= 0xfffffffc;
00392             break;
00393         case 16:
00394             LPC_I2S->I2SDAI &= (0 << 1);
00395             LPC_I2S->I2SDAI |= (1 << 0);
00396             break;
00397         case 32:
00398             LPC_I2S->I2SDAI &= (0 << 1);
00399             LPC_I2S->I2SDAI |= (3 << 0);
00400             break;
00401         default:
00402             break;
00403     }
00404     //set audio mode
00405     if(mode == STEREO){
00406         LPC_I2S->I2SDAI |= (0 << 2);
00407     } else {
00408         LPC_I2S->I2SDAI |= (1 << 2);
00409     }
00410 #elif defined(TARGET_LPC4088)
00411     LPC_I2S->DAO &= (0x00 << 6);
00412     LPC_I2S->DAO |= (bps << 6);
00413     //set bit length
00414     switch(bit){
00415         case 8:
00416             LPC_I2S->DAO &= 0xfffffffc;
00417             break;
00418         case 16:
00419             LPC_I2S->DAO &= (0 << 1);
00420             LPC_I2S->DAO |= (1 << 0);           
00421             break;
00422         case 32:
00423             LPC_I2S->DAO &= (0 << 1);
00424             LPC_I2S->DAO |= (3 << 0);
00425             break;
00426         default:
00427             break;
00428     }
00429     //set audio mode
00430     if(mode == STEREO){
00431         LPC_I2S->DAO |= (0 << 2);
00432     } else {
00433         LPC_I2S->DAO |= (1 << 2);
00434     }
00435     //set transmitter and receiver setting to be the same
00436     LPC_I2S->DAI &= (0x00 << 6);
00437     LPC_I2S->DAI |= (bps << 6);
00438     //set bit length
00439     switch(bit){
00440         case 8:
00441             LPC_I2S->DAI &= 0xfffffffc;
00442             break;
00443         case 16:
00444             LPC_I2S->DAI &= (0 << 1);
00445             LPC_I2S->DAI |= (1 << 0);
00446             break;
00447         case 32:
00448             LPC_I2S->DAI &= (0 << 1);
00449             LPC_I2S->DAI |= (3 << 0);
00450             break;
00451         default:
00452             break;
00453     }
00454     //set audio mode
00455     if(mode == STEREO){
00456         LPC_I2S->DAI |= (0 << 2);
00457     } else {
00458         LPC_I2S->DAI |= (1 << 2);
00459     }
00460 #endif
00461 }
00462 /******************************************************
00463  * Function name:   modeConfig_()
00464  *
00465  * Description:     Set slave mode
00466  *
00467  * Parameters:      none
00468  * Returns:         none
00469 ******************************************************/
00470 void I2SSlave::modeConfig_(void){
00471 #if defined(TARGET_LPC1768) || defined(TARGET_LPC2368)
00472     LPC_I2S->I2STXMODE |= (0x0 << 0);
00473     LPC_I2S->I2SRXMODE |= (0x0 << 0);
00474 #elif defined(TARGET_LPC4088)
00475     LPC_I2S->TXMODE |= (0x0 << 0);
00476     LPC_I2S->RXMODE |= (0x0 << 0);
00477 #endif
00478 }
00479 /******************************************************
00480  * Function name:   storePins_()
00481  *
00482  * Description:     set external pin configuration
00483  *
00484  * Parameters:      PinName tx_sda, PinName tx_ws, PinName clk, PinName rx_sda, PinName rx_ws
00485  * Returns:         none
00486 ******************************************************/
00487 void I2SSlave::storePins_(PinName tx_sda, PinName tx_ws, PinName clk, PinName rx_sda, PinName rx_ws){
00488     tx_sda_ = tx_sda;
00489     tx_ws_ = tx_ws;
00490     clk_ = clk;
00491     rx_sda_ = rx_sda;
00492     rx_ws_ = rx_ws;
00493 }