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