@@ -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)); |