pull/8/merge
jcj83429 5 years ago committed by GitHub
commit e557e5e79a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 4
      AudioConvert_F32.h
  2. 2
      OpenAudio_ArduinoLibrary.h
  3. 124
      analyze_fft256_f32.cpp
  4. 118
      analyze_fft256_f32.h
  5. 500
      control_tlv320aic3206.cpp
  6. 58
      control_tlv320aic3206.h
  7. 100
      output_i2s_f32.cpp
  8. 9
      output_i2s_f32.h

@ -36,7 +36,7 @@ class AudioConvert_I16toF32 : public AudioStream_F32 //receive Int and transmits
static void convertAudio_I16toF32(audio_block_t *in, audio_block_f32_t *out, int len) {
//WEA Method. Should look at CMSIS arm_q15_to_float instead: https://www.keil.com/pack/doc/CMSIS/DSP/html/group__q15__to__x.html#gaf8b0d2324de273fc430b0e61ad4e9eb2
const float MAX_INT = 32678.0;
const float MAX_INT = 32768.0;
for (int i = 0; i < len; i++) out->data[i] = (float)(in->data[i]);
arm_scale_f32(out->data, 1.0/MAX_INT, out->data, out->length); //divide by 32678 to get -1.0 to +1.0
}
@ -88,4 +88,4 @@ class AudioConvert_F32toI16 : public AudioStream_F32 //receive Float and transmi
};
#endif
#endif

@ -1,7 +1,6 @@
#include <AudioStream_F32.h>
#include <AudioControlSGTL5000_Extended.h>
#include <control_tlv320aic3206.h>
#include "AudioCalcEnvelope_F32.h"
#include "AudioCalcGainWDRC_F32.h"
#include "AudioConfigFIRFilterBank_F32.h"
@ -17,6 +16,7 @@
#include "AudioMixer_F32.h"
#include "AudioMultiply_F32.h"
#include "AudioSettings_F32.h"
#include "analyze_fft256_f32.h"
#include "input_i2s_f32.h"
#include "output_i2s_f32.h"
#include "play_queue_f32.h"

