A well tested I2S library where the send and recieve parts are seperate instances.

Dependents:   TLV320_Write_test flash_audio_playerI2S Wolfson_3_wav

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers I2S.cpp Source File

I2S.cpp

00001 #include "I2S.h"
00002 
00003 #define I2S_DF_WORDWIDTH                16
00004 #define I2S_DF_SAMPLERATE               32000
00005 #define I2S_DF_MASTERSLAVE              I2S_SLAVE
00006 #define I2S_DF_STEREOMONO               I2S_STEREO
00007 #define I2S_DF_MUTED                    I2S_UNMUTED
00008 #define I2S_DF_INTERRUPT_FIFO_LEVEL     4
00009 
00010 #define I2S_MAX_DENOMINATOR             256
00011 #define I2S_MAX_NUMERATOR               256
00012 #define I2S_MAX_BITRATE_DIV             64
00013 
00014 #define I2S_PCLK_RATE                   24000000
00015 
00016 FunctionPointer I2S::I2STXISR;
00017 FunctionPointer I2S::I2SRXISR;
00018 
00019 bool I2S::txisr;
00020 bool I2S::rxisr;
00021 
00022 I2S::I2S(bool rxtx, PinName sd, PinName ws, PinName clk)
00023 {
00024     NVIC_DisableIRQ (I2S_IRQn);
00025 
00026     _sd = sd;
00027     _ws = ws;
00028     _clk = clk;
00029     _rxtx = rxtx;
00030 
00031     ws_d = true;
00032     clk_d = true;
00033     mclk_d = false;
00034 
00035     fourwire = false;
00036 
00037     reg_write_err = 0;
00038 
00039     pin_setup();
00040 
00041     if (pin_setup_err != 0) {
00042         perror("I2S Pins incorrectly defined.");
00043     }
00044 
00045     defaulter();
00046 }
00047 
00048 I2S::I2S(bool rxtx, PinName sd)
00049 {
00050     NVIC_DisableIRQ (I2S_IRQn);
00051 
00052     _sd = sd;
00053     _rxtx = rxtx;
00054 
00055     ws_d = false;
00056     clk_d = false;
00057     mclk_d = false;
00058 
00059     fourwire = false;
00060 
00061     reg_write_err = 0;
00062 
00063     pin_setup();
00064 
00065     if (pin_setup_err != 0) {
00066         perror("I2S Pins incorrectly defined.");
00067     }
00068 
00069     defaulter();
00070 }
00071 
00072 I2S::I2S(bool rxtx, PinName sd, bool fourwiremode)
00073 {
00074     NVIC_DisableIRQ (I2S_IRQn);
00075 
00076     _sd = sd;
00077     _rxtx = rxtx;
00078 
00079     ws_d = false;
00080     clk_d = false;
00081     mclk_d = false;
00082 
00083     reg_write_err = 0;
00084 
00085     fourwire = fourwiremode;
00086 
00087     pin_setup();
00088 
00089     if (pin_setup_err != 0) {
00090         perror("I2S Pins incorrectly defined.");
00091     }
00092 
00093     defaulter();
00094 }
00095 
00096 I2S::I2S(bool rxtx, PinName sd, PinName ws, bool fourwiremode)
00097 {
00098     NVIC_DisableIRQ (I2S_IRQn);
00099 
00100     _sd = sd;
00101     _ws = ws;
00102     _rxtx = rxtx;
00103 
00104     ws_d = true;
00105     clk_d = false;
00106     mclk_d = false;
00107 
00108     reg_write_err = 0;
00109 
00110     fourwire = fourwiremode;
00111 
00112     pin_setup();
00113 
00114     if (pin_setup_err != 0) {
00115         perror("I2S Pins incorrectly defined.");
00116     }
00117 
00118     defaulter();
00119 }
00120 
00121 I2S::I2S(bool rxtx, PinName sd, PinName ws)
00122 {
00123     NVIC_DisableIRQ (I2S_IRQn);
00124 
00125     _sd = sd;
00126     _ws = ws;
00127     _rxtx = rxtx;
00128 
00129     ws_d = true;
00130     clk_d = false;
00131     mclk_d = false;
00132 
00133     reg_write_err = 0;
00134 
00135     fourwire = false;
00136 
00137     pin_setup();
00138 
00139     if (pin_setup_err != 0) {
00140         perror("I2S Pins incorrectly defined.");
00141     }
00142 
00143     defaulter();
00144 }
00145 
00146 I2S::~I2S()
00147 {
00148     NVIC_DisableIRQ (I2S_IRQn);
00149     deallocating = true;
00150     pin_setup();
00151     write_registers();
00152 }
00153 
00154 void I2S::defaulter()
00155 {
00156     LPC_SC->PCONP |= (1 << 27);
00157 
00158     stop();
00159     master = false;
00160     deallocating = false;
00161 
00162     frequency(I2S_DF_SAMPLERATE);
00163     wordsize(I2S_DF_WORDWIDTH);
00164     masterslave (I2S_DF_MASTERSLAVE);
00165     stereomono (I2S_DF_STEREOMONO);
00166     set_interrupt_fifo_level(I2S_DF_INTERRUPT_FIFO_LEVEL);
00167     mute (I2S_DF_MUTED);
00168 
00169     NVIC_SetVector(I2S_IRQn, (uint32_t) & _i2sisr);
00170     NVIC_EnableIRQ (I2S_IRQn);
00171 }
00172 
00173 void I2S::write(char buf[], int len)
00174 {
00175     if (_rxtx == I2S_TRANSMIT) {
00176         if (len > max_fifo_points())
00177             len = max_fifo_points();
00178         if (len <= 0)
00179             return;
00180         int temp = 0;
00181         for (int i = 0; i < len; i += 4) {
00182             temp = 0;
00183             for (int j = 0; j < 4; j++) {
00184                 temp |= int(buf[i + j]) << (j * 8);
00185             }
00186             LPC_I2S->I2STXFIFO = temp;
00187         }
00188     }
00189 
00190 }
00191 
00192 void I2S::write(int buf[], int len)
00193 {
00194     if (_rxtx == I2S_TRANSMIT && wordwidth > 0) {
00195         if (len > max_fifo_points()) {
00196             len = max_fifo_points();
00197             printf("Trying to write too much data!\n\r");
00198         }
00199         if (len <= 0)
00200             return;
00201         uint32_t temp = 0;
00202         int increment = 32 / wordwidth;
00203         unsigned char recast[] =
00204         { 0, 0, 0, 0 };
00205         for (int i = 0; i < len; i += increment) {
00206             temp = 0;
00207 
00208             switch (wordwidth) {
00209 
00210                 case 8:
00211 
00212                     recast[0] = (int8_t) buf[i + 0];
00213                     recast[1] = (int8_t) buf[i + 1];
00214                     recast[2] = (int8_t) buf[i + 2];
00215                     recast[3] = (int8_t) buf[i + 3];
00216                     break;
00217                 case 16:
00218                     recast[0] = (((int16_t) buf[i + 0]) >> 0) & 0xFF;
00219                     recast[1] = (((int16_t) buf[i + 0]) >> 8) & 0xFF;
00220                     recast[2] = (((int16_t) buf[i + 1]) >> 0) & 0xFF;
00221                     recast[3] = (((int16_t) buf[i + 1]) >> 8) & 0xFF;
00222                     break;
00223                 case 32:
00224                     recast[0] = (((int32_t) buf[i + 0]) >> 0) & 0xFF;
00225                     recast[1] = (((int32_t) buf[i + 0]) >> 8) & 0xFF;
00226                     recast[2] = (((int32_t) buf[i + 0]) >> 16) & 0xFF;
00227                     recast[3] = (((int32_t) buf[i + 0]) >> 24) & 0xFF;
00228                     break;
00229 
00230             }
00231             for (int j = 0; j < 4; j++) {
00232 
00233                 temp |= recast[j] << (j * 8);
00234             }
00235 
00236             //if(((temp >> 16) & 0xFFFF) == 0xFFFF) printf("Hmmm %x %x %x\n\r",temp, increment,i); //|| temp &0xFFFF == 0xFFFF
00237             //if((buf[i]-buf[i+1])>5000 || (buf[i]-buf[i+1])<-5000) printf("J:%i,%i\n\r",buf[i],buf[i+1]);
00238             //printf("%x\n",temp);
00239             LPC_I2S->I2STXFIFO = temp;
00240         }
00241     }
00242 }
00243 
00244 void I2S::write(int bufr[], int bufl[], int len)
00245 {
00246     //#TODO: Write this!
00247 }
00248 
00249 int I2S::read()
00250 {
00251     return LPC_I2S->I2SRXFIFO;
00252 }
00253 
00254 void I2S::read(char buf[], int len)
00255 {
00256     bool len_valid = true;
00257     if (len <= 0)
00258         return;
00259     if (len >= fifo_points())
00260         len = fifo_points();
00261     int temp[8];
00262     int counter = 0;
00263     int increment = 4;            //32/wordwidth;
00264     int fifo_levl = fifo_level();
00265     while (counter < fifo_levl && len_valid) {
00266         temp[counter] = LPC_I2S->I2SRXFIFO;
00267         for (int j = 0; j < increment; j++) {
00268             if ((counter * 4) + j > len) {
00269                 len_valid = false;
00270                 break;
00271             }
00272             buf[counter + j] = temp[counter] >> (j * 8);
00273 
00274         }
00275         counter++;
00276     }
00277 }
00278 
00279 void I2S::read(int buf[], int len)
00280 {
00281     bool len_valid = true;
00282     if (len <= 0)
00283         return;
00284     if (len >= fifo_points())
00285         len = fifo_points();
00286     int temp[8];
00287     int counter = 0;
00288     int increment = 32 / wordwidth;
00289     int fifo_levl = fifo_level();
00290     while (counter < fifo_levl && len_valid) {
00291         temp[counter] = LPC_I2S->I2SRXFIFO;
00292         for (int j = 0; j < increment; j++) {
00293             if ((counter * increment) + j > len) {
00294                 len_valid = false;
00295                 break;
00296             }
00297             buf[counter + j] = temp[counter] >> (j * wordwidth);
00298 
00299         }
00300         counter++;
00301     }
00302 }
00303 
00304 void I2S::read(int bufr[], int bufl[], int len)
00305 {
00306     //#TODO: Write this
00307 }
00308 
00309 int I2S::max_fifo_points()
00310 {
00311     switch (wordwidth) {
00312         case 8:
00313             return (4 * 8);
00314         case 16:
00315             return (2 * 8);
00316         case 32:
00317             return 8;
00318         default:
00319             return 0;
00320     }
00321 }
00322 
00323 int I2S::fifo_points()
00324 {
00325     switch (wordwidth) {
00326         case 8:
00327             return (4 * fifo_level());
00328         case 16:
00329             return (2 * fifo_level());
00330         case 32:
00331             return fifo_level();
00332         default:
00333             return 0;
00334     }
00335 }
00336 
00337 void I2S::power(bool pwr)
00338 {
00339     if (pwr) {
00340         stopped = false;
00341     } else {
00342         stopped = true;
00343     }
00344     write_registers();
00345 }
00346 
00347 void I2S::masterslave(bool mastermode)
00348 {
00349     if (mastermode == I2S_MASTER) {
00350         master = true;
00351     } else {
00352         master = false;
00353     }
00354     write_registers();
00355 }
00356 
00357 void I2S::wordsize(int words)
00358 {
00359     wordwidth = words;
00360     write_registers();
00361 }
00362 
00363 void I2S::mclk_freq(int freq)
00364 {
00365     mclk_frequency = freq;
00366     write_registers();
00367 }
00368 
00369 void I2S::frequency(int desired_freq)
00370 {
00371     freq = desired_freq;
00372     write_registers();
00373 }
00374 
00375 int I2S::fifo_level()
00376 {
00377     int level = 0;
00378     if (_rxtx == I2S_TRANSMIT) {
00379         level = LPC_I2S->I2SSTATE;
00380         level >>= 16;
00381         level &= 0xF;
00382     } else {
00383         level = LPC_I2S->I2SSTATE;
00384         level >>= 8;
00385         level &= 0xF;
00386     }
00387     return level;
00388 }
00389 
00390 void I2S::stereomono(bool stereomode)
00391 {
00392     if (stereomode == I2S_STEREO) {
00393         stereo = true;
00394     } else {
00395         stereo = false;
00396     }
00397 }
00398 
00399 void I2S::mute()
00400 {
00401     muted = true;
00402     write_registers();
00403 }
00404 
00405 void I2S::mute(bool mute_en)
00406 {
00407     muted = mute_en;
00408     write_registers();
00409 }
00410 
00411 void I2S::stop()
00412 {
00413     stopped = true;
00414     write_registers();
00415 }
00416 
00417 void I2S::set_interrupt_fifo_level(int level)
00418 {
00419     interrupt_fifo_level = level;
00420     write_registers();
00421 }
00422 
00423 void I2S::start()
00424 {
00425     stopped = false;
00426     muted = false;
00427     write_registers();
00428 }
00429 
00430 bool I2S::setup_ok()
00431 {
00432     if ((reg_write_err + pin_setup_err) > 0)
00433         return false;
00434     else
00435         return true;
00436 }
00437 
00438 void I2S::pin_setup()
00439 {
00440     pin_setup_err = 0;
00441 
00442     if (_rxtx == I2S_TRANSMIT) {
00443         printf("\n\rSetting up pins....\n\r");
00444         if (_sd != p5)
00445             pin_setup_err++;
00446         if (_ws != p6 && ws_d == true)
00447             pin_setup_err++;
00448         if (_clk != p7 && clk_d == true)
00449             pin_setup_err++;
00450         printf("Hmm....%i\n\r", pin_setup_err);
00451     } else {
00452         if (_sd != p17 && _sd != p8)
00453             pin_setup_err++;
00454         if (_ws != p16 && _ws != p29 && ws_d == true)
00455             pin_setup_err++;
00456         if (_clk != p15 && _clk != p30 && clk_d == true)
00457             pin_setup_err++;
00458     }
00459 
00460     if (pin_setup_err == 0) {
00461         if (_rxtx == I2S_TRANSMIT) {
00462             int val1 = 1;
00463             if (deallocating) {
00464                 val1 = 0;
00465             }
00466             LPC_PINCON->PINSEL0 |= (val1 << 18); //set p5 as transmit serial data line
00467             if (ws_d == true)
00468                 LPC_PINCON->PINSEL0 |= (val1 << 14); //set p7 as transmit clock line
00469             if (clk_d == true)
00470                 LPC_PINCON->PINSEL0 |= (val1 << 16); //set p6 as word select line
00471 
00472         } else {
00473             int val1 = 1;
00474             int val2 = 2;
00475             if (deallocating) {
00476                 val1 = 0;
00477                 val2 = 0;
00478             }
00479 
00480             if (_sd == p8)
00481                 LPC_PINCON->PINSEL0 |= (val1 << 12);
00482             else
00483                 LPC_PINCON->PINSEL1 |= (val2 << 18);
00484 
00485             if (ws_d == true) {
00486                 if (_ws == p29)
00487                     LPC_PINCON->PINSEL0 |= (val1 << 10);
00488                 else
00489                     LPC_PINCON->PINSEL1 |= (val2 << 16);
00490             }
00491 
00492             if (clk_d == true) {
00493                 if (_clk == p15)
00494                     LPC_PINCON->PINSEL0 |= (val1 << 8);
00495                 else
00496                     LPC_PINCON->PINSEL1 |= (val2 << 14);
00497             }
00498         }
00499     }
00500 }
00501 
00502 void I2S::write_registers()
00503 {
00504     reg_write_err = 0;
00505     //Clock Multiplier Calculations
00506     float pre_mult = 0;
00507     int pre_num = 0;
00508     int pre_den = 0;
00509     int bitrate_div = 0;
00510     if (master == true) { // In the hope of not doing all this heavy lifting every configuration
00511         //printf("Doing some clock magic..\n\r");
00512         int bitrate = freq * 64;
00513         float target_div = I2S_PCLK_RATE / float(bitrate * 2);// Work out what divider is needed in the end, including the halving of rates the smoother does
00514         if (mclk_frequency == 0) {
00515             float rnd = fmod(target_div,1);// To make the X/Y fraction closest to 1, we set the last divider to the nearest integer to the rate divider
00516             bitrate_div = int(target_div - rnd);
00517             while (bitrate_div > I2S_MAX_BITRATE_DIV) { // But this might be out of range, so we right shift it into focus
00518                 bitrate_div >>= 1;
00519             }
00520             if (bitrate_div == 0) { // Could be zero, which would disable the the clock...
00521                 bitrate_div = 1;
00522             }
00523             pre_mult = float(bitrate_div) / target_div;    // Work out what we have left to correct
00524             pre_num = 0;
00525             pre_den = 0;
00526             fraction_estimator(pre_mult, &pre_num, &pre_den);// Get the function to work out the closest fraction, there might be some point in adding some possible multipliers of these values to add to the smoothing, the reference manual (UM10360 page 480) suggests this
00527 
00528         } else {
00529             pre_mult = float(mclk_frequency * 2) / (I2S_PCLK_RATE);
00530             pre_num = 0;
00531             pre_den = 0;
00532             fraction_estimator(pre_mult, &pre_num, &pre_den);// Get the function to work out the closest fraction, there might be some point in adding some possible multipliers of these values to add to the smoothing, the reference manual (UM10360 page 480) suggests this
00533             bitrate_div = int(
00534                               I2S_PCLK_RATE * float(pre_num) / float(pre_den)
00535                               / float(bitrate));
00536         }
00537 
00538         old_freq = freq;
00539         old_pre_num = pre_num;
00540         old_pre_den = pre_den;
00541         old_bitrate_div = bitrate_div;
00542     } else {
00543         pre_num = old_pre_num;
00544         pre_den = old_pre_den;
00545         bitrate_div = old_bitrate_div;
00546     }
00547 
00548     //Clock Multiplier, MCLK setup
00549     if (_rxtx == I2S_TRANSMIT) {
00550         int regvals = ((pre_num << 8) & 0xFF00) | (pre_den & 0xFF);
00551         LPC_I2S->I2STXRATE = regvals;                // Setting the X/Y fraction
00552         LPC_I2S->I2STXBITRATE = (bitrate_div - 1) & 0x3F;// Setting up the bitrate divider, the periferal adds one to this
00553 
00554         LPC_I2S->I2STXMODE = fourwire << 2;
00555 
00556         if (mclk_d == true) {
00557             LPC_I2S->I2STXMODE |= (1 << 3);
00558         }
00559     } else {
00560         int regvals = ((pre_num << 8) & 0xFF00) | (pre_den & 0xFF);
00561         LPC_I2S->I2SRXRATE = regvals;                // Setting the X/Y fraction
00562         LPC_I2S->I2SRXBITRATE = (bitrate_div - 1) & 0x3F;// Setting up the bitrate divider, the periferal adds one to this
00563 
00564         LPC_I2S->I2SRXMODE = fourwire << 2;
00565 
00566         if (mclk_d == true) {
00567             LPC_I2S->I2SRXMODE |= (1 << 3);
00568         }
00569     }
00570 
00571     switch (wordwidth) {
00572         case 8:
00573             wordwidth_code = 0;
00574             break;
00575         case 16:
00576             wordwidth_code = 1;
00577             break;
00578         case 32:
00579             wordwidth_code = 3;
00580             break;
00581         default:
00582             reg_write_err++;
00583             break;
00584     }
00585 
00586     int I2SDA_reg = (wordwidth_code & 0x3);
00587     I2SDA_reg |= ((!stereo << 2) & 0x4);
00588     I2SDA_reg |= ((stopped << 3) & 0x8);
00589     I2SDA_reg |= ((!master << 5) & 0x20);
00590     I2SDA_reg |= (0x1F << 6);
00591     I2SDA_reg |= ((muted << 15) & 0x8000);
00592 
00593     if (_rxtx == I2S_TRANSMIT) {
00594         LPC_I2S->I2SDAO = I2SDA_reg;
00595     } else {
00596         LPC_I2S->I2SDAI = I2SDA_reg;
00597     }
00598 
00599     if (_rxtx == I2S_TRANSMIT) {
00600         if (txisr) {
00601             LPC_I2S->I2SIRQ = (LPC_I2S->I2SIRQ & 0xFF0FFFFF)
00602                               | ((interrupt_fifo_level & 0xF) << 16);
00603             LPC_I2S->I2SIRQ |= 0x2;
00604         } else {
00605             LPC_I2S->I2SIRQ &= 0xFFFFFFFD;
00606         }
00607     } else {
00608         if (rxisr) {
00609             LPC_I2S->I2SIRQ = (LPC_I2S->I2SIRQ & 0xFFFFF0FF)
00610                               | ((interrupt_fifo_level & 0xF) << 8);
00611             LPC_I2S->I2SIRQ |= 0x1;
00612         }
00613 
00614         else {
00615             LPC_I2S->I2SIRQ &= 0xFFFFFFFE;
00616         }
00617     }
00618 }
00619 
00620 void I2S::_i2sisr(void)
00621 {
00622     I2STXISR.call();
00623     I2SRXISR.call();
00624 }
00625 
00626 // A function to find the nearest fraction to that put to it, with numerator and denomnator less than 256
00627 // This is used when trying to get the clocks correct
00628 
00629 void I2S::fraction_estimator(float in, int * num, int * den)
00630 {
00631     int test_num = 0;
00632     int test_den = 0;
00633     float least_error = 1;
00634     int least_err_den = 0;
00635     float genval;
00636     float generr;
00637 
00638     for (test_den = 1; test_den < I2S_MAX_DENOMINATOR; test_den++) {
00639         test_num = int(float(test_den) * in);
00640         if (test_num < I2S_MAX_NUMERATOR && test_num > 0) {
00641             genval = float(test_num) / float(test_den);
00642             generr = mod(genval - in);
00643             if (generr < least_error) {
00644                 least_error = generr;
00645                 least_err_den = test_den;
00646             }
00647             if (generr == 0) {
00648                 break;
00649             }
00650         }
00651     }
00652 
00653     test_num = int(float(least_err_den) * in);
00654     *num = test_num;
00655     *den = least_err_den;
00656 
00657 }
00658 
00659 float I2S::mod(float in)
00660 {
00661     if (in < 0)
00662         in *= -1;
00663 
00664     return in;
00665 }