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