Adapted to work with the LPC4088 Experiment Base Board

Dependents:   lpc4088_ebb_ptp Algorithm-testing

Fork of I2S by Giles Barton-Owen

Committer:
p07gbar
Date:
Wed Sep 19 10:53:33 2012 +0000
Revision:
0:455d5826751b
Child:
1:af579d286498
Working fairly stably with read/write 16/32 tx/rx

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) {
p07gbar 0:455d5826751b 493 if (_clk == p15)
p07gbar 0:455d5826751b 494 LPC_PINCON->PINSEL0 |= (val1 << 8);
p07gbar 0:455d5826751b 495 else
p07gbar 0:455d5826751b 496 LPC_PINCON->PINSEL1 |= (val2 << 14);
p07gbar 0:455d5826751b 497 }
p07gbar 0:455d5826751b 498 }
p07gbar 0:455d5826751b 499 }
p07gbar 0:455d5826751b 500 }
p07gbar 0:455d5826751b 501
p07gbar 0:455d5826751b 502 void I2S::write_registers()
p07gbar 0:455d5826751b 503 {
p07gbar 0:455d5826751b 504 reg_write_err = 0;
p07gbar 0:455d5826751b 505 //Clock Multiplier Calculations
p07gbar 0:455d5826751b 506 float pre_mult = 0;
p07gbar 0:455d5826751b 507 int pre_num = 0;
p07gbar 0:455d5826751b 508 int pre_den = 0;
p07gbar 0:455d5826751b 509 int bitrate_div = 0;
p07gbar 0:455d5826751b 510 if (master == true) { // In the hope of not doing all this heavy lifting every configuration
p07gbar 0:455d5826751b 511 //printf("Doing some clock magic..\n\r");
p07gbar 0:455d5826751b 512 int bitrate = freq * 64;
p07gbar 0:455d5826751b 513 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 514 if (mclk_frequency == 0) {
p07gbar 0:455d5826751b 515 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 516 bitrate_div = int(target_div - rnd);
p07gbar 0:455d5826751b 517 while (bitrate_div > I2S_MAX_BITRATE_DIV) { // But this might be out of range, so we right shift it into focus
p07gbar 0:455d5826751b 518 bitrate_div >>= 1;
p07gbar 0:455d5826751b 519 }
p07gbar 0:455d5826751b 520 if (bitrate_div == 0) { // Could be zero, which would disable the the clock...
p07gbar 0:455d5826751b 521 bitrate_div = 1;
p07gbar 0:455d5826751b 522 }
p07gbar 0:455d5826751b 523 pre_mult = float(bitrate_div) / target_div; // Work out what we have left to correct
p07gbar 0:455d5826751b 524 pre_num = 0;
p07gbar 0:455d5826751b 525 pre_den = 0;
p07gbar 0:455d5826751b 526 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 527
p07gbar 0:455d5826751b 528 } else {
p07gbar 0:455d5826751b 529 pre_mult = float(mclk_frequency * 2) / (I2S_PCLK_RATE);
p07gbar 0:455d5826751b 530 pre_num = 0;
p07gbar 0:455d5826751b 531 pre_den = 0;
p07gbar 0:455d5826751b 532 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 533 bitrate_div = int(
p07gbar 0:455d5826751b 534 I2S_PCLK_RATE * float(pre_num) / float(pre_den)
p07gbar 0:455d5826751b 535 / float(bitrate));
p07gbar 0:455d5826751b 536 }
p07gbar 0:455d5826751b 537
p07gbar 0:455d5826751b 538 old_freq = freq;
p07gbar 0:455d5826751b 539 old_pre_num = pre_num;
p07gbar 0:455d5826751b 540 old_pre_den = pre_den;
p07gbar 0:455d5826751b 541 old_bitrate_div = bitrate_div;
p07gbar 0:455d5826751b 542 } else {
p07gbar 0:455d5826751b 543 pre_num = old_pre_num;
p07gbar 0:455d5826751b 544 pre_den = old_pre_den;
p07gbar 0:455d5826751b 545 bitrate_div = old_bitrate_div;
p07gbar 0:455d5826751b 546 }
p07gbar 0:455d5826751b 547
p07gbar 0:455d5826751b 548 //Clock Multiplier, MCLK setup
p07gbar 0:455d5826751b 549 if (_rxtx == I2S_TRANSMIT) {
p07gbar 0:455d5826751b 550 int regvals = ((pre_num << 8) & 0xFF00) | (pre_den & 0xFF);
p07gbar 0:455d5826751b 551 LPC_I2S->I2STXRATE = regvals; // Setting the X/Y fraction
p07gbar 0:455d5826751b 552 LPC_I2S->I2STXBITRATE = (bitrate_div - 1) & 0x3F;// Setting up the bitrate divider, the periferal adds one to this
p07gbar 0:455d5826751b 553
p07gbar 0:455d5826751b 554 LPC_I2S->I2STXMODE = fourwire << 2;
p07gbar 0:455d5826751b 555
p07gbar 0:455d5826751b 556 if (mclk_d == true) {
p07gbar 0:455d5826751b 557 LPC_I2S->I2STXMODE |= (1 << 3);
p07gbar 0:455d5826751b 558 }
p07gbar 0:455d5826751b 559 } else {
p07gbar 0:455d5826751b 560 int regvals = ((pre_num << 8) & 0xFF00) | (pre_den & 0xFF);
p07gbar 0:455d5826751b 561 LPC_I2S->I2SRXRATE = regvals; // Setting the X/Y fraction
p07gbar 0:455d5826751b 562 LPC_I2S->I2SRXBITRATE = (bitrate_div - 1) & 0x3F;// Setting up the bitrate divider, the periferal adds one to this
p07gbar 0:455d5826751b 563
p07gbar 0:455d5826751b 564 LPC_I2S->I2SRXMODE = fourwire << 2;
p07gbar 0:455d5826751b 565
p07gbar 0:455d5826751b 566 if (mclk_d == true) {
p07gbar 0:455d5826751b 567 LPC_I2S->I2SRXMODE |= (1 << 3);
p07gbar 0:455d5826751b 568 }
p07gbar 0:455d5826751b 569 }
p07gbar 0:455d5826751b 570
p07gbar 0:455d5826751b 571 switch (wordwidth) {
p07gbar 0:455d5826751b 572 case 8:
p07gbar 0:455d5826751b 573 wordwidth_code = 0;
p07gbar 0:455d5826751b 574 break;
p07gbar 0:455d5826751b 575 case 16:
p07gbar 0:455d5826751b 576 wordwidth_code = 1;
p07gbar 0:455d5826751b 577 break;
p07gbar 0:455d5826751b 578 case 32:
p07gbar 0:455d5826751b 579 wordwidth_code = 3;
p07gbar 0:455d5826751b 580 break;
p07gbar 0:455d5826751b 581 default:
p07gbar 0:455d5826751b 582 reg_write_err++;
p07gbar 0:455d5826751b 583 break;
p07gbar 0:455d5826751b 584 }
p07gbar 0:455d5826751b 585
p07gbar 0:455d5826751b 586 int I2SDA_reg = (wordwidth_code & 0x3);
p07gbar 0:455d5826751b 587 I2SDA_reg |= ((!stereo << 2) & 0x4);
p07gbar 0:455d5826751b 588 I2SDA_reg |= ((stopped << 3) & 0x8);
p07gbar 0:455d5826751b 589 I2SDA_reg |= ((!master << 5) & 0x20);
p07gbar 0:455d5826751b 590 I2SDA_reg |= (0x1F << 6);
p07gbar 0:455d5826751b 591 I2SDA_reg |= ((muted << 15) & 0x8000);
p07gbar 0:455d5826751b 592
p07gbar 0:455d5826751b 593 if (_rxtx == I2S_TRANSMIT) {
p07gbar 0:455d5826751b 594 LPC_I2S->I2SDAO = I2SDA_reg;
p07gbar 0:455d5826751b 595 } else {
p07gbar 0:455d5826751b 596 LPC_I2S->I2SDAI = I2SDA_reg;
p07gbar 0:455d5826751b 597 }
p07gbar 0:455d5826751b 598
p07gbar 0:455d5826751b 599 if (_rxtx == I2S_TRANSMIT) {
p07gbar 0:455d5826751b 600 if (txisr) {
p07gbar 0:455d5826751b 601 LPC_I2S->I2SIRQ = (LPC_I2S->I2SIRQ & 0xFF0FFFFF)
p07gbar 0:455d5826751b 602 | ((interrupt_fifo_level & 0xF) << 16);
p07gbar 0:455d5826751b 603 LPC_I2S->I2SIRQ |= 0x2;
p07gbar 0:455d5826751b 604 } else {
p07gbar 0:455d5826751b 605 LPC_I2S->I2SIRQ &= 0xFFFFFFFD;
p07gbar 0:455d5826751b 606 }
p07gbar 0:455d5826751b 607 } else {
p07gbar 0:455d5826751b 608 if (rxisr) {
p07gbar 0:455d5826751b 609 LPC_I2S->I2SIRQ = (LPC_I2S->I2SIRQ & 0xFFFFF0FF)
p07gbar 0:455d5826751b 610 | ((interrupt_fifo_level & 0xF) << 8);
p07gbar 0:455d5826751b 611 LPC_I2S->I2SIRQ |= 0x1;
p07gbar 0:455d5826751b 612 }
p07gbar 0:455d5826751b 613
p07gbar 0:455d5826751b 614 else {
p07gbar 0:455d5826751b 615 LPC_I2S->I2SIRQ &= 0xFFFFFFFE;
p07gbar 0:455d5826751b 616 }
p07gbar 0:455d5826751b 617 }
p07gbar 0:455d5826751b 618 }
p07gbar 0:455d5826751b 619
p07gbar 0:455d5826751b 620 void I2S::_i2sisr(void)
p07gbar 0:455d5826751b 621 {
p07gbar 0:455d5826751b 622 I2STXISR.call();
p07gbar 0:455d5826751b 623 I2SRXISR.call();
p07gbar 0:455d5826751b 624 }
p07gbar 0:455d5826751b 625
p07gbar 0:455d5826751b 626 // A function to find the nearest fraction to that put to it, with numerator and denomnator less than 256
p07gbar 0:455d5826751b 627 // This is used when trying to get the clocks correct
p07gbar 0:455d5826751b 628
p07gbar 0:455d5826751b 629 void I2S::fraction_estimator(float in, int * num, int * den)
p07gbar 0:455d5826751b 630 {
p07gbar 0:455d5826751b 631 int test_num = 0;
p07gbar 0:455d5826751b 632 int test_den = 0;
p07gbar 0:455d5826751b 633 float least_error = 1;
p07gbar 0:455d5826751b 634 int least_err_den = 0;
p07gbar 0:455d5826751b 635 float genval;
p07gbar 0:455d5826751b 636 float generr;
p07gbar 0:455d5826751b 637
p07gbar 0:455d5826751b 638 for (test_den = 1; test_den < I2S_MAX_DENOMINATOR; test_den++) {
p07gbar 0:455d5826751b 639 test_num = int(float(test_den) * in);
p07gbar 0:455d5826751b 640 if (test_num < I2S_MAX_NUMERATOR && test_num > 0) {
p07gbar 0:455d5826751b 641 genval = float(test_num) / float(test_den);
p07gbar 0:455d5826751b 642 generr = mod(genval - in);
p07gbar 0:455d5826751b 643 if (generr < least_error) {
p07gbar 0:455d5826751b 644 least_error = generr;
p07gbar 0:455d5826751b 645 least_err_den = test_den;
p07gbar 0:455d5826751b 646 }
p07gbar 0:455d5826751b 647 if (generr == 0) {
p07gbar 0:455d5826751b 648 break;
p07gbar 0:455d5826751b 649 }
p07gbar 0:455d5826751b 650 }
p07gbar 0:455d5826751b 651 }
p07gbar 0:455d5826751b 652
p07gbar 0:455d5826751b 653 test_num = int(float(least_err_den) * in);
p07gbar 0:455d5826751b 654 *num = test_num;
p07gbar 0:455d5826751b 655 *den = least_err_den;
p07gbar 0:455d5826751b 656
p07gbar 0:455d5826751b 657 }
p07gbar 0:455d5826751b 658
p07gbar 0:455d5826751b 659 float I2S::mod(float in)
p07gbar 0:455d5826751b 660 {
p07gbar 0:455d5826751b 661 if (in < 0)
p07gbar 0:455d5826751b 662 in *= -1;
p07gbar 0:455d5826751b 663
p07gbar 0:455d5826751b 664 return in;
p07gbar 0:455d5826751b 665 }