A library which allows the playing of Wav files using the TLV320
Dependents: RSALB_hbridge_helloworld RSALB_lobster WavPlayer_test AudioCODEC_HelloWorld
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 }
Generated on Tue Jul 12 2022 17:42:18 by 1.7.2