I2S for LPC1768 with typo patch for I2S rx clock pin setup in I2S.cpp line 492 - used for microphone demo

Dependents:   i2s_microphone LPC1768_MicrophoneSensing Receiver

Fork of I2S by Giles Barton-Owen

Fixes I2S rx clock typo in original I2S library code - see line 494 The two I2S RX clock pin options were swapped in the pin setup code. See https://os.mbed.com/users/4180_1/notebook/using-an-i2s-microphone---sph0645lm4h/

Committer:
4180_1
Date:
Fri Jan 26 00:52:02 2018 +0000
Revision:
1:58bbfaf58a7b
Parent:
0:455d5826751b
I2S for LPC1768 - with patch for rx clock pin

Who changed what in which revision?

UserRevisionLine numberNew contents of line
p07gbar 0:455d5826751b 1 #include "I2S.h"
p07gbar 0:455d5826751b 2
p07gbar 0:455d5826751b 3 #define I2S_DF_WORDWIDTH 16
p07gbar 0:455d5826751b 4 #define I2S_DF_SAMPLERATE 32000
p07gbar 0:455d5826751b 5 #define I2S_DF_MASTERSLAVE I2S_SLAVE
p07gbar 0:455d5826751b 6 #define I2S_DF_STEREOMONO I2S_STEREO
p07gbar 0:455d5826751b 7 #define I2S_DF_MUTED I2S_UNMUTED
p07gbar 0:455d5826751b 8 #define I2S_DF_INTERRUPT_FIFO_LEVEL 4
p07gbar 0:455d5826751b 9
p07gbar 0:455d5826751b 10 #define I2S_MAX_DENOMINATOR 256
p07gbar 0:455d5826751b 11 #define I2S_MAX_NUMERATOR 256
p07gbar 0:455d5826751b 12 #define I2S_MAX_BITRATE_DIV 64
p07gbar 0:455d5826751b 13
p07gbar 0:455d5826751b 14 #define I2S_PCLK_RATE 24000000
p07gbar 0:455d5826751b 15
p07gbar 0:455d5826751b 16 FunctionPointer I2S::I2STXISR;
p07gbar 0:455d5826751b 17 FunctionPointer I2S::I2SRXISR;
p07gbar 0:455d5826751b 18
p07gbar 0:455d5826751b 19 bool I2S::txisr;
p07gbar 0:455d5826751b 20 bool I2S::rxisr;
p07gbar 0:455d5826751b 21
p07gbar 0:455d5826751b 22 I2S::I2S(bool rxtx, PinName sd, PinName ws, PinName clk)
p07gbar 0:455d5826751b 23 {
p07gbar 0:455d5826751b 24 NVIC_DisableIRQ (I2S_IRQn);
p07gbar 0:455d5826751b 25
p07gbar 0:455d5826751b 26 _sd = sd;
p07gbar 0:455d5826751b 27 _ws = ws;
p07gbar 0:455d5826751b 28 _clk = clk;
p07gbar 0:455d5826751b 29 _rxtx = rxtx;
p07gbar 0:455d5826751b 30
p07gbar 0:455d5826751b 31 ws_d = true;
p07gbar 0:455d5826751b 32 clk_d = true;
p07gbar 0:455d5826751b 33 mclk_d = false;
p07gbar 0:455d5826751b 34
p07gbar 0:455d5826751b 35 fourwire = false;
p07gbar 0:455d5826751b 36
p07gbar 0:455d5826751b 37 reg_write_err = 0;
p07gbar 0:455d5826751b 38
p07gbar 0:455d5826751b 39 pin_setup();
p07gbar 0:455d5826751b 40
p07gbar 0:455d5826751b 41 if (pin_setup_err != 0) {
p07gbar 0:455d5826751b 42 perror("I2S Pins incorrectly defined.");
p07gbar 0:455d5826751b 43 }
p07gbar 0:455d5826751b 44
p07gbar 0:455d5826751b 45 defaulter();
p07gbar 0:455d5826751b 46 }
p07gbar 0:455d5826751b 47
p07gbar 0:455d5826751b 48 I2S::I2S(bool rxtx, PinName sd)
p07gbar 0:455d5826751b 49 {
p07gbar 0:455d5826751b 50 NVIC_DisableIRQ (I2S_IRQn);
p07gbar 0:455d5826751b 51
p07gbar 0:455d5826751b 52 _sd = sd;
p07gbar 0:455d5826751b 53 _rxtx = rxtx;
p07gbar 0:455d5826751b 54
p07gbar 0:455d5826751b 55 ws_d = false;
p07gbar 0:455d5826751b 56 clk_d = false;
p07gbar 0:455d5826751b 57 mclk_d = false;
p07gbar 0:455d5826751b 58
p07gbar 0:455d5826751b 59 fourwire = false;
p07gbar 0:455d5826751b 60
p07gbar 0:455d5826751b 61 reg_write_err = 0;
p07gbar 0:455d5826751b 62
p07gbar 0:455d5826751b 63 pin_setup();
p07gbar 0:455d5826751b 64
p07gbar 0:455d5826751b 65 if (pin_setup_err != 0) {
p07gbar 0:455d5826751b 66 perror("I2S Pins incorrectly defined.");
p07gbar 0:455d5826751b 67 }
p07gbar 0:455d5826751b 68
p07gbar 0:455d5826751b 69 defaulter();
p07gbar 0:455d5826751b 70 }
p07gbar 0:455d5826751b 71
p07gbar 0:455d5826751b 72 I2S::I2S(bool rxtx, PinName sd, bool fourwiremode)
p07gbar 0:455d5826751b 73 {
p07gbar 0:455d5826751b 74 NVIC_DisableIRQ (I2S_IRQn);
p07gbar 0:455d5826751b 75
p07gbar 0:455d5826751b 76 _sd = sd;
p07gbar 0:455d5826751b 77 _rxtx = rxtx;
p07gbar 0:455d5826751b 78
p07gbar 0:455d5826751b 79 ws_d = false;
p07gbar 0:455d5826751b 80 clk_d = false;
p07gbar 0:455d5826751b 81 mclk_d = false;
p07gbar 0:455d5826751b 82
p07gbar 0:455d5826751b 83 reg_write_err = 0;
p07gbar 0:455d5826751b 84
p07gbar 0:455d5826751b 85 fourwire = fourwiremode;
p07gbar 0:455d5826751b 86
p07gbar 0:455d5826751b 87 pin_setup();
p07gbar 0:455d5826751b 88
p07gbar 0:455d5826751b 89 if (pin_setup_err != 0) {
p07gbar 0:455d5826751b 90 perror("I2S Pins incorrectly defined.");
p07gbar 0:455d5826751b 91 }
p07gbar 0:455d5826751b 92
p07gbar 0:455d5826751b 93 defaulter();
p07gbar 0:455d5826751b 94 }
p07gbar 0:455d5826751b 95
p07gbar 0:455d5826751b 96 I2S::I2S(bool rxtx, PinName sd, PinName ws, bool fourwiremode)
p07gbar 0:455d5826751b 97 {
p07gbar 0:455d5826751b 98 NVIC_DisableIRQ (I2S_IRQn);
p07gbar 0:455d5826751b 99
p07gbar 0:455d5826751b 100 _sd = sd;
p07gbar 0:455d5826751b 101 _ws = ws;
p07gbar 0:455d5826751b 102 _rxtx = rxtx;
p07gbar 0:455d5826751b 103
p07gbar 0:455d5826751b 104 ws_d = true;
p07gbar 0:455d5826751b 105 clk_d = false;
p07gbar 0:455d5826751b 106 mclk_d = false;
p07gbar 0:455d5826751b 107
p07gbar 0:455d5826751b 108 reg_write_err = 0;
p07gbar 0:455d5826751b 109
p07gbar 0:455d5826751b 110 fourwire = fourwiremode;
p07gbar 0:455d5826751b 111
p07gbar 0:455d5826751b 112 pin_setup();
p07gbar 0:455d5826751b 113
p07gbar 0:455d5826751b 114 if (pin_setup_err != 0) {
p07gbar 0:455d5826751b 115 perror("I2S Pins incorrectly defined.");
p07gbar 0:455d5826751b 116 }
p07gbar 0:455d5826751b 117
p07gbar 0:455d5826751b 118 defaulter();
p07gbar 0:455d5826751b 119 }
p07gbar 0:455d5826751b 120
p07gbar 0:455d5826751b 121 I2S::I2S(bool rxtx, PinName sd, PinName ws)
p07gbar 0:455d5826751b 122 {
p07gbar 0:455d5826751b 123 NVIC_DisableIRQ (I2S_IRQn);
p07gbar 0:455d5826751b 124
p07gbar 0:455d5826751b 125 _sd = sd;
p07gbar 0:455d5826751b 126 _ws = ws;
p07gbar 0:455d5826751b 127 _rxtx = rxtx;
p07gbar 0:455d5826751b 128
p07gbar 0:455d5826751b 129 ws_d = true;
p07gbar 0:455d5826751b 130 clk_d = false;
p07gbar 0:455d5826751b 131 mclk_d = false;
p07gbar 0:455d5826751b 132
p07gbar 0:455d5826751b 133 reg_write_err = 0;
p07gbar 0:455d5826751b 134
p07gbar 0:455d5826751b 135 fourwire = false;
p07gbar 0:455d5826751b 136
p07gbar 0:455d5826751b 137 pin_setup();
p07gbar 0:455d5826751b 138
p07gbar 0:455d5826751b 139 if (pin_setup_err != 0) {
p07gbar 0:455d5826751b 140 perror("I2S Pins incorrectly defined.");
p07gbar 0:455d5826751b 141 }
p07gbar 0:455d5826751b 142
p07gbar 0:455d5826751b 143 defaulter();
p07gbar 0:455d5826751b 144 }
p07gbar 0:455d5826751b 145
p07gbar 0:455d5826751b 146 I2S::~I2S()
p07gbar 0:455d5826751b 147 {
p07gbar 0:455d5826751b 148 NVIC_DisableIRQ (I2S_IRQn);
p07gbar 0:455d5826751b 149 deallocating = true;
p07gbar 0:455d5826751b 150 pin_setup();
p07gbar 0:455d5826751b 151 write_registers();
p07gbar 0:455d5826751b 152 }
p07gbar 0:455d5826751b 153
p07gbar 0:455d5826751b 154 void I2S::defaulter()
p07gbar 0:455d5826751b 155 {
p07gbar 0:455d5826751b 156 LPC_SC->PCONP |= (1 << 27);
p07gbar 0:455d5826751b 157
p07gbar 0:455d5826751b 158 stop();
p07gbar 0:455d5826751b 159 master = false;
p07gbar 0:455d5826751b 160 deallocating = false;
p07gbar 0:455d5826751b 161
p07gbar 0:455d5826751b 162 frequency(I2S_DF_SAMPLERATE);
p07gbar 0:455d5826751b 163 wordsize(I2S_DF_WORDWIDTH);
p07gbar 0:455d5826751b 164 masterslave (I2S_DF_MASTERSLAVE);
p07gbar 0:455d5826751b 165 stereomono (I2S_DF_STEREOMONO);
p07gbar 0:455d5826751b 166 set_interrupt_fifo_level(I2S_DF_INTERRUPT_FIFO_LEVEL);
p07gbar 0:455d5826751b 167 mute (I2S_DF_MUTED);
p07gbar 0:455d5826751b 168
p07gbar 0:455d5826751b 169 NVIC_SetVector(I2S_IRQn, (uint32_t) & _i2sisr);
p07gbar 0:455d5826751b 170 NVIC_EnableIRQ (I2S_IRQn);
p07gbar 0:455d5826751b 171 }
p07gbar 0:455d5826751b 172
p07gbar 0:455d5826751b 173 void I2S::write(char buf[], int len)
p07gbar 0:455d5826751b 174 {
p07gbar 0:455d5826751b 175 if (_rxtx == I2S_TRANSMIT) {
p07gbar 0:455d5826751b 176 if (len > max_fifo_points())
p07gbar 0:455d5826751b 177 len = max_fifo_points();
p07gbar 0:455d5826751b 178 if (len <= 0)
p07gbar 0:455d5826751b 179 return;
p07gbar 0:455d5826751b 180 int temp = 0;
p07gbar 0:455d5826751b 181 for (int i = 0; i < len; i += 4) {
p07gbar 0:455d5826751b 182 temp = 0;
p07gbar 0:455d5826751b 183 for (int j = 0; j < 4; j++) {
p07gbar 0:455d5826751b 184 temp |= int(buf[i + j]) << (j * 8);
p07gbar 0:455d5826751b 185 }
p07gbar 0:455d5826751b 186 LPC_I2S->I2STXFIFO = temp;
p07gbar 0:455d5826751b 187 }
p07gbar 0:455d5826751b 188 }
p07gbar 0:455d5826751b 189
p07gbar 0:455d5826751b 190 }
p07gbar 0:455d5826751b 191
p07gbar 0:455d5826751b 192 void I2S::write(int buf[], int len)
p07gbar 0:455d5826751b 193 {
p07gbar 0:455d5826751b 194 if (_rxtx == I2S_TRANSMIT && wordwidth > 0) {
p07gbar 0:455d5826751b 195 if (len > max_fifo_points()) {
p07gbar 0:455d5826751b 196 len = max_fifo_points();
p07gbar 0:455d5826751b 197 printf("Trying to write too much data!\n\r");
p07gbar 0:455d5826751b 198 }
p07gbar 0:455d5826751b 199 if (len <= 0)
p07gbar 0:455d5826751b 200 return;
p07gbar 0:455d5826751b 201 uint32_t temp = 0;
p07gbar 0:455d5826751b 202 int increment = 32 / wordwidth;
p07gbar 0:455d5826751b 203 unsigned char recast[] =
p07gbar 0:455d5826751b 204 { 0, 0, 0, 0 };
p07gbar 0:455d5826751b 205 for (int i = 0; i < len; i += increment) {
p07gbar 0:455d5826751b 206 temp = 0;
p07gbar 0:455d5826751b 207
p07gbar 0:455d5826751b 208 switch (wordwidth) {
p07gbar 0:455d5826751b 209
p07gbar 0:455d5826751b 210 case 8:
p07gbar 0:455d5826751b 211
p07gbar 0:455d5826751b 212 recast[0] = (int8_t) buf[i + 0];
p07gbar 0:455d5826751b 213 recast[1] = (int8_t) buf[i + 1];
p07gbar 0:455d5826751b 214 recast[2] = (int8_t) buf[i + 2];
p07gbar 0:455d5826751b 215 recast[3] = (int8_t) buf[i + 3];
p07gbar 0:455d5826751b 216 break;
p07gbar 0:455d5826751b 217 case 16:
p07gbar 0:455d5826751b 218 recast[0] = (((int16_t) buf[i + 0]) >> 0) & 0xFF;
p07gbar 0:455d5826751b 219 recast[1] = (((int16_t) buf[i + 0]) >> 8) & 0xFF;
p07gbar 0:455d5826751b 220 recast[2] = (((int16_t) buf[i + 1]) >> 0) & 0xFF;
p07gbar 0:455d5826751b 221 recast[3] = (((int16_t) buf[i + 1]) >> 8) & 0xFF;
p07gbar 0:455d5826751b 222 break;
p07gbar 0:455d5826751b 223 case 32:
p07gbar 0:455d5826751b 224 recast[0] = (((int32_t) buf[i + 0]) >> 0) & 0xFF;
p07gbar 0:455d5826751b 225 recast[1] = (((int32_t) buf[i + 0]) >> 8) & 0xFF;
p07gbar 0:455d5826751b 226 recast[2] = (((int32_t) buf[i + 0]) >> 16) & 0xFF;
p07gbar 0:455d5826751b 227 recast[3] = (((int32_t) buf[i + 0]) >> 24) & 0xFF;
p07gbar 0:455d5826751b 228 break;
p07gbar 0:455d5826751b 229
p07gbar 0:455d5826751b 230 }
p07gbar 0:455d5826751b 231 for (int j = 0; j < 4; j++) {
p07gbar 0:455d5826751b 232
p07gbar 0:455d5826751b 233 temp |= recast[j] << (j * 8);
p07gbar 0:455d5826751b 234 }
p07gbar 0:455d5826751b 235
p07gbar 0:455d5826751b 236 //if(((temp >> 16) & 0xFFFF) == 0xFFFF) printf("Hmmm %x %x %x\n\r",temp, increment,i); //|| temp &0xFFFF == 0xFFFF
p07gbar 0:455d5826751b 237 //if((buf[i]-buf[i+1])>5000 || (buf[i]-buf[i+1])<-5000) printf("J:%i,%i\n\r",buf[i],buf[i+1]);
p07gbar 0:455d5826751b 238 //printf("%x\n",temp);
p07gbar 0:455d5826751b 239 LPC_I2S->I2STXFIFO = temp;
p07gbar 0:455d5826751b 240 }
p07gbar 0:455d5826751b 241 }
p07gbar 0:455d5826751b 242 }
p07gbar 0:455d5826751b 243
p07gbar 0:455d5826751b 244 void I2S::write(int bufr[], int bufl[], int len)
p07gbar 0:455d5826751b 245 {
p07gbar 0:455d5826751b 246 //#TODO: Write this!
p07gbar 0:455d5826751b 247 }
p07gbar 0:455d5826751b 248
p07gbar 0:455d5826751b 249 int I2S::read()
p07gbar 0:455d5826751b 250 {
p07gbar 0:455d5826751b 251 return LPC_I2S->I2SRXFIFO;
p07gbar 0:455d5826751b 252 }
p07gbar 0:455d5826751b 253
p07gbar 0:455d5826751b 254 void I2S::read(char buf[], int len)
p07gbar 0:455d5826751b 255 {
p07gbar 0:455d5826751b 256 bool len_valid = true;
p07gbar 0:455d5826751b 257 if (len <= 0)
p07gbar 0:455d5826751b 258 return;
p07gbar 0:455d5826751b 259 if (len >= fifo_points())
p07gbar 0:455d5826751b 260 len = fifo_points();
p07gbar 0:455d5826751b 261 int temp[8];
p07gbar 0:455d5826751b 262 int counter = 0;
p07gbar 0:455d5826751b 263 int increment = 4; //32/wordwidth;
p07gbar 0:455d5826751b 264 int fifo_levl = fifo_level();
p07gbar 0:455d5826751b 265 while (counter < fifo_levl && len_valid) {
p07gbar 0:455d5826751b 266 temp[counter] = LPC_I2S->I2SRXFIFO;
p07gbar 0:455d5826751b 267 for (int j = 0; j < increment; j++) {
p07gbar 0:455d5826751b 268 if ((counter * 4) + j > len) {
p07gbar 0:455d5826751b 269 len_valid = false;
p07gbar 0:455d5826751b 270 break;
p07gbar 0:455d5826751b 271 }
p07gbar 0:455d5826751b 272 buf[counter + j] = temp[counter] >> (j * 8);
p07gbar 0:455d5826751b 273
p07gbar 0:455d5826751b 274 }
p07gbar 0:455d5826751b 275 counter++;
p07gbar 0:455d5826751b 276 }
p07gbar 0:455d5826751b 277 }
p07gbar 0:455d5826751b 278
p07gbar 0:455d5826751b 279 void I2S::read(int buf[], int len)
p07gbar 0:455d5826751b 280 {
p07gbar 0:455d5826751b 281 bool len_valid = true;
p07gbar 0:455d5826751b 282 if (len <= 0)
p07gbar 0:455d5826751b 283 return;
p07gbar 0:455d5826751b 284 if (len >= fifo_points())
p07gbar 0:455d5826751b 285 len = fifo_points();
p07gbar 0:455d5826751b 286 int temp[8];
p07gbar 0:455d5826751b 287 int counter = 0;
p07gbar 0:455d5826751b 288 int increment = 32 / wordwidth;
p07gbar 0:455d5826751b 289 int fifo_levl = fifo_level();
p07gbar 0:455d5826751b 290 while (counter < fifo_levl && len_valid) {
p07gbar 0:455d5826751b 291 temp[counter] = LPC_I2S->I2SRXFIFO;
p07gbar 0:455d5826751b 292 for (int j = 0; j < increment; j++) {
p07gbar 0:455d5826751b 293 if ((counter * increment) + j > len) {
p07gbar 0:455d5826751b 294 len_valid = false;
p07gbar 0:455d5826751b 295 break;
p07gbar 0:455d5826751b 296 }
p07gbar 0:455d5826751b 297 buf[counter + j] = temp[counter] >> (j * wordwidth);
p07gbar 0:455d5826751b 298
p07gbar 0:455d5826751b 299 }
p07gbar 0:455d5826751b 300 counter++;
p07gbar 0:455d5826751b 301 }
p07gbar 0:455d5826751b 302 }
p07gbar 0:455d5826751b 303
p07gbar 0:455d5826751b 304 void I2S::read(int bufr[], int bufl[], int len)
p07gbar 0:455d5826751b 305 {
p07gbar 0:455d5826751b 306 //#TODO: Write this
p07gbar 0:455d5826751b 307 }
p07gbar 0:455d5826751b 308
p07gbar 0:455d5826751b 309 int I2S::max_fifo_points()
p07gbar 0:455d5826751b 310 {
p07gbar 0:455d5826751b 311 switch (wordwidth) {
p07gbar 0:455d5826751b 312 case 8:
p07gbar 0:455d5826751b 313 return (4 * 8);
p07gbar 0:455d5826751b 314 case 16:
p07gbar 0:455d5826751b 315 return (2 * 8);
p07gbar 0:455d5826751b 316 case 32:
p07gbar 0:455d5826751b 317 return 8;
p07gbar 0:455d5826751b 318 default:
p07gbar 0:455d5826751b 319 return 0;
p07gbar 0:455d5826751b 320 }
p07gbar 0:455d5826751b 321 }
p07gbar 0:455d5826751b 322
p07gbar 0:455d5826751b 323 int I2S::fifo_points()
p07gbar 0:455d5826751b 324 {
p07gbar 0:455d5826751b 325 switch (wordwidth) {
p07gbar 0:455d5826751b 326 case 8:
p07gbar 0:455d5826751b 327 return (4 * fifo_level());
p07gbar 0:455d5826751b 328 case 16:
p07gbar 0:455d5826751b 329 return (2 * fifo_level());
p07gbar 0:455d5826751b 330 case 32:
p07gbar 0:455d5826751b 331 return fifo_level();
p07gbar 0:455d5826751b 332 default:
p07gbar 0:455d5826751b 333 return 0;
p07gbar 0:455d5826751b 334 }
p07gbar 0:455d5826751b 335 }
p07gbar 0:455d5826751b 336
p07gbar 0:455d5826751b 337 void I2S::power(bool pwr)
p07gbar 0:455d5826751b 338 {
p07gbar 0:455d5826751b 339 if (pwr) {
p07gbar 0:455d5826751b 340 stopped = false;
p07gbar 0:455d5826751b 341 } else {
p07gbar 0:455d5826751b 342 stopped = true;
p07gbar 0:455d5826751b 343 }
p07gbar 0:455d5826751b 344 write_registers();
p07gbar 0:455d5826751b 345 }
p07gbar 0:455d5826751b 346
p07gbar 0:455d5826751b 347 void I2S::masterslave(bool mastermode)
p07gbar 0:455d5826751b 348 {
p07gbar 0:455d5826751b 349 if (mastermode == I2S_MASTER) {
p07gbar 0:455d5826751b 350 master = true;
p07gbar 0:455d5826751b 351 } else {
p07gbar 0:455d5826751b 352 master = false;
p07gbar 0:455d5826751b 353 }
p07gbar 0:455d5826751b 354 write_registers();
p07gbar 0:455d5826751b 355 }
p07gbar 0:455d5826751b 356
p07gbar 0:455d5826751b 357 void I2S::wordsize(int words)
p07gbar 0:455d5826751b 358 {
p07gbar 0:455d5826751b 359 wordwidth = words;
p07gbar 0:455d5826751b 360 write_registers();
p07gbar 0:455d5826751b 361 }
p07gbar 0:455d5826751b 362
p07gbar 0:455d5826751b 363 void I2S::mclk_freq(int freq)
p07gbar 0:455d5826751b 364 {
p07gbar 0:455d5826751b 365 mclk_frequency = freq;
p07gbar 0:455d5826751b 366 write_registers();
p07gbar 0:455d5826751b 367 }
p07gbar 0:455d5826751b 368
p07gbar 0:455d5826751b 369 void I2S::frequency(int desired_freq)
p07gbar 0:455d5826751b 370 {
p07gbar 0:455d5826751b 371 freq = desired_freq;
p07gbar 0:455d5826751b 372 write_registers();
p07gbar 0:455d5826751b 373 }
p07gbar 0:455d5826751b 374
p07gbar 0:455d5826751b 375 int I2S::fifo_level()
p07gbar 0:455d5826751b 376 {
p07gbar 0:455d5826751b 377 int level = 0;
p07gbar 0:455d5826751b 378 if (_rxtx == I2S_TRANSMIT) {
p07gbar 0:455d5826751b 379 level = LPC_I2S->I2SSTATE;
p07gbar 0:455d5826751b 380 level >>= 16;
p07gbar 0:455d5826751b 381 level &= 0xF;
p07gbar 0:455d5826751b 382 } else {
p07gbar 0:455d5826751b 383 level = LPC_I2S->I2SSTATE;
p07gbar 0:455d5826751b 384 level >>= 8;
p07gbar 0:455d5826751b 385 level &= 0xF;
p07gbar 0:455d5826751b 386 }
p07gbar 0:455d5826751b 387 return level;
p07gbar 0:455d5826751b 388 }
p07gbar 0:455d5826751b 389
p07gbar 0:455d5826751b 390 void I2S::stereomono(bool stereomode)
p07gbar 0:455d5826751b 391 {
p07gbar 0:455d5826751b 392 if (stereomode == I2S_STEREO) {
p07gbar 0:455d5826751b 393 stereo = true;
p07gbar 0:455d5826751b 394 } else {
p07gbar 0:455d5826751b 395 stereo = false;
p07gbar 0:455d5826751b 396 }
p07gbar 0:455d5826751b 397 }
p07gbar 0:455d5826751b 398
p07gbar 0:455d5826751b 399 void I2S::mute()
p07gbar 0:455d5826751b 400 {
p07gbar 0:455d5826751b 401 muted = true;
p07gbar 0:455d5826751b 402 write_registers();
p07gbar 0:455d5826751b 403 }
p07gbar 0:455d5826751b 404
p07gbar 0:455d5826751b 405 void I2S::mute(bool mute_en)
p07gbar 0:455d5826751b 406 {
p07gbar 0:455d5826751b 407 muted = mute_en;
p07gbar 0:455d5826751b 408 write_registers();
p07gbar 0:455d5826751b 409 }
p07gbar 0:455d5826751b 410
p07gbar 0:455d5826751b 411 void I2S::stop()
p07gbar 0:455d5826751b 412 {
p07gbar 0:455d5826751b 413 stopped = true;
p07gbar 0:455d5826751b 414 write_registers();
p07gbar 0:455d5826751b 415 }
p07gbar 0:455d5826751b 416
p07gbar 0:455d5826751b 417 void I2S::set_interrupt_fifo_level(int level)
p07gbar 0:455d5826751b 418 {
p07gbar 0:455d5826751b 419 interrupt_fifo_level = level;
p07gbar 0:455d5826751b 420 write_registers();
p07gbar 0:455d5826751b 421 }
p07gbar 0:455d5826751b 422
p07gbar 0:455d5826751b 423 void I2S::start()
p07gbar 0:455d5826751b 424 {
p07gbar 0:455d5826751b 425 stopped = false;
p07gbar 0:455d5826751b 426 muted = false;
p07gbar 0:455d5826751b 427 write_registers();
p07gbar 0:455d5826751b 428 }
p07gbar 0:455d5826751b 429
p07gbar 0:455d5826751b 430 bool I2S::setup_ok()
p07gbar 0:455d5826751b 431 {
p07gbar 0:455d5826751b 432 if ((reg_write_err + pin_setup_err) > 0)
p07gbar 0:455d5826751b 433 return false;
p07gbar 0:455d5826751b 434 else
p07gbar 0:455d5826751b 435 return true;
p07gbar 0:455d5826751b 436 }
p07gbar 0:455d5826751b 437
p07gbar 0:455d5826751b 438 void I2S::pin_setup()
p07gbar 0:455d5826751b 439 {
p07gbar 0:455d5826751b 440 pin_setup_err = 0;
p07gbar 0:455d5826751b 441
p07gbar 0:455d5826751b 442 if (_rxtx == I2S_TRANSMIT) {
p07gbar 0:455d5826751b 443 printf("\n\rSetting up pins....\n\r");
p07gbar 0:455d5826751b 444 if (_sd != p5)
p07gbar 0:455d5826751b 445 pin_setup_err++;
p07gbar 0:455d5826751b 446 if (_ws != p6 && ws_d == true)
p07gbar 0:455d5826751b 447 pin_setup_err++;
p07gbar 0:455d5826751b 448 if (_clk != p7 && clk_d == true)
p07gbar 0:455d5826751b 449 pin_setup_err++;
p07gbar 0:455d5826751b 450 printf("Hmm....%i\n\r", pin_setup_err);
p07gbar 0:455d5826751b 451 } else {
p07gbar 0:455d5826751b 452 if (_sd != p17 && _sd != p8)
p07gbar 0:455d5826751b 453 pin_setup_err++;
p07gbar 0:455d5826751b 454 if (_ws != p16 && _ws != p29 && ws_d == true)
p07gbar 0:455d5826751b 455 pin_setup_err++;
p07gbar 0:455d5826751b 456 if (_clk != p15 && _clk != p30 && clk_d == true)
p07gbar 0:455d5826751b 457 pin_setup_err++;
p07gbar 0:455d5826751b 458 }
p07gbar 0:455d5826751b 459
p07gbar 0:455d5826751b 460 if (pin_setup_err == 0) {
p07gbar 0:455d5826751b 461 if (_rxtx == I2S_TRANSMIT) {
p07gbar 0:455d5826751b 462 int val1 = 1;
p07gbar 0:455d5826751b 463 if (deallocating) {
p07gbar 0:455d5826751b 464 val1 = 0;
p07gbar 0:455d5826751b 465 }
p07gbar 0:455d5826751b 466 LPC_PINCON->PINSEL0 |= (val1 << 18); //set p5 as transmit serial data line
p07gbar 0:455d5826751b 467 if (ws_d == true)
p07gbar 0:455d5826751b 468 LPC_PINCON->PINSEL0 |= (val1 << 14); //set p7 as transmit clock line
p07gbar 0:455d5826751b 469 if (clk_d == true)
p07gbar 0:455d5826751b 470 LPC_PINCON->PINSEL0 |= (val1 << 16); //set p6 as word select line
p07gbar 0:455d5826751b 471
p07gbar 0:455d5826751b 472 } else {
p07gbar 0:455d5826751b 473 int val1 = 1;
p07gbar 0:455d5826751b 474 int val2 = 2;
p07gbar 0:455d5826751b 475 if (deallocating) {
p07gbar 0:455d5826751b 476 val1 = 0;
p07gbar 0:455d5826751b 477 val2 = 0;
p07gbar 0:455d5826751b 478 }
p07gbar 0:455d5826751b 479
p07gbar 0:455d5826751b 480 if (_sd == p8)
p07gbar 0:455d5826751b 481 LPC_PINCON->PINSEL0 |= (val1 << 12);
p07gbar 0:455d5826751b 482 else
p07gbar 0:455d5826751b 483 LPC_PINCON->PINSEL1 |= (val2 << 18);
p07gbar 0:455d5826751b 484
p07gbar 0:455d5826751b 485 if (ws_d == true) {
p07gbar 0:455d5826751b 486 if (_ws == p29)
p07gbar 0:455d5826751b 487 LPC_PINCON->PINSEL0 |= (val1 << 10);
p07gbar 0:455d5826751b 488 else
p07gbar 0:455d5826751b 489 LPC_PINCON->PINSEL1 |= (val2 << 16);
p07gbar 0:455d5826751b 490 }
p07gbar 0:455d5826751b 491
p07gbar 0:455d5826751b 492 if (clk_d == true) {
4180_1 1:58bbfaf58a7b 493
4180_1 1:58bbfaf58a7b 494 //
4180_1 1:58bbfaf58a7b 495 //I2S library patch 1/25/18 for typo to get input clock to work!
4180_1 1:58bbfaf58a7b 496 //patch "==" was changed to "!=" in if cond below to get I2S rx clock on correct pin
4180_1 1:58bbfaf58a7b 497 //
4180_1 1:58bbfaf58a7b 498 if (_clk != p15)
p07gbar 0:455d5826751b 499 LPC_PINCON->PINSEL0 |= (val1 << 8);
p07gbar 0:455d5826751b 500 else
p07gbar 0:455d5826751b 501 LPC_PINCON->PINSEL1 |= (val2 << 14);
p07gbar 0:455d5826751b 502 }
p07gbar 0:455d5826751b 503 }
p07gbar 0:455d5826751b 504 }
p07gbar 0:455d5826751b 505 }
p07gbar 0:455d5826751b 506
p07gbar 0:455d5826751b 507 void I2S::write_registers()
p07gbar 0:455d5826751b 508 {
p07gbar 0:455d5826751b 509 reg_write_err = 0;
p07gbar 0:455d5826751b 510 //Clock Multiplier Calculations
p07gbar 0:455d5826751b 511 float pre_mult = 0;
p07gbar 0:455d5826751b 512 int pre_num = 0;
p07gbar 0:455d5826751b 513 int pre_den = 0;
p07gbar 0:455d5826751b 514 int bitrate_div = 0;
p07gbar 0:455d5826751b 515 if (master == true) { // In the hope of not doing all this heavy lifting every configuration
p07gbar 0:455d5826751b 516 //printf("Doing some clock magic..\n\r");
p07gbar 0:455d5826751b 517 int bitrate = freq * 64;
p07gbar 0:455d5826751b 518 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
p07gbar 0:455d5826751b 519 if (mclk_frequency == 0) {
p07gbar 0:455d5826751b 520 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
p07gbar 0:455d5826751b 521 bitrate_div = int(target_div - rnd);
p07gbar 0:455d5826751b 522 while (bitrate_div > I2S_MAX_BITRATE_DIV) { // But this might be out of range, so we right shift it into focus
p07gbar 0:455d5826751b 523 bitrate_div >>= 1;
p07gbar 0:455d5826751b 524 }
p07gbar 0:455d5826751b 525 if (bitrate_div == 0) { // Could be zero, which would disable the the clock...
p07gbar 0:455d5826751b 526 bitrate_div = 1;
p07gbar 0:455d5826751b 527 }
p07gbar 0:455d5826751b 528 pre_mult = float(bitrate_div) / target_div; // Work out what we have left to correct
p07gbar 0:455d5826751b 529 pre_num = 0;
p07gbar 0:455d5826751b 530 pre_den = 0;
p07gbar 0:455d5826751b 531 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
p07gbar 0:455d5826751b 532
p07gbar 0:455d5826751b 533 } else {
p07gbar 0:455d5826751b 534 pre_mult = float(mclk_frequency * 2) / (I2S_PCLK_RATE);
p07gbar 0:455d5826751b 535 pre_num = 0;
p07gbar 0:455d5826751b 536 pre_den = 0;
p07gbar 0:455d5826751b 537 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
p07gbar 0:455d5826751b 538 bitrate_div = int(
p07gbar 0:455d5826751b 539 I2S_PCLK_RATE * float(pre_num) / float(pre_den)
p07gbar 0:455d5826751b 540 / float(bitrate));
p07gbar 0:455d5826751b 541 }
p07gbar 0:455d5826751b 542
p07gbar 0:455d5826751b 543 old_freq = freq;
p07gbar 0:455d5826751b 544 old_pre_num = pre_num;
p07gbar 0:455d5826751b 545 old_pre_den = pre_den;
p07gbar 0:455d5826751b 546 old_bitrate_div = bitrate_div;
p07gbar 0:455d5826751b 547 } else {
p07gbar 0:455d5826751b 548 pre_num = old_pre_num;
p07gbar 0:455d5826751b 549 pre_den = old_pre_den;
p07gbar 0:455d5826751b 550 bitrate_div = old_bitrate_div;
p07gbar 0:455d5826751b 551 }
p07gbar 0:455d5826751b 552
p07gbar 0:455d5826751b 553 //Clock Multiplier, MCLK setup
p07gbar 0:455d5826751b 554 if (_rxtx == I2S_TRANSMIT) {
p07gbar 0:455d5826751b 555 int regvals = ((pre_num << 8) & 0xFF00) | (pre_den & 0xFF);
p07gbar 0:455d5826751b 556 LPC_I2S->I2STXRATE = regvals; // Setting the X/Y fraction
p07gbar 0:455d5826751b 557 LPC_I2S->I2STXBITRATE = (bitrate_div - 1) & 0x3F;// Setting up the bitrate divider, the periferal adds one to this
p07gbar 0:455d5826751b 558
p07gbar 0:455d5826751b 559 LPC_I2S->I2STXMODE = fourwire << 2;
p07gbar 0:455d5826751b 560
p07gbar 0:455d5826751b 561 if (mclk_d == true) {
p07gbar 0:455d5826751b 562 LPC_I2S->I2STXMODE |= (1 << 3);
p07gbar 0:455d5826751b 563 }
p07gbar 0:455d5826751b 564 } else {
p07gbar 0:455d5826751b 565 int regvals = ((pre_num << 8) & 0xFF00) | (pre_den & 0xFF);
p07gbar 0:455d5826751b 566 LPC_I2S->I2SRXRATE = regvals; // Setting the X/Y fraction
p07gbar 0:455d5826751b 567 LPC_I2S->I2SRXBITRATE = (bitrate_div - 1) & 0x3F;// Setting up the bitrate divider, the periferal adds one to this
p07gbar 0:455d5826751b 568
p07gbar 0:455d5826751b 569 LPC_I2S->I2SRXMODE = fourwire << 2;
p07gbar 0:455d5826751b 570
p07gbar 0:455d5826751b 571 if (mclk_d == true) {
p07gbar 0:455d5826751b 572 LPC_I2S->I2SRXMODE |= (1 << 3);
p07gbar 0:455d5826751b 573 }
p07gbar 0:455d5826751b 574 }
p07gbar 0:455d5826751b 575
p07gbar 0:455d5826751b 576 switch (wordwidth) {
p07gbar 0:455d5826751b 577 case 8:
p07gbar 0:455d5826751b 578 wordwidth_code = 0;
p07gbar 0:455d5826751b 579 break;
p07gbar 0:455d5826751b 580 case 16:
p07gbar 0:455d5826751b 581 wordwidth_code = 1;
p07gbar 0:455d5826751b 582 break;
p07gbar 0:455d5826751b 583 case 32:
p07gbar 0:455d5826751b 584 wordwidth_code = 3;
p07gbar 0:455d5826751b 585 break;
p07gbar 0:455d5826751b 586 default:
p07gbar 0:455d5826751b 587 reg_write_err++;
p07gbar 0:455d5826751b 588 break;
p07gbar 0:455d5826751b 589 }
p07gbar 0:455d5826751b 590
p07gbar 0:455d5826751b 591 int I2SDA_reg = (wordwidth_code & 0x3);
p07gbar 0:455d5826751b 592 I2SDA_reg |= ((!stereo << 2) & 0x4);
p07gbar 0:455d5826751b 593 I2SDA_reg |= ((stopped << 3) & 0x8);
p07gbar 0:455d5826751b 594 I2SDA_reg |= ((!master << 5) & 0x20);
p07gbar 0:455d5826751b 595 I2SDA_reg |= (0x1F << 6);
p07gbar 0:455d5826751b 596 I2SDA_reg |= ((muted << 15) & 0x8000);
p07gbar 0:455d5826751b 597
p07gbar 0:455d5826751b 598 if (_rxtx == I2S_TRANSMIT) {
p07gbar 0:455d5826751b 599 LPC_I2S->I2SDAO = I2SDA_reg;
p07gbar 0:455d5826751b 600 } else {
p07gbar 0:455d5826751b 601 LPC_I2S->I2SDAI = I2SDA_reg;
p07gbar 0:455d5826751b 602 }
p07gbar 0:455d5826751b 603
p07gbar 0:455d5826751b 604 if (_rxtx == I2S_TRANSMIT) {
p07gbar 0:455d5826751b 605 if (txisr) {
p07gbar 0:455d5826751b 606 LPC_I2S->I2SIRQ = (LPC_I2S->I2SIRQ & 0xFF0FFFFF)
p07gbar 0:455d5826751b 607 | ((interrupt_fifo_level & 0xF) << 16);
p07gbar 0:455d5826751b 608 LPC_I2S->I2SIRQ |= 0x2;
p07gbar 0:455d5826751b 609 } else {
p07gbar 0:455d5826751b 610 LPC_I2S->I2SIRQ &= 0xFFFFFFFD;
p07gbar 0:455d5826751b 611 }
p07gbar 0:455d5826751b 612 } else {
p07gbar 0:455d5826751b 613 if (rxisr) {
p07gbar 0:455d5826751b 614 LPC_I2S->I2SIRQ = (LPC_I2S->I2SIRQ & 0xFFFFF0FF)
p07gbar 0:455d5826751b 615 | ((interrupt_fifo_level & 0xF) << 8);
p07gbar 0:455d5826751b 616 LPC_I2S->I2SIRQ |= 0x1;
p07gbar 0:455d5826751b 617 }
p07gbar 0:455d5826751b 618
p07gbar 0:455d5826751b 619 else {
p07gbar 0:455d5826751b 620 LPC_I2S->I2SIRQ &= 0xFFFFFFFE;
p07gbar 0:455d5826751b 621 }
p07gbar 0:455d5826751b 622 }
p07gbar 0:455d5826751b 623 }
p07gbar 0:455d5826751b 624
p07gbar 0:455d5826751b 625 void I2S::_i2sisr(void)
p07gbar 0:455d5826751b 626 {
p07gbar 0:455d5826751b 627 I2STXISR.call();
p07gbar 0:455d5826751b 628 I2SRXISR.call();
p07gbar 0:455d5826751b 629 }
p07gbar 0:455d5826751b 630
p07gbar 0:455d5826751b 631 // A function to find the nearest fraction to that put to it, with numerator and denomnator less than 256
p07gbar 0:455d5826751b 632 // This is used when trying to get the clocks correct
p07gbar 0:455d5826751b 633
p07gbar 0:455d5826751b 634 void I2S::fraction_estimator(float in, int * num, int * den)
p07gbar 0:455d5826751b 635 {
p07gbar 0:455d5826751b 636 int test_num = 0;
p07gbar 0:455d5826751b 637 int test_den = 0;
p07gbar 0:455d5826751b 638 float least_error = 1;
p07gbar 0:455d5826751b 639 int least_err_den = 0;
p07gbar 0:455d5826751b 640 float genval;
p07gbar 0:455d5826751b 641 float generr;
p07gbar 0:455d5826751b 642
p07gbar 0:455d5826751b 643 for (test_den = 1; test_den < I2S_MAX_DENOMINATOR; test_den++) {
p07gbar 0:455d5826751b 644 test_num = int(float(test_den) * in);
p07gbar 0:455d5826751b 645 if (test_num < I2S_MAX_NUMERATOR && test_num > 0) {
p07gbar 0:455d5826751b 646 genval = float(test_num) / float(test_den);
p07gbar 0:455d5826751b 647 generr = mod(genval - in);
p07gbar 0:455d5826751b 648 if (generr < least_error) {
p07gbar 0:455d5826751b 649 least_error = generr;
p07gbar 0:455d5826751b 650 least_err_den = test_den;
p07gbar 0:455d5826751b 651 }
p07gbar 0:455d5826751b 652 if (generr == 0) {
p07gbar 0:455d5826751b 653 break;
p07gbar 0:455d5826751b 654 }
p07gbar 0:455d5826751b 655 }
p07gbar 0:455d5826751b 656 }
p07gbar 0:455d5826751b 657
p07gbar 0:455d5826751b 658 test_num = int(float(least_err_den) * in);
p07gbar 0:455d5826751b 659 *num = test_num;
p07gbar 0:455d5826751b 660 *den = least_err_den;
p07gbar 0:455d5826751b 661
p07gbar 0:455d5826751b 662 }
p07gbar 0:455d5826751b 663
p07gbar 0:455d5826751b 664 float I2S::mod(float in)
p07gbar 0:455d5826751b 665 {
p07gbar 0:455d5826751b 666 if (in < 0)
p07gbar 0:455d5826751b 667 in *= -1;
p07gbar 0:455d5826751b 668
p07gbar 0:455d5826751b 669 return in;
p07gbar 0:455d5826751b 670 }