@ -0,0 +1,124 @@
/* Audio Library for Teensy 3.X
* Copyright (c) 2014, Paul Stoffregen, paul@pjrc.com
*
* Development of this audio library was funded by PJRC.COM, LLC by sales of
* Teensy and Audio Adaptor boards. Please support PJRC's efforts to develop
* open source software by purchasing Teensy or other PJRC products.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice, development funding notice, and this permission
* notice shall be included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include <Arduino.h>
#include "analyze_fft256_f32.h"
#include "utility/dspinst.h"
static void copy_to_fft_buffer(void *destination, const void *source)
{
const float32_t *src = (const float32_t *)source;
float32_t *dst = (float32_t *)destination;
for (int i=0; i < AUDIO_BLOCK_SAMPLES; i++) {
*dst++ = *src++; // real sample plus a zero for imaginary
*dst++ = 0;
}
}
static void apply_window_to_fft_buffer(void *buffer, const void *window)
{
float32_t *buf = (float32_t *)buffer;
const int16_t *win = (int16_t *)window;;
for (int i=0; i < 256; i++) {
*buf *= *win++;
*buf /= 32768;
buf += 2;
}
}
void AudioAnalyzeFFT256_F32::update(void)
{
audio_block_f32_t *block;
block = receiveReadOnly_f32();
if (!block) return;
#if AUDIO_BLOCK_SAMPLES == 128
if (!prevblock) {
prevblock = block;
return;
}
copy_to_fft_buffer(buffer, prevblock->data);
copy_to_fft_buffer(buffer+256, block->data);
//window = AudioWindowBlackmanNuttall256;
//window = NULL;
if (window) apply_window_to_fft_buffer(buffer, window);
arm_cfft_radix4_f32(&fft_inst, buffer);
// G. Heinzel's paper says we're supposed to average the magnitude
// squared, then do the square root at the end.
if (count == 0) {
for (int i=0; i < 128; i++) {
sum[i] = (buffer[i * 2] * buffer[i * 2] + buffer[i * 2 + 1] * buffer[i * 2 + 1]);
}
} else {
for (int i=0; i < 128; i++) {
sum[i] += (buffer[i * 2] * buffer[i * 2] + buffer[i * 2 + 1] * buffer[i * 2 + 1]);
}
}
if (++count == naverage) {
count = 0;
for (int i=0; i < 128; i++) {
output[i] = sqrtf(sum[i] / naverage) / 64; // I don't know why 64, but a full scale sine wave is 64.
}
outputflag = true;
}
release(prevblock);
prevblock = block;
#elif AUDIO_BLOCK_SAMPLES == 64
if (prevblocks[2] == NULL) {
prevblocks[2] = prevblocks[1];
prevblocks[1] = prevblocks[0];
prevblocks[0] = block;
return;
}
if (count == 0) {
count = 1;
copy_to_fft_buffer(buffer, prevblocks[2]->data);
copy_to_fft_buffer(buffer+128, prevblocks[1]->data);
copy_to_fft_buffer(buffer+256, prevblocks[1]->data);
copy_to_fft_buffer(buffer+384, block->data);
if (window) apply_window_to_fft_buffer(buffer, window);
arm_cfft_radix4_q15(&fft_inst, buffer);
} else {
count = 2;
const uint32_t *p = (uint32_t *)buffer;
for (int i=0; i < 128; i++) {
uint32_t tmp = *p++;
int16_t v1 = tmp & 0xFFFF;
int16_t v2 = tmp >> 16;
output[i] = sqrt_uint32_approx(v1 * v1 + v2 * v2);
}
}
release(prevblocks[2]);
prevblocks[2] = prevblocks[1];
prevblocks[1] = prevblocks[0];
prevblocks[0] = block;
#endif
}

@ -0,0 +1,118 @@
/* Audio Library for Teensy 3.X
* Copyright (c) 2014, Paul Stoffregen, paul@pjrc.com
*
* Development of this audio library was funded by PJRC.COM, LLC by sales of
* Teensy and Audio Adaptor boards. Please support PJRC's efforts to develop
* open source software by purchasing Teensy or other PJRC products.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice, development funding notice, and this permission
* notice shall be included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef analyze_fft256_f32_h_
#define analyze_fft256_f32_h_
#include "Arduino.h"
#include "AudioStream_F32.h"
#include "arm_math.h"
// windows.c
extern "C" {
extern const int16_t AudioWindowHanning256[];
extern const int16_t AudioWindowBartlett256[];
extern const int16_t AudioWindowBlackman256[];
extern const int16_t AudioWindowFlattop256[];
extern const int16_t AudioWindowBlackmanHarris256[];
extern const int16_t AudioWindowNuttall256[];
extern const int16_t AudioWindowBlackmanNuttall256[];
extern const int16_t AudioWindowWelch256[];
extern const int16_t AudioWindowHamming256[];
extern const int16_t AudioWindowCosine256[];
extern const int16_t AudioWindowTukey256[];
}
class AudioAnalyzeFFT256_F32 : public AudioStream_F32
{
public:
AudioAnalyzeFFT256_F32() : AudioStream_F32(1, inputQueueArray),
window(AudioWindowHanning256), count(0), outputflag(false) {
arm_cfft_radix4_init_f32(&fft_inst, 256, 0, 1);
#if AUDIO_BLOCK_SAMPLES == 128
prevblock = NULL;
naverage = 1;
#elif AUDIO_BLOCK_SAMPLES == 64
prevblocks[0] = NULL;
prevblocks[1] = NULL;
prevblocks[2] = NULL;
#endif
}
bool available() {
if (outputflag == true) {
outputflag = false;
return true;
}
return false;
}
float read(unsigned int binNumber) {
if (binNumber > 127) return 0.0;
return output[binNumber];
}
float read(unsigned int binFirst, unsigned int binLast) {
if (binFirst > binLast) {
unsigned int tmp = binLast;
binLast = binFirst;
binFirst = tmp;
}
if (binFirst > 127) return 0.0;
if (binLast > 127) binLast = 127;
uint32_t sum = 0;
do {
sum += output[binFirst++];
} while (binFirst <= binLast);
return sum;
}
void averageTogether(uint8_t n) {
#if AUDIO_BLOCK_SAMPLES == 128
if (n == 0) n = 1;
naverage = n;
#endif
}
void windowFunction(const int16_t *w) {
window = w;
}
virtual void update(void);
float32_t output[128] __attribute__ ((aligned (4)));
private:
const int16_t *window;
#if AUDIO_BLOCK_SAMPLES == 128
audio_block_f32_t *prevblock;
#elif AUDIO_BLOCK_SAMPLES == 64
audio_block_f32_t *prevblocks[3];
#endif
float32_t buffer[512] __attribute__ ((aligned (4)));
#if AUDIO_BLOCK_SAMPLES == 128
float32_t sum[128];
uint8_t naverage;
#endif
uint8_t count;
volatile bool outputflag;
audio_block_f32_t *inputQueueArray[1];
arm_cfft_radix4_instance_f32 fft_inst;
};
#endif

@ -1,500 +0,0 @@
/*
control_tlv320aic3206
Created: Brendan Flynn (http://www.flexvoltbiosensor.com/) for Tympan, Jan-Feb 2017
Purpose: Control module for Texas Instruments TLV320AIC3206 compatible with Teensy Audio Library
License: MIT License. Use at your own risk.
*/
#include "control_tlv320aic3206.h"
#include <Wire.h>
//******************************** Constants *******************************//
#define AIC3206_I2C_ADDR 0x18
#ifndef AIC_FS
# define AIC_FS 44100UL
#endif
#define AIC_BITS 16
#define AIC_I2S_SLAVE 1
#if AIC_I2S_SLAVE
// Direction of BCLK and WCLK (reg 27) is input if a slave:
# define AIC_CLK_DIR 0
#else
// If master, make outputs:
# define AIC_CLK_DIR 0x0C
#endif
//#ifndef AIC_CODEC_CLKIN_BCLK
//# define AIC_CODEC_CLKIN_BCLK 0
//#endif
//**************************** Clock Setup **********************************//
//********************************** 44100 *********************************//
#if AIC_FS == 44100
// MCLK = 180000000 * 16 / 255 = 11.294117 MHz // FROM TEENSY, FIXED
// PLL setup. PLL_OUT = MCLK * R * J.D / P
//// J.D = 7.5264, P = 1, R = 1 => 90.32 MHz // FROM 12MHz CHA AND WHF //
// J.D = 7.9968, P = 1, R = 1 => 90.3168 MHz // For 44.1kHz exact
// J.D = 8.0000000002, P = 1, R = 1 => 9.35294117888MHz // for TEENSY 44.11764706kHz
#define PLL_J 8
#define PLL_D 0
// Bitclock divisor.
// BCLK = DAC_CLK/N = PLL_OUT/NDAC/N = 32*fs or 16*fs
// PLL_OUT = fs*NDAC*MDAC*DOSR
// BLCK = 32*fs = 1411200 = PLL
#if AIC_BITS == 16
#define BCLK_N 8
#elif AIC_BITS == 32
#define BCLK_N 4
#endif
// ADC/DAC FS setup.
// ADC_MOD_CLK = CODEC_CLKIN / (NADC * MADC)
// DAC_MOD_CLK = CODEC_CLKIN / (NDAC * MDAC)
// ADC_FS = PLL_OUT / (NADC*MADC*AOSR)
// DAC_FS = PLL_OUT / (NDAC*MDAC*DOSR)
// FS = 90.3168MHz / (8*2*128) = 44100 Hz.
// MOD = 90.3168MHz / (8*2) = 5644800 Hz
// Actual from Teensy: 44117.64706Hz * 128 => 5647058.82368Hz * 8*2 => 90352941.17888Hz
// DAC clock config.
// Note: MDAC*DOSR/32 >= RC, where RC is 8 for the default filter.
// See Table 2-21
// http://www.ti.com/lit/an/slaa463b/slaa463b.pdf
// PB1 - RC = 8. Use M8, N2
// PB25 - RC = 12. Use M8, N2
#define DOSR 128
#define NDAC 2
#define MDAC 8
#define AOSR 128
#define NADC 2
#define MADC 8
// Signal Processing Modes, Playback and Recording.
#define PRB_P 1
#define PRB_R 1
#endif // end fs if block
//**************************** Chip Setup **********************************//
//******************* INPUT DEFINITIONS *****************************//
// MIC routing registers
#define TYMPAN_MICPGA_LEFT_POSITIVE_REG 0x0134 // page 1 register 52
#define TYMPAN_MICPGA_LEFT_NEGATIVE_REG 0x0136 // page 1 register 54
#define TYMPAN_MICPGA_RIGHT_POSITIVE_REG 0x0137 // page 1 register 55
#define TYMPAN_MICPGA_RIGHT_NEGATIVE_REG 0x0139 // page 1 register 57
#define TYMPAN_MIC_ROUTING_POSITIVE_IN1 0b11000000 //
#define TYMPAN_MIC_ROUTING_POSITIVE_IN2 0b00110000 //
#define TYMPAN_MIC_ROUTING_POSITIVE_IN3 0b00001100 //
#define TYMPAN_MIC_ROUTING_POSITIVE_REVERSE 0b00000011 //
#define TYMPAN_MIC_ROUTING_NEGATIVE_CM_TO_CM1L 0b11000000 //
#define TYMPAN_MIC_ROUTING_NEGATIVE_IN2_REVERSE 0b00110000 //
#define TYMPAN_MIC_ROUTING_NEGATIVE_IN3_REVERSE 0b00001100 //
#define TYMPAN_MIC_ROUTING_NEGATIVE_CM_TO_CM2L 0b00000011 //
#define TYMPAN_MIC_ROUTING_RESISTANCE_10k 0b01010101
#define TYMPAN_MIC_ROUTING_RESISTANCE_20k 0b10101010
#define TYMPAN_MIC_ROUTING_RESISTANCE_40k 0b11111111
#define TYMPAN_MIC_ROUTING_RESISTANCE_DEFAULT TYMPAN_MIC_ROUTING_RESISTANCE_10k
#define TYMPAN_MICPGA_LEFT_VOLUME_REG 0x013B // page 1 register 59 // 0 to 47.5dB in 0.5dB steps
#define TYMPAN_MICPGA_RIGHT_VOLUME_REG 0x013C // page 1 register 60 // 0 to 47.5dB in 0.5dB steps
#define TYMPAN_MICPGA_VOLUME_ENABLE 0x00 // default is 0b11000000 - clear to 0 to enable
#define TYMPAN_MIC_BIAS_REG 0x0133 // page 1 reg 51
#define TYMPAN_MIC_BIAS_POWER_ON 0x40
#define TYMPAN_MIC_BIAS_POWER_OFF 0x00
#define TYMPAN_MIC_BIAS_OUTPUT_VOLTAGE_1_25 0x00
#define TYMPAN_MIC_BIAS_OUTPUT_VOLTAGE_1_7 0x01
#define TYMPAN_MIC_BIAS_OUTPUT_VOLTAGE_2_5 0x10
#define TYMPAN_MIC_BIAS_OUTPUT_VOLTAGE_VSUPPLY 0x11
#define TYMPAN_ADC_PROCESSING_BLOCK_REG 0x003d // page 0 register 61
#define TYMPAN_ADC_CHANNEL_POWER_REG 0x0051 // page 0 register81
#define TYMPAN_ADC_CHANNELS_ON 0b11000000 // power up left and right
#define TYMPAN_ADC_MUTE_REG 0x0052 // page 0, register 82
#define TYMPAN_ADC_UNMUTE 0x00
bool AudioControlTLV320AIC3206::enable(void)
{
delay(100);
// Setup for Master mode, pins 18/19, external pullups, 400kHz, 200ms default timeout
Wire.begin();
delay(5);
//hard reset the AIC
//Serial.println("Hardware reset of AIC...");
#define RESET_PIN 21
pinMode(RESET_PIN,OUTPUT);
digitalWrite(RESET_PIN,HIGH);delay(50); //not reset
digitalWrite(RESET_PIN,LOW);delay(50); //reset
digitalWrite(RESET_PIN,HIGH);delay(50);//not reset
aic_reset(); delay(100); //soft reset
aic_init(); delay(100);
aic_initADC(); delay(100);
aic_initDAC(); delay(100);
aic_readPage(0, 27); // check a specific register - a register read test
if (debugToSerial) Serial.println("TLV320 enable done");
return true;
}
bool AudioControlTLV320AIC3206::disable(void) {
return true;
}
//dummy function to keep compatible with Teensy Audio Library
bool AudioControlTLV320AIC3206::inputLevel(float volume) {
return false;
}
bool AudioControlTLV320AIC3206::inputSelect(int n) {
if (n == TYMPAN_INPUT_LINE_IN) {
// USE LINE IN SOLDER PADS
aic_writeAddress(TYMPAN_MICPGA_LEFT_POSITIVE_REG, TYMPAN_MIC_ROUTING_POSITIVE_IN1 & TYMPAN_MIC_ROUTING_RESISTANCE_DEFAULT);
aic_writeAddress(TYMPAN_MICPGA_LEFT_NEGATIVE_REG, TYMPAN_MIC_ROUTING_NEGATIVE_CM_TO_CM1L & TYMPAN_MIC_ROUTING_RESISTANCE_DEFAULT);
aic_writeAddress(TYMPAN_MICPGA_RIGHT_POSITIVE_REG, TYMPAN_MIC_ROUTING_POSITIVE_IN1 & TYMPAN_MIC_ROUTING_RESISTANCE_DEFAULT);
aic_writeAddress(TYMPAN_MICPGA_RIGHT_NEGATIVE_REG, TYMPAN_MIC_ROUTING_NEGATIVE_CM_TO_CM1L & TYMPAN_MIC_ROUTING_RESISTANCE_DEFAULT);
// BIAS OFF
setMicBias(TYMPAN_MIC_BIAS_OFF);
if (debugToSerial) Serial.println("Set Audio Input to Line In");
return true;
} else if (n == TYMPAN_INPUT_JACK_AS_MIC) {
// mic-jack = IN3
aic_writeAddress(TYMPAN_MICPGA_LEFT_POSITIVE_REG, TYMPAN_MIC_ROUTING_POSITIVE_IN3 & TYMPAN_MIC_ROUTING_RESISTANCE_DEFAULT);
aic_writeAddress(TYMPAN_MICPGA_LEFT_NEGATIVE_REG, TYMPAN_MIC_ROUTING_NEGATIVE_CM_TO_CM1L & TYMPAN_MIC_ROUTING_RESISTANCE_DEFAULT);
aic_writeAddress(TYMPAN_MICPGA_RIGHT_POSITIVE_REG, TYMPAN_MIC_ROUTING_POSITIVE_IN3 & TYMPAN_MIC_ROUTING_RESISTANCE_DEFAULT);
aic_writeAddress(TYMPAN_MICPGA_RIGHT_NEGATIVE_REG, TYMPAN_MIC_ROUTING_NEGATIVE_CM_TO_CM1L & TYMPAN_MIC_ROUTING_RESISTANCE_DEFAULT);
// BIAS on, using default
setMicBias(TYMPAN_DEFAULT_MIC_BIAS);
if (debugToSerial) Serial.println("Set Audio Input to JACK AS MIC, BIAS SET TO DEFAULT 2.5V");
return true;
} else if (n == TYMPAN_INPUT_JACK_AS_LINEIN) {
// 1
// mic-jack = IN3
aic_writeAddress(TYMPAN_MICPGA_LEFT_POSITIVE_REG, TYMPAN_MIC_ROUTING_POSITIVE_IN3 & TYMPAN_MIC_ROUTING_RESISTANCE_DEFAULT);
aic_writeAddress(TYMPAN_MICPGA_LEFT_NEGATIVE_REG, TYMPAN_MIC_ROUTING_NEGATIVE_CM_TO_CM1L & TYMPAN_MIC_ROUTING_RESISTANCE_DEFAULT);
aic_writeAddress(TYMPAN_MICPGA_RIGHT_POSITIVE_REG, TYMPAN_MIC_ROUTING_POSITIVE_IN3 & TYMPAN_MIC_ROUTING_RESISTANCE_DEFAULT);
aic_writeAddress(TYMPAN_MICPGA_RIGHT_NEGATIVE_REG, TYMPAN_MIC_ROUTING_NEGATIVE_CM_TO_CM1L & TYMPAN_MIC_ROUTING_RESISTANCE_DEFAULT);
// BIAS Off
setMicBias(TYMPAN_MIC_BIAS_OFF);
if (debugToSerial) Serial.println("Set Audio Input to JACK AS LINEIN, BIAS OFF");
return true;
} else if (n == TYMPAN_INPUT_ON_BOARD_MIC) {
// on-board = IN2
aic_writeAddress(TYMPAN_MICPGA_LEFT_POSITIVE_REG, TYMPAN_MIC_ROUTING_POSITIVE_IN2 & TYMPAN_MIC_ROUTING_RESISTANCE_DEFAULT);
aic_writeAddress(TYMPAN_MICPGA_LEFT_NEGATIVE_REG, TYMPAN_MIC_ROUTING_NEGATIVE_CM_TO_CM1L & TYMPAN_MIC_ROUTING_RESISTANCE_DEFAULT);
aic_writeAddress(TYMPAN_MICPGA_RIGHT_POSITIVE_REG, TYMPAN_MIC_ROUTING_POSITIVE_IN2 & TYMPAN_MIC_ROUTING_RESISTANCE_DEFAULT);
aic_writeAddress(TYMPAN_MICPGA_RIGHT_NEGATIVE_REG, TYMPAN_MIC_ROUTING_NEGATIVE_CM_TO_CM1L & TYMPAN_MIC_ROUTING_RESISTANCE_DEFAULT);
// BIAS Off
setMicBias(TYMPAN_MIC_BIAS_OFF);
if (debugToSerial) Serial.println("Set Audio Input to Tympan On-Board MIC, BIAS OFF");
return true;
}
Serial.print("controlTLV320AIC3206: ERROR: Unable to Select Input - Value not supported: ");
Serial.println(n);
return false;
}
bool AudioControlTLV320AIC3206::setMicBias(int n) {
if (n == TYMPAN_MIC_BIAS_1_25) {
aic_writeAddress(TYMPAN_MIC_BIAS_REG, TYMPAN_MIC_BIAS_POWER_ON | TYMPAN_MIC_BIAS_OUTPUT_VOLTAGE_1_25); // power up mic bias
return true;
} else if (n == TYMPAN_MIC_BIAS_1_7) {
aic_writeAddress(TYMPAN_MIC_BIAS_REG, TYMPAN_MIC_BIAS_POWER_ON | TYMPAN_MIC_BIAS_OUTPUT_VOLTAGE_1_7); // power up mic bias
return true;
} else if (n == TYMPAN_MIC_BIAS_2_5) {
aic_writeAddress(TYMPAN_MIC_BIAS_REG, TYMPAN_MIC_BIAS_POWER_ON | TYMPAN_MIC_BIAS_OUTPUT_VOLTAGE_2_5); // power up mic bias
return true;
} else if (n == TYMPAN_MIC_BIAS_VSUPPLY) {
aic_writeAddress(TYMPAN_MIC_BIAS_REG, TYMPAN_MIC_BIAS_POWER_ON | TYMPAN_MIC_BIAS_OUTPUT_VOLTAGE_VSUPPLY); // power up mic bias
return true;
} else if (n == TYMPAN_MIC_BIAS_OFF) {
aic_writeAddress(TYMPAN_MIC_BIAS_REG, TYMPAN_MIC_BIAS_POWER_OFF); // power up mic bias
return true;
}
Serial.print("controlTLV320AIC3206: ERROR: Unable to set MIC BIAS - Value not supported: ");
Serial.println(n);
return false;
}
void AudioControlTLV320AIC3206::aic_reset() {
if (debugToSerial) Serial.println("INFO: Reseting AIC");
aic_writePage(0x00, 0x01, 0x01);
// aic_writeAddress(0x0001, 0x01);
delay(10);
}
// example - turn on IN3 - mic jack, with negatives routed to CM1L and with 10k resistance
// aic_writeAddress(TYMPAN_LEFT_MICPGA_POSITIVE_REG, TYMPAN_MIC_ROUTING_POSITIVE_IN3 & TYMPAN_MIC_ROUTING_RESISTANCE_DEFAULT);
// aic_writeAddress(TYMPAN_LEFT_MICPGA_NEGATIVE_REG, TYMPAN_MIC_ROUTING_NEGATIVE_CM_TO_CM1L & TYMPAN_MIC_ROUTING_RESISTANCE_DEFAULT);
// aic_writeAddress(TYMPAN_RIGHT_MICPGA_POSITIVE_REG, TYMPAN_MIC_ROUTING_POSITIVE_IN3 & TYMPAN_MIC_ROUTING_RESISTANCE_DEFAULT);
// aic_writeAddress(TYMPAN_RIGHT_MICPGA_NEGATIVE_REG, TYMPAN_MIC_ROUTING_NEGATIVE_CM_TO_CM1L & TYMPAN_MIC_ROUTING_RESISTANCE_DEFAULT);
void AudioControlTLV320AIC3206::aic_initADC() {
if (debugToSerial) Serial.println("INFO: Initializing AIC ADC");
aic_writeAddress(TYMPAN_ADC_PROCESSING_BLOCK_REG, PRB_R); // processing blocks - ADC
aic_writePage(1, 61, 0); // 0x3D // Select ADC PTM_R4 Power Tune?
aic_writePage(1, 71, 0b00110001); // 0x47 // Set MicPGA startup delay to 3.1ms
aic_writeAddress(TYMPAN_MIC_BIAS_REG, TYMPAN_MIC_BIAS_POWER_ON | TYMPAN_MIC_BIAS_2_5); // power up mic bias
aic_writeAddress(TYMPAN_MICPGA_LEFT_POSITIVE_REG, TYMPAN_MIC_ROUTING_POSITIVE_IN2 & TYMPAN_MIC_ROUTING_RESISTANCE_DEFAULT);
aic_writeAddress(TYMPAN_MICPGA_LEFT_NEGATIVE_REG, TYMPAN_MIC_ROUTING_NEGATIVE_CM_TO_CM1L & TYMPAN_MIC_ROUTING_RESISTANCE_DEFAULT);
aic_writeAddress(TYMPAN_MICPGA_RIGHT_POSITIVE_REG, TYMPAN_MIC_ROUTING_POSITIVE_IN2 & TYMPAN_MIC_ROUTING_RESISTANCE_DEFAULT);
aic_writeAddress(TYMPAN_MICPGA_RIGHT_NEGATIVE_REG, TYMPAN_MIC_ROUTING_NEGATIVE_CM_TO_CM1L & TYMPAN_MIC_ROUTING_RESISTANCE_DEFAULT);
aic_writeAddress(TYMPAN_MICPGA_LEFT_VOLUME_REG, TYMPAN_MICPGA_VOLUME_ENABLE); // enable Left MicPGA, set gain to 0 dB
aic_writeAddress(TYMPAN_MICPGA_RIGHT_VOLUME_REG, TYMPAN_MICPGA_VOLUME_ENABLE); // enable Right MicPGA, set gain to 0 dB
aic_writeAddress(TYMPAN_ADC_MUTE_REG, TYMPAN_ADC_UNMUTE); // Unmute Left and Right ADC Digital Volume Control
aic_writeAddress(TYMPAN_ADC_CHANNEL_POWER_REG, TYMPAN_ADC_CHANNELS_ON); // Unmute Left and Right ADC Digital Volume Control
}
// set MICPGA volume, 0-47.5dB in 0.5dB setps
bool AudioControlTLV320AIC3206::setInputGain_dB(float volume) {
if (volume < 0.0) {
volume = 0.0; // 0.0 dB
Serial.println("controlTLV320AIC3206: WARNING: Attempting to set MIC volume outside range");
}
if (volume > 47.5) {
volume = 47.5; // 47.5 dB
Serial.println("controlTLV320AIC3206: WARNING: Attempting to set MIC volume outside range");
}
volume = volume * 2.0; // convert to value map (0.5 dB steps)
int8_t volume_int = (int8_t) (round(volume)); // round
if (debugToSerial) {
Serial.print("INFO: Setting MIC volume to ");
Serial.print(volume, 1);
Serial.print(". Converted to volume map => ");
Serial.println(volume_int);
}
aic_writeAddress(TYMPAN_MICPGA_LEFT_VOLUME_REG, TYMPAN_MICPGA_VOLUME_ENABLE | volume_int); // enable Left MicPGA, set gain to 0 dB
aic_writeAddress(TYMPAN_MICPGA_RIGHT_VOLUME_REG, TYMPAN_MICPGA_VOLUME_ENABLE | volume_int); // enable Right MicPGA, set gain to 0 dB
return true;
}
//******************* OUTPUT DEFINITIONS *****************************//
#define TYMPAN_DAC_PROCESSING_BLOCK_REG 0x003c // page 0 register 60
#define TYMPAN_DAC_VOLUME_LEFT_REG 0x0041 // page 0 reg 65
#define TYMPAN_DAC_VOLUME_RIGHT_REG 0x0042 // page 0 reg 66
//volume control, similar to Teensy Audio Board
// value between 0.0 and 1.0. Set to span -58 to +15 dB
bool AudioControlTLV320AIC3206::volume(float volume) {
volume = max(0.0, min(1.0, volume));
float vol_dB = -58.f + (15.0 - (-58.0f)) * volume;
volume_dB(vol_dB);
return true;
}
// -63.6 to +24 dB in 0.5dB steps. uses signed 8-bit
bool AudioControlTLV320AIC3206::volume_dB(float volume) {
// Constrain to limits
if (volume > 24.0) {
volume = 24.0;
Serial.println("controlTLV320AIC3206: WARNING: Attempting to set DAC Volume outside range");
}
if (volume < -63.5) {
volume = -63.5;
Serial.println("controlTLV320AIC3206: WARNING: Attempting to set DAC Volume outside range");
}
volume = volume * 2.0; // convert to value map (0.5 dB steps)
int8_t volume_int = (int8_t) (round(volume)); // round
if (debugToSerial) {
Serial.print("INFO: Setting DAC volume to ");
Serial.print(volume, 1);
Serial.print(". Converted to volume map => ");
Serial.println(volume_int);
}
aic_writeAddress(TYMPAN_DAC_VOLUME_RIGHT_REG, volume_int);
aic_writeAddress(TYMPAN_DAC_VOLUME_LEFT_REG, volume_int);
return true;
}
void AudioControlTLV320AIC3206::aic_initDAC() {
if (debugToSerial) Serial.println("INFO: Initializing AIC DAC");
// PLAYBACK SETUP
aic_writeAddress(TYMPAN_DAC_PROCESSING_BLOCK_REG, PRB_P); // processing blocks - DAC
//aic_writePage(1, 20, 0x25); // 0x14 De-Pop
aic_writePage(1, 12, 8); // route LDAC/RDAC to HPL/HPR
aic_writePage(1, 13, 8); // route LDAC/RDAC to HPL/HPR
aic_writePage(0, 63, 0xD6); // 0x3F // Power up LDAC/RDAC
// aic_writePage(1, 14, 8); // route LDAC/RDAC to LOL/LOR
// aic_writePage(1, 15, 8); // route LDAC/RDAC to LOL/LOR
aic_writePage(1, 16, 0); // unmute HPL Driver, 0 gain
aic_writePage(1, 17, 0); // unmute HPR Driver, 0 gain
// aic_writePage(1, 18, 0); // unmute LOL Driver, 0 gain
// aic_writePage(1, 19, 0); // unmute LOR Driver, 0 gain
aic_writePage(1, 9, 0x30); // Power up HPL/HPR and LOL/LOR drivers
delay(100);
aic_writeAddress(TYMPAN_DAC_VOLUME_LEFT_REG, 0); // default to 0 dB
aic_writeAddress(TYMPAN_DAC_VOLUME_RIGHT_REG, 0); // default to 0 dB
aic_writePage(0, 64, 0); // 0x40 // Unmute LDAC/RDAC
}
void AudioControlTLV320AIC3206::aic_init() {
if (debugToSerial) Serial.println("INFO: Initializing AIC");
// PLL
aic_writePage(0, 4, 3); // 0x04 low PLL clock range, MCLK is PLL input, PLL_OUT is CODEC_CLKIN
aic_writePage(0, 5, (PLL_J != 0 ? 0x91 : 0x11));
aic_writePage(0, 6, PLL_J);
aic_writePage(0, 7, PLL_D >> 8);
aic_writePage(0, 8, PLL_D &0xFF);
// CLOCKS
aic_writePage(0, 11, 0x80 | NDAC); // 0x0B
aic_writePage(0, 12, 0x80 | MDAC); // 0x0C
aic_writePage(0, 13, 0); // 0x0D
aic_writePage(0, 14, DOSR); // 0x0E
// aic_writePage(0, 18, 0); // 0x12 // powered down, ADC_CLK same as DAC_CLK
// aic_writePage(0, 19, 0); // 0x13 // powered down, ADC_MOD_CLK same as DAC_MOD_CLK
aic_writePage(0, 18, 0x80 | NADC); // 0x12
aic_writePage(0, 19, 0x80 | MADC); // 0x13
aic_writePage(0, 20, AOSR);
aic_writePage(0, 30, 0x80 | BCLK_N); // power up BLCK N Divider, default is 128
// POWER
aic_writePage(1, 1, 8); // 0x01
aic_writePage(1, 2, 0); // 0x02 Enable Master Analog Power Control
aic_writePage(1, 10, 0); // common mode 0.9 for full chip, HP, LO // from WHF/CHA
aic_writePage(1, 71, 0x31); // 0x47 Set input power-up time to 3.1ms (for ADC)
aic_writePage(1, 123, 1); // 0x7B Set reference to power up in 40ms when analog blocks are powered up
//aic_writePage(1, 124, 6); // 0x7D Charge Pump
aic_writePage(1, 125, 0x53); // Enable ground-centered mode, DC offset correction // from WHF/CHA
// !!!!!!!!! The below writes are from WHF/CHA - probably don't need?
// aic_writePage(1, 1, 10); // 0x01 // Charge pump
aic_writePage(0, 27, 0x01 | AIC_CLK_DIR | (AIC_BITS == 32 ? 0x30 : 0)); // 0x1B
// aic_writePage(0, 28, 0); // 0x1C
}
unsigned int AudioControlTLV320AIC3206::aic_readPage(uint8_t page, uint8_t reg)
{
unsigned int val;
if (aic_goToPage(page)) {
Wire.beginTransmission(AIC3206_I2C_ADDR);
Wire.write(reg);
unsigned int result = Wire.endTransmission();
if (result != 0) {
Serial.print("controlTLV320AIC3206: ERROR: Read Page. Page: ");Serial.print(page);
Serial.print(" Reg: ");Serial.print(reg);
Serial.print(". Received Error During Read Page: ");
Serial.println(result);
val = 300 + result;
return val;
}
if (Wire.requestFrom(AIC3206_I2C_ADDR, 1) < 1) {
Serial.print("controlTLV320AIC3206: ERROR: Read Page. Page: ");Serial.print(page);
Serial.print(" Reg: ");Serial.print(reg);
Serial.println(". Nothing to return");
val = 400;
return val;
}
if (Wire.available() >= 1) {
uint16_t val = Wire.read();
if (debugToSerial) {
Serial.print("INFO: Read Page. Page: ");Serial.print(page);
Serial.print(" Reg: ");Serial.print(reg);
Serial.print(". Received: ");
Serial.println(val, HEX);
}
return val;
}
} else {
Serial.print("controlTLV320AIC3206: INFO: Read Page. Page: ");Serial.print(page);
Serial.print(" Reg: ");Serial.print(reg);
Serial.println(". Failed to go to read page. Could not go there.");
val = 500;
return val;
}
val = 600;
return val;
}
bool AudioControlTLV320AIC3206::aic_writeAddress(uint16_t address, uint8_t val) {
uint8_t reg = (uint8_t) (address & 0xFF);
uint8_t page = (uint8_t) ((address >> 8) & 0xFF);
return aic_writePage(page, reg, val);
}
bool AudioControlTLV320AIC3206::aic_writePage(uint8_t page, uint8_t reg, uint8_t val) {
if (debugToSerial) {
Serial.print("INFO: Write Page. Page: ");Serial.print(page);
Serial.print(" Reg: ");Serial.print(reg);
Serial.print(" Val: ");Serial.println(val);
}
if (aic_goToPage(page)) {
Wire.beginTransmission(AIC3206_I2C_ADDR);
Wire.write(reg);delay(10);
Wire.write(val);delay(10);
uint8_t result = Wire.endTransmission();
if (result == 0) return true;
else {
Serial.print("controlTLV320AIC3206: Received Error During writePage(): Error = ");
Serial.println(result);
}
}
return false;
}
bool AudioControlTLV320AIC3206::aic_goToPage(byte page) {
Wire.beginTransmission(AIC3206_I2C_ADDR);
Wire.write(0x00); delay(10);// page register //was delay(10) from BPF
Wire.write(page); delay(10);// go to page //was delay(10) from BPF
byte result = Wire.endTransmission();
if (result != 0) {
Serial.print("controlTLV320AIC3206: Received Error During goToPage(): Error = ");
Serial.println(result);
if (result == 2) {
// failed to transmit address
//return aic_goToPage(page);
} else if (result == 3) {
// failed to transmit data
//return aic_goToPage(page);
}
return false;
}
return true;
}

@ -1,58 +0,0 @@
/*
control_tlv320aic3206
Created: Brendan Flynn (http://www.flexvoltbiosensor.com/) for Tympan, Jan-Feb 2017
Purpose: Control module for Texas Instruments TLV320AIC3206 compatible with Teensy Audio Library
License: MIT License. Use at your own risk.
*/
#ifndef control_tlv320aic3206_h_
#define control_tlv320aic3206_h_
#include "AudioControl.h"
class AudioControlTLV320AIC3206: public AudioControl
{
public:
//GUI: inputs:0, outputs:0 //this line used for automatic generation of GUI node
AudioControlTLV320AIC3206(void) { debugToSerial = false; };
AudioControlTLV320AIC3206(bool _debugToSerial) { debugToSerial = _debugToSerial; };
bool enable(void);
bool disable(void);
bool volume(float n);
bool volume_dB(float n);
bool inputLevel(float n); //dummy to be compatible with Teensy Audio Library
bool inputSelect(int n);
bool setInputGain_dB(float n);
bool setMicBias(int n);
bool debugToSerial;
private:
void aic_reset(void);
void aic_init(void);
void aic_initDAC(void);
void aic_initADC(void);
unsigned int aic_readPage(uint8_t page, uint8_t reg);
bool aic_writePage(uint8_t page, uint8_t reg, uint8_t val);
bool aic_writeAddress(uint16_t address, uint8_t val);
bool aic_goToPage(uint8_t page);
};
#define TYMPAN_OUTPUT_HEADPHONE_JACK_OUT 1
//convenience names to use with inputSelect() to set whnch analog inputs to use
#define TYMPAN_INPUT_LINE_IN 1 //uses IN1
#define TYMPAN_INPUT_ON_BOARD_MIC 2 //uses IN2 analog inputs
#define TYMPAN_INPUT_JACK_AS_LINEIN 3 //uses IN3 analog inputs
#define TYMPAN_INPUT_JACK_AS_MIC 4 //uses IN3 analog inputs *and* enables mic bias
//names to use with setMicBias() to set the amount of bias voltage to use
#define TYMPAN_MIC_BIAS_OFF 0
#define TYMPAN_MIC_BIAS_1_25 1
#define TYMPAN_MIC_BIAS_1_7 2
#define TYMPAN_MIC_BIAS_2_5 3
#define TYMPAN_MIC_BIAS_VSUPPLY 4
#define TYMPAN_DEFAULT_MIC_BIAS TYMPAN_MIC_BIAS_2_5
#endif

@ -73,14 +73,19 @@ float setI2SFreq(const float freq_Hz) {
return 0.0f;
}
audio_block_t * AudioOutputI2S_F32::block_left_1st = NULL;
audio_block_t * AudioOutputI2S_F32::block_right_1st = NULL;
audio_block_t * AudioOutputI2S_F32::block_left_2nd = NULL;
audio_block_t * AudioOutputI2S_F32::block_right_2nd = NULL;
static inline int32_t f32_to_i32(float32_t f) {
const float32_t fullscale = 1LL << 31;
return max(-(fullscale - 1), min(fullscale - 1, f * fullscale));
}
audio_block_f32_t * AudioOutputI2S_F32::block_left_1st = NULL;
audio_block_f32_t * AudioOutputI2S_F32::block_right_1st = NULL;
audio_block_f32_t * AudioOutputI2S_F32::block_left_2nd = NULL;
audio_block_f32_t * AudioOutputI2S_F32::block_right_2nd = NULL;
uint16_t AudioOutputI2S_F32::block_left_offset = 0;
uint16_t AudioOutputI2S_F32::block_right_offset = 0;
bool AudioOutputI2S_F32::update_responsibility = false;
DMAMEM static uint32_t i2s_tx_buffer[AUDIO_BLOCK_SAMPLES]; //local audio_block_samples should be no larger than global AUDIO_BLOCK_SAMPLES
DMAMEM static uint64_t i2s_tx_buffer[AUDIO_BLOCK_SAMPLES]; //local audio_block_samples should be no larger than global AUDIO_BLOCK_SAMPLES
DMAChannel AudioOutputI2S_F32::dma(false);
float AudioOutputI2S_F32::sample_rate_Hz = AUDIO_SAMPLE_RATE;
@ -103,18 +108,18 @@ void AudioOutputI2S_F32::begin(void)
#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);
dma.TCD->NBYTES_MLNO = 2;
dma.TCD->SOFF = 4;
dma.TCD->ATTR = DMA_TCD_ATTR_SSIZE(2) | DMA_TCD_ATTR_DSIZE(2);
dma.TCD->NBYTES_MLNO = 4;
//dma.TCD->SLAST = -sizeof(i2s_tx_buffer); //original
dma.TCD->SLAST = -I2S_BUFFER_TO_USE_BYTES;
dma.TCD->DADDR = &I2S0_TDR0;
dma.TCD->DADDR = (void *)((uint32_t)&I2S0_TDR0);
dma.TCD->DOFF = 0;
//dma.TCD->CITER_ELINKNO = sizeof(i2s_tx_buffer) / 2; //original
dma.TCD->CITER_ELINKNO = I2S_BUFFER_TO_USE_BYTES / 2;
dma.TCD->CITER_ELINKNO = I2S_BUFFER_TO_USE_BYTES / 4;
dma.TCD->DLASTSGA = 0;
//dma.TCD->BITER_ELINKNO = sizeof(i2s_tx_buffer) / 2; //original
dma.TCD->BITER_ELINKNO = I2S_BUFFER_TO_USE_BYTES / 2;
dma.TCD->BITER_ELINKNO = I2S_BUFFER_TO_USE_BYTES / 4;
dma.TCD->CSR = DMA_TCD_CSR_INTHALF | DMA_TCD_CSR_INTMAJOR;
#endif
dma.triggerAtHardwareEvent(DMAMUX_SOURCE_I2S0_TX);
@ -137,8 +142,8 @@ void AudioOutputI2S_F32::begin(void)
void AudioOutputI2S_F32::isr(void)
{
#if defined(KINETISK)
int16_t *dest;
audio_block_t *blockL, *blockR;
int32_t *dest;
audio_block_f32_t *blockL, *blockR;
uint32_t saddr, offsetL, offsetR;
saddr = (uint32_t)(dma.TCD->SADDR);
@ -148,12 +153,12 @@ void AudioOutputI2S_F32::isr(void)
// DMA is transmitting the first half of the buffer
// so we must fill the second half
//dest = (int16_t *)&i2s_tx_buffer[AUDIO_BLOCK_SAMPLES/2]; //original
dest = (int16_t *)&i2s_tx_buffer[audio_block_samples/2];
dest = (int32_t *)&i2s_tx_buffer[audio_block_samples/2];
if (AudioOutputI2S_F32::update_responsibility) AudioStream_F32::update_all();
} else {
// DMA is transmitting the second half of the buffer
// so we must fill the first half
dest = (int16_t *)i2s_tx_buffer;
dest = (int32_t *)i2s_tx_buffer;
}
blockL = AudioOutputI2S_F32::block_left_1st;
@ -178,27 +183,27 @@ void AudioOutputI2S_F32::isr(void)
}
*/
int16_t *d = dest;
int32_t *d = dest;
if (blockL && blockR) {
//memcpy_tointerleaveLR(dest, blockL->data + offsetL, blockR->data + offsetR);
//memcpy_tointerleaveLRwLen(dest, blockL->data + offsetL, blockR->data + offsetR, audio_block_samples/2);
int16_t *pL = blockL->data + offsetL;
int16_t *pR = blockR->data + offsetR;
for (int i=0; i < audio_block_samples/2; i++) { *d++ = *pL++; *d++ = *pR++; } //interleave
float32_t *pL = blockL->data + offsetL;
float32_t *pR = blockR->data + offsetR;
for (int i=0; i < audio_block_samples/2; i++) { *d++ = f32_to_i32(*pL++); *d++ = f32_to_i32(*pR++); } //interleave
offsetL += audio_block_samples / 2;
offsetR += audio_block_samples / 2;
} else if (blockL) {
//memcpy_tointerleaveLR(dest, blockL->data + offsetL, blockR->data + offsetR);
int16_t *pL = blockL->data + offsetL;
for (int i=0; i < audio_block_samples / 2 * 2; i+=2) { *(d+i) = *pL++; } //interleave
float32_t *pL = blockL->data + offsetL;
for (int i=0; i < audio_block_samples / 2 * 2; i+=2) { *(d+i) = f32_to_i32(*pL++); } //interleave
offsetL += audio_block_samples / 2;
} else if (blockR) {
int16_t *pR = blockR->data + offsetR;
for (int i=0; i < audio_block_samples /2 * 2; i+=2) { *(d+i) = *pR++; } //interleave
float32_t *pR = blockR->data + offsetR;
for (int i=0; i < audio_block_samples /2 * 2; i+=2) { *(d+i) = f32_to_i32(*pR++); } //interleave
offsetR += audio_block_samples / 2;
} else {
//memset(dest,0,AUDIO_BLOCK_SAMPLES * 2);
memset(dest,0,audio_block_samples * 2);
memset(dest,0,audio_block_samples * 4);
return;
}
@ -207,7 +212,7 @@ void AudioOutputI2S_F32::isr(void)
AudioOutputI2S_F32::block_left_offset = offsetL;
} else {
AudioOutputI2S_F32::block_left_offset = 0;
AudioStream::release(blockL);
AudioStream_F32::release(blockL);
AudioOutputI2S_F32::block_left_1st = AudioOutputI2S_F32::block_left_2nd;
AudioOutputI2S_F32::block_left_2nd = NULL;
}
@ -216,7 +221,7 @@ void AudioOutputI2S_F32::isr(void)
AudioOutputI2S_F32::block_right_offset = offsetR;
} else {
AudioOutputI2S_F32::block_right_offset = 0;
AudioStream::release(blockR);
AudioStream_F32::release(blockR);
AudioOutputI2S_F32::block_right_1st = AudioOutputI2S_F32::block_right_2nd;
AudioOutputI2S_F32::block_right_2nd = NULL;
}
@ -302,7 +307,6 @@ void AudioOutputI2S_F32::update(void)
//audio_block_t *block = receiveReadOnly();
//if (block) release(block);
audio_block_t *block;
audio_block_f32_t *block_f32;
block_f32 = receiveReadOnly_f32(0); // input 0 = left channel
if (block_f32) {
@ -315,52 +319,42 @@ void AudioOutputI2S_F32::update(void)
//Serial.print("AudioOutputI2S_F32: audio_block_samples = ");
//Serial.println(audio_block_samples);
//convert F32 to Int16
block = AudioStream::allocate();
convert_f32_to_i16(block_f32->data, block->data, audio_block_samples);
AudioStream_F32::release(block_f32);
//now process the data blocks
__disable_irq();
if (block_left_1st == NULL) {
block_left_1st = block;
block_left_1st = block_f32;
block_left_offset = 0;
__enable_irq();
} else if (block_left_2nd == NULL) {
block_left_2nd = block;
block_left_2nd = block_f32;
__enable_irq();
} else {
audio_block_t *tmp = block_left_1st;
audio_block_f32_t *tmp = block_left_1st;
block_left_1st = block_left_2nd;
block_left_2nd = block;
block_left_2nd = block_f32;
block_left_offset = 0;
__enable_irq();
AudioStream::release(tmp);
AudioStream_F32::release(tmp);
}
}
block_f32 = receiveReadOnly_f32(1); // input 1 = right channel
if (block_f32) {
//convert F32 to Int16
block = AudioStream::allocate();
convert_f32_to_i16(block_f32->data, block->data, audio_block_samples);
AudioStream_F32::release(block_f32);
__disable_irq();
if (block_right_1st == NULL) {
block_right_1st = block;
block_right_1st = block_f32;
block_right_offset = 0;
__enable_irq();
} else if (block_right_2nd == NULL) {
block_right_2nd = block;
block_right_2nd = block_f32;
__enable_irq();
} else {
audio_block_t *tmp = block_right_1st;
audio_block_f32_t *tmp = block_right_1st;
block_right_1st = block_right_2nd;
block_right_2nd = block;
block_right_2nd = block_f32;
block_right_offset = 0;
__enable_irq();
AudioStream::release(tmp);
AudioStream_F32::release(tmp);
}
}
}
@ -432,21 +426,21 @@ void AudioOutputI2S_F32::config_i2s(void)
I2S0_TMR = 0;
I2S0_TCR1 = I2S_TCR1_TFW(1); // watermark at half fifo size
I2S0_TCR2 = I2S_TCR2_SYNC(0) | I2S_TCR2_BCP | I2S_TCR2_MSEL(1)
| I2S_TCR2_BCD | I2S_TCR2_DIV(3);
| I2S_TCR2_BCD | I2S_TCR2_DIV(1);
I2S0_TCR3 = I2S_TCR3_TCE;
I2S0_TCR4 = I2S_TCR4_FRSZ(1) | I2S_TCR4_SYWD(15) | I2S_TCR4_MF
I2S0_TCR4 = I2S_TCR4_FRSZ(1) | I2S_TCR4_SYWD(31) | I2S_TCR4_MF
| I2S_TCR4_FSE | I2S_TCR4_FSP | I2S_TCR4_FSD;
I2S0_TCR5 = I2S_TCR5_WNW(15) | I2S_TCR5_W0W(15) | I2S_TCR5_FBT(15);
I2S0_TCR5 = I2S_TCR5_WNW(31) | I2S_TCR5_W0W(31) | I2S_TCR5_FBT(31);
// configure receiver (sync'd to transmitter clocks)
I2S0_RMR = 0;
I2S0_RCR1 = I2S_RCR1_RFW(1);
I2S0_RCR2 = I2S_RCR2_SYNC(1) | I2S_TCR2_BCP | I2S_RCR2_MSEL(1)
| I2S_RCR2_BCD | I2S_RCR2_DIV(3);
| I2S_RCR2_BCD | I2S_RCR2_DIV(1);
I2S0_RCR3 = I2S_RCR3_RCE;
I2S0_RCR4 = I2S_RCR4_FRSZ(1) | I2S_RCR4_SYWD(15) | I2S_RCR4_MF
I2S0_RCR4 = I2S_RCR4_FRSZ(1) | I2S_RCR4_SYWD(31) | I2S_RCR4_MF
| I2S_RCR4_FSE | I2S_RCR4_FSP | I2S_RCR4_FSD;
I2S0_RCR5 = I2S_RCR5_WNW(15) | I2S_RCR5_W0W(15) | I2S_RCR5_FBT(15);
I2S0_RCR5 = I2S_RCR5_WNW(31) | I2S_RCR5_W0W(31) | I2S_RCR5_FBT(31);
// configure pin mux for 3 clock signals
CORE_PIN23_CONFIG = PORT_PCR_MUX(6); // pin 23, PTC2, I2S0_TX_FS (LRCLK)

@ -32,6 +32,7 @@
#include "AudioStream.h"
#include "DMAChannel.h"
float setI2SFreq(const float freq_Hz);
class AudioOutputI2S_F32 : public AudioStream_F32
{
@ -52,14 +53,14 @@ public:
protected:
//AudioOutputI2S_F32(const AudioSettings &settings): AudioStream_F32(2, inputQueueArray) {} // to be used only inside AudioOutputI2Sslave !!
static void config_i2s(void);
static audio_block_t *block_left_1st;
static audio_block_t *block_right_1st;
static audio_block_f32_t *block_left_1st;
static audio_block_f32_t *block_right_1st;
static bool update_responsibility;
static DMAChannel dma;
static void isr(void);
private:
static audio_block_t *block_left_2nd;
static audio_block_t *block_right_2nd;
static audio_block_f32_t *block_left_2nd;
static audio_block_f32_t *block_right_2nd;
static uint16_t block_left_offset;
static uint16_t block_right_offset;
audio_block_f32_t *inputQueueArray[2];

Loading…
Cancel
Save