| @@ -61,6 +61,7 @@ void AudioAnalyzeFFT1024::update(void) | |||
| block = receiveReadOnly(); | |||
| if (!block) return; | |||
| #if defined(KINETISK) | |||
| switch (state) { | |||
| case 0: | |||
| blocklist[0] = block; | |||
| @@ -122,6 +123,9 @@ void AudioAnalyzeFFT1024::update(void) | |||
| state = 4; | |||
| break; | |||
| } | |||
| #else | |||
| release(block); | |||
| #endif | |||
| } | |||
| @@ -53,6 +53,7 @@ void AudioInputAnalog::init(uint8_t pin) | |||
| dc_average = sum >> 10; | |||
| // set the programmable delay block to trigger the ADC at 44.1 kHz | |||
| #if defined(KINETISK) | |||
| if (!(SIM_SCGC6 & SIM_SCGC6_PDB) | |||
| || (PDB0_SC & PDB_CONFIG) != PDB_CONFIG | |||
| || PDB0_MOD != PDB_PERIOD | |||
| @@ -65,12 +66,13 @@ void AudioInputAnalog::init(uint8_t pin) | |||
| PDB0_SC = PDB_CONFIG | PDB_SC_SWTRIG; | |||
| PDB0_CH0C1 = 0x0101; | |||
| } | |||
| #endif | |||
| // enable the ADC for hardware trigger and DMA | |||
| ADC0_SC2 |= ADC_SC2_ADTRG | ADC_SC2_DMAEN; | |||
| // set up a DMA channel to store the ADC data | |||
| dma.begin(true); | |||
| #if defined(KINETISK) | |||
| dma.TCD->SADDR = &ADC0_RA; | |||
| dma.TCD->SOFF = 0; | |||
| dma.TCD->ATTR = DMA_TCD_ATTR_SSIZE(1) | DMA_TCD_ATTR_DSIZE(1); | |||
| @@ -82,6 +84,7 @@ void AudioInputAnalog::init(uint8_t pin) | |||
| dma.TCD->DLASTSGA = -sizeof(analog_rx_buffer); | |||
| dma.TCD->BITER_ELINKNO = sizeof(analog_rx_buffer) / 2; | |||
| dma.TCD->CSR = DMA_TCD_CSR_INTHALF | DMA_TCD_CSR_INTMAJOR; | |||
| #endif | |||
| dma.triggerAtHardwareEvent(DMAMUX_SOURCE_ADC0); | |||
| update_responsibility = update_setup(); | |||
| dma.enable(); | |||
| @@ -96,7 +99,9 @@ void AudioInputAnalog::isr(void) | |||
| uint16_t *dest_left; | |||
| audio_block_t *left; | |||
| #if defined(KINETISK) | |||
| daddr = (uint32_t)(dma.TCD->DADDR); | |||
| #endif | |||
| dma.clearInterrupt(); | |||
| if (daddr < (uint32_t)analog_rx_buffer + sizeof(analog_rx_buffer) / 2) { | |||
| @@ -27,7 +27,10 @@ | |||
| #include "mixer.h" | |||
| #include "utility/dspinst.h" | |||
| void applyGain(int16_t *data, int32_t mult) | |||
| #if defined(KINETISK) | |||
| #define MULTI_UNITYGAIN 65536 | |||
| static void applyGain(int16_t *data, int32_t mult) | |||
| { | |||
| uint32_t *p = (uint32_t *)data; | |||
| const uint32_t *end = (uint32_t *)(data + AUDIO_BLOCK_SAMPLES); | |||
| @@ -38,19 +41,17 @@ void applyGain(int16_t *data, int32_t mult) | |||
| int32_t val2 = signed_multiply_32x16t(mult, tmp32); | |||
| val1 = signed_saturate_rshift(val1, 16, 0); | |||
| val2 = signed_saturate_rshift(val2, 16, 0); | |||
| *p++ = pack_16x16(val2, val1); | |||
| *p++ = pack_16b_16b(val2, val1); | |||
| } while (p < end); | |||
| } | |||
| // page 133 | |||
| void applyGainThenAdd(int16_t *data, const int16_t *in, int32_t mult) | |||
| static void applyGainThenAdd(int16_t *data, const int16_t *in, int32_t mult) | |||
| { | |||
| uint32_t *dst = (uint32_t *)data; | |||
| const uint32_t *src = (uint32_t *)in; | |||
| const uint32_t *end = (uint32_t *)(data + AUDIO_BLOCK_SAMPLES); | |||
| if (mult == 65536) { | |||
| if (mult == MULTI_UNITYGAIN) { | |||
| do { | |||
| uint32_t tmp32 = *dst; | |||
| *dst++ = signed_add_16_and_16(tmp32, *src++); | |||
| @@ -64,13 +65,44 @@ void applyGainThenAdd(int16_t *data, const int16_t *in, int32_t mult) | |||
| int32_t val2 = signed_multiply_32x16t(mult, tmp32); | |||
| val1 = signed_saturate_rshift(val1, 16, 0); | |||
| val2 = signed_saturate_rshift(val2, 16, 0); | |||
| tmp32 = pack_16x16(val2, val1); | |||
| tmp32 = pack_16b_16b(val2, val1); | |||
| uint32_t tmp32b = *dst; | |||
| *dst++ = signed_add_16_and_16(tmp32, tmp32b); | |||
| } while (dst < end); | |||
| } | |||
| } | |||
| #elif defined(KINETISL) | |||
| #define MULTI_UNITYGAIN 256 | |||
| static void applyGain(int16_t *data, int32_t mult) | |||
| { | |||
| const int16_t *end = data + AUDIO_BLOCK_SAMPLES; | |||
| do { | |||
| int32_t val = *data * mult; | |||
| *data++ = signed_saturate_rshift(val, 16, 0); | |||
| } while (data < end); | |||
| } | |||
| static void applyGainThenAdd(int16_t *dst, const int16_t *src, int32_t mult) | |||
| { | |||
| const int16_t *end = dst + AUDIO_BLOCK_SAMPLES; | |||
| if (mult == MULTI_UNITYGAIN) { | |||
| do { | |||
| int32_t val = *dst + *src++; | |||
| *dst++ = signed_saturate_rshift(val, 16, 0); | |||
| } while (dst < end); | |||
| } else { | |||
| do { | |||
| int32_t val = *dst + ((*src++ * mult) >> 8); // overflow possible?? | |||
| *dst++ = signed_saturate_rshift(val, 16, 0); | |||
| } while (dst < end); | |||
| } | |||
| } | |||
| #endif | |||
| void AudioMixer4::update(void) | |||
| { | |||
| @@ -82,7 +114,7 @@ void AudioMixer4::update(void) | |||
| out = receiveWritable(channel); | |||
| if (out) { | |||
| int32_t mult = multiplier[channel]; | |||
| if (mult != 65536) applyGain(out->data, mult); | |||
| if (mult != MULTI_UNITYGAIN) applyGain(out->data, mult); | |||
| } | |||
| } else { | |||
| in = receiveReadOnly(channel); | |||
| @@ -31,6 +31,7 @@ | |||
| class AudioMixer4 : public AudioStream | |||
| { | |||
| #if defined(KINETISK) | |||
| public: | |||
| AudioMixer4(void) : AudioStream(4, inputQueueArray) { | |||
| for (int i=0; i<4; i++) multiplier[i] = 65536; | |||
| @@ -45,6 +46,23 @@ public: | |||
| private: | |||
| int32_t multiplier[4]; | |||
| audio_block_t *inputQueueArray[4]; | |||
| #elif defined(KINETISL) | |||
| public: | |||
| AudioMixer4(void) : AudioStream(4, inputQueueArray) { | |||
| for (int i=0; i<4; i++) multiplier[i] = 256; | |||
| } | |||
| virtual void update(void); | |||
| void gain(unsigned int channel, float gain) { | |||
| if (channel >= 4) return; | |||
| if (gain > 127.0f) gain = 127.0f; | |||
| else if (gain < 0.0f) gain = 0.0f; | |||
| multiplier[channel] = gain * 256.0f; // TODO: proper roundoff? | |||
| } | |||
| private: | |||
| int16_t multiplier[4]; | |||
| audio_block_t *inputQueueArray[4]; | |||
| #endif | |||
| }; | |||
| #endif | |||
| @@ -47,6 +47,7 @@ void AudioOutputI2S::begin(void) | |||
| config_i2s(); | |||
| CORE_PIN22_CONFIG = PORT_PCR_MUX(6); // pin 22, PTC1, I2S0_TXD0 | |||
| #if defined(KINETISK) | |||
| dma.TCD->SADDR = i2s_tx_buffer; | |||
| dma.TCD->SOFF = 2; | |||
| dma.TCD->ATTR = DMA_TCD_ATTR_SSIZE(1) | DMA_TCD_ATTR_DSIZE(1); | |||
| @@ -58,6 +59,7 @@ void AudioOutputI2S::begin(void) | |||
| dma.TCD->DLASTSGA = 0; | |||
| dma.TCD->BITER_ELINKNO = sizeof(i2s_tx_buffer) / 2; | |||
| dma.TCD->CSR = DMA_TCD_CSR_INTHALF | DMA_TCD_CSR_INTMAJOR; | |||
| #endif | |||
| dma.triggerAtHardwareEvent(DMAMUX_SOURCE_I2S0_TX); | |||
| update_responsibility = update_setup(); | |||
| dma.enable(); | |||
| @@ -74,7 +76,9 @@ void AudioOutputI2S::isr(void) | |||
| audio_block_t *block; | |||
| uint32_t saddr, offset; | |||
| #if defined(KINETISK) | |||
| saddr = (uint32_t)(dma.TCD->SADDR); | |||
| #endif | |||
| dma.clearInterrupt(); | |||
| if (saddr < (uint32_t)i2s_tx_buffer + sizeof(i2s_tx_buffer) / 2) { | |||
| // DMA is transmitting the first half of the buffer | |||
| @@ -276,7 +280,7 @@ void AudioOutputI2Sslave::begin(void) | |||
| AudioOutputI2Sslave::config_i2s(); | |||
| CORE_PIN22_CONFIG = PORT_PCR_MUX(6); // pin 22, PTC1, I2S0_TXD0 | |||
| #if defined(KINETISK) | |||
| dma.TCD->SADDR = i2s_tx_buffer; | |||
| dma.TCD->SOFF = 2; | |||
| dma.TCD->ATTR = DMA_TCD_ATTR_SSIZE(1) | DMA_TCD_ATTR_DSIZE(1); | |||
| @@ -288,7 +292,7 @@ void AudioOutputI2Sslave::begin(void) | |||
| dma.TCD->DLASTSGA = 0; | |||
| dma.TCD->BITER_ELINKNO = sizeof(i2s_tx_buffer) / 2; | |||
| dma.TCD->CSR = DMA_TCD_CSR_INTHALF | DMA_TCD_CSR_INTMAJOR; | |||
| #endif | |||
| dma.triggerAtHardwareEvent(DMAMUX_SOURCE_I2S0_TX); | |||
| update_responsibility = update_setup(); | |||
| dma.enable(); | |||
| @@ -33,27 +33,47 @@ | |||
| static inline int32_t signed_saturate_rshift(int32_t val, int bits, int rshift) __attribute__((always_inline, unused)); | |||
| static inline int32_t signed_saturate_rshift(int32_t val, int bits, int rshift) | |||
| { | |||
| #if defined(KINETISK) | |||
| int32_t out; | |||
| asm volatile("ssat %0, %1, %2, asr %3" : "=r" (out) : "I" (bits), "r" (val), "I" (rshift)); | |||
| return out; | |||
| #elif defined(KINETISL) | |||
| int32_t out, max; | |||
| out = val >> rshift; | |||
| max = 1 << (bits - 1); | |||
| if (out >= 0) { | |||
| if (out > max - 1) out = max - 1; | |||
| } else { | |||
| if (out < -max) out = -max; | |||
| } | |||
| return out; | |||
| #endif | |||
| } | |||
| // computes ((a[31:0] * b[15:0]) >> 16) | |||
| static inline int32_t signed_multiply_32x16b(int32_t a, uint32_t b) __attribute__((always_inline, unused)); | |||
| static inline int32_t signed_multiply_32x16b(int32_t a, uint32_t b) | |||
| { | |||
| #if defined(KINETISK) | |||
| int32_t out; | |||
| asm volatile("smulwb %0, %1, %2" : "=r" (out) : "r" (a), "r" (b)); | |||
| return out; | |||
| #elif defined(KINETISL) | |||
| return ((int64_t)a * (int16_t)(b & 0xFFFF)) >> 16; | |||
| #endif | |||
| } | |||
| // computes ((a[31:0] * b[31:16]) >> 16) | |||
| static inline int32_t signed_multiply_32x16t(int32_t a, uint32_t b) __attribute__((always_inline, unused)); | |||
| static inline int32_t signed_multiply_32x16t(int32_t a, uint32_t b) | |||
| { | |||
| #if defined(KINETISK) | |||
| int32_t out; | |||
| asm volatile("smulwt %0, %1, %2" : "=r" (out) : "r" (a), "r" (b)); | |||
| return out; | |||
| #elif defined(KINETISL) | |||
| return ((int64_t)a * (int16_t)(b >> 16)) >> 16; | |||
| #endif | |||
| } | |||
| // computes (((int64_t)a[31:0] * (int64_t)b[31:0]) >> 32) | |||
| @@ -97,30 +117,43 @@ static inline int32_t multiply_subtract_32x32_rshift32_rounded(int32_t sum, int3 | |||
| static inline uint32_t pack_16t_16t(int32_t a, int32_t b) __attribute__((always_inline, unused)); | |||
| static inline uint32_t pack_16t_16t(int32_t a, int32_t b) | |||
| { | |||
| #if defined(KINETISK) | |||
| int32_t out; | |||
| asm volatile("pkhtb %0, %1, %2, asr #16" : "=r" (out) : "r" (a), "r" (b)); | |||
| return out; | |||
| #elif defined(KINETISL) | |||
| return (a & 0xFFFF0000) | ((uint32_t)b >> 16); | |||
| #endif | |||
| } | |||
| // computes (a[31:16] | b[15:0]) | |||
| static inline uint32_t pack_16t_16b(int32_t a, int32_t b) __attribute__((always_inline, unused)); | |||
| static inline uint32_t pack_16t_16b(int32_t a, int32_t b) | |||
| { | |||
| #if defined(KINETISK) | |||
| int32_t out; | |||
| asm volatile("pkhtb %0, %1, %2" : "=r" (out) : "r" (a), "r" (b)); | |||
| return out; | |||
| #elif defined(KINETISL) | |||
| return (a & 0xFFFF0000) | (b & 0x0000FFFF); | |||
| #endif | |||
| } | |||
| // computes ((a[15:0] << 16) | b[15:0]) | |||
| static inline uint32_t pack_16b_16b(int32_t a, int32_t b) __attribute__((always_inline, unused)); | |||
| static inline uint32_t pack_16b_16b(int32_t a, int32_t b) | |||
| { | |||
| #if defined(KINETISK) | |||
| int32_t out; | |||
| asm volatile("pkhbt %0, %1, %2, lsl #16" : "=r" (out) : "r" (b), "r" (a)); | |||
| return out; | |||
| #elif defined(KINETISL) | |||
| return (a << 16) | (b & 0x0000FFFF); | |||
| #endif | |||
| } | |||
| // computes ((a[15:0] << 16) | b[15:0]) | |||
| /* | |||
| static inline uint32_t pack_16x16(int32_t a, int32_t b) __attribute__((always_inline, unused)); | |||
| static inline uint32_t pack_16x16(int32_t a, int32_t b) | |||
| { | |||
| @@ -128,6 +161,7 @@ static inline uint32_t pack_16x16(int32_t a, int32_t b) | |||
| asm volatile("pkhbt %0, %1, %2, lsl #16" : "=r" (out) : "r" (b), "r" (a)); | |||
| return out; | |||
| } | |||
| */ | |||
| // computes (((a[31:16] + b[31:16]) << 16) | (a[15:0 + b[15:0])) | |||
| static inline uint32_t signed_add_16_and_16(uint32_t a, uint32_t b) __attribute__((always_inline, unused)); | |||