Browse Source

Merge pull request #358 from alex6679/master

using the spdif configuration of AudioOutputSPDIF3 and more
dds
Paul Stoffregen 4 years ago
parent
commit
05265df196
No account linked to committer's email address
6 changed files with 143 additions and 222 deletions
  1. +28
    -30
      Resampler.cpp
  2. +9
    -2
      Resampler.h
  3. +64
    -144
      async_input_spdif3.cpp
  4. +11
    -20
      async_input_spdif3.h
  5. +30
    -26
      examples/HardwareTesting/PassThroughAsyncSpdif/PassThroughAsyncSpdif.ino
  6. +1
    -0
      output_spdif3.h

+ 28
- 30
Resampler.cpp View File

#include "Resampler.h" #include "Resampler.h"
#include <math.h> #include <math.h>


Resampler::Resampler(StepAdaptionParameters settings){
Resampler::Resampler(float attenuation, int32_t minHalfFilterLength, int32_t maxHalfFilterLength, StepAdaptionParameters settings): _targetAttenuation(attenuation)
{
_maxHalfFilterLength=max(1, min(MAX_HALF_FILTER_LENGTH, maxHalfFilterLength));
_minHalfFilterLength=max(1, min(maxHalfFilterLength, minHalfFilterLength));
#ifdef DEBUG_RESAMPLER #ifdef DEBUG_RESAMPLER
while (!Serial); while (!Serial);
#endif #endif
double Resampler::getStep() const { double Resampler::getStep() const {
return _stepAdapted; return _stepAdapted;
} }
double Resampler::getAttenuation() const {
return _attenuation;
}
int32_t Resampler::getHalfFilterLength() const{
return _halfFilterLength;
}
void Resampler::reset(){ void Resampler::reset(){
_initialized=false; _initialized=false;
} }
void Resampler::configure(float fs, float newFs, float attenuation, int32_t minHalfFilterLength){
void Resampler::configure(float fs, float newFs){
// Serial.print("configure, fs: "); // Serial.print("configure, fs: ");
// Serial.println(fs); // Serial.println(fs);
if (fs<=0. || newFs <=0.){ if (fs<=0. || newFs <=0.){
_attenuation=0;
_halfFilterLength=0;
_initialized=false; _initialized=false;
return; return;
} }
_attenuation=_targetAttenuation;
_step=(double)fs/newFs; _step=(double)fs/newFs;
_configuredStep=_step; _configuredStep=_step;
_stepAdapted=_step; _stepAdapted=_step;
_oldDiffs[0]=0.; _oldDiffs[0]=0.;
_oldDiffs[1]=0.; _oldDiffs[1]=0.;
for (uint8_t i =0; i< MAX_NO_CHANNELS; i++){ for (uint8_t i =0; i< MAX_NO_CHANNELS; i++){
memset(_buffer[i], 0, sizeof(float)*MAX_HALF_FILTER_LENGTH*2);
memset(_buffer[i], 0, sizeof(float)*_maxHalfFilterLength*2);
} }


float cutOffFrequ, kaiserBeta; float cutOffFrequ, kaiserBeta;
_overSamplingFactor=1024; _overSamplingFactor=1024;
if (fs <= newFs){ if (fs <= newFs){
_attenuation=0;
cutOffFrequ=1.; cutOffFrequ=1.;
kaiserBeta=10; kaiserBeta=10;
_halfFilterLength=minHalfFilterLength;
_halfFilterLength=min(_minHalfFilterLength,_maxHalfFilterLength);
} }
else{ else{
cutOffFrequ=newFs/fs; cutOffFrequ=newFs/fs;
Serial.print("b: "); Serial.print("b: ");
Serial.println(b); Serial.println(b);
#endif #endif
double hfl=(int32_t)((attenuation-8)/(2.*2.285*TWO_PI*b)+0.5);
if (hfl >= minHalfFilterLength && hfl <= MAX_HALF_FILTER_LENGTH){
double hfl=(int32_t)((_attenuation-8)/(2.*2.285*TWO_PI*b)+0.5);
if (hfl >= _minHalfFilterLength && hfl <= _maxHalfFilterLength){
_halfFilterLength=hfl; _halfFilterLength=hfl;
#ifdef DEBUG_RESAMPLER
Serial.print("Attenuation: ");
#endif
} }
else if (hfl < minHalfFilterLength){
_halfFilterLength=minHalfFilterLength;
attenuation=((2*_halfFilterLength+1)-1)*(2.285*TWO_PI*b)+8;
#ifdef DEBUG_RESAMPLER
Serial.println("Resmapler: sinc filter length increased");
Serial.print("Attenuation increased to ");
#endif
else if (hfl < _minHalfFilterLength){
_halfFilterLength=_minHalfFilterLength;
_attenuation=((2*_halfFilterLength+1)-1)*(2.285*TWO_PI*b)+8;
} }
else{ else{
_halfFilterLength=MAX_HALF_FILTER_LENGTH;
attenuation=((2*_halfFilterLength+1)-1)*(2.285*TWO_PI*b)+8;
#ifdef DEBUG_RESAMPLER
Serial.println("Resmapler: needed sinc filter length too long");
Serial.print("Attenuation decreased to ");
#endif
_halfFilterLength=_maxHalfFilterLength;
_attenuation=((2*_halfFilterLength+1)-1)*(2.285*TWO_PI*b)+8;
} }
#ifdef DEBUG_RESAMPLER
Serial.print(attenuation);
Serial.println("dB");
#endif
if (attenuation>50.){
kaiserBeta=0.1102*(attenuation-8.7);
if (_attenuation>50.){
kaiserBeta=0.1102*(_attenuation-8.7);
} }
else if (21<=attenuation && attenuation<=50){
kaiserBeta=0.5842*(float)pow(attenuation-21.,0.4)+0.07886*(attenuation-21.);
else if (21<=_attenuation && _attenuation<=50){
kaiserBeta=0.5842*(float)pow(_attenuation-21.,0.4)+0.07886*(_attenuation-21.);
} }
else{ else{
kaiserBeta=0.; kaiserBeta=0.;

+ 9
- 2
Resampler.h View File

double ki=0.00012; double ki=0.00012;
double kd= 1.8; double kd= 1.8;
}; };
Resampler(StepAdaptionParameters settings=StepAdaptionParameters());
Resampler(float attenuation=100, int32_t minHalfFilterLength=20, int32_t maxHalfFilterLength=80, StepAdaptionParameters settings=StepAdaptionParameters());
void reset(); void reset();
///@param attenuation target attenuation [dB] of the anti-aliasing filter. Only used if newFs<fs. The attenuation can't be reached if the needed filter length exceeds 2*MAX_FILTER_SAMPLES+1 ///@param attenuation target attenuation [dB] of the anti-aliasing filter. Only used if newFs<fs. The attenuation can't be reached if the needed filter length exceeds 2*MAX_FILTER_SAMPLES+1
///@param minHalfFilterLength If newFs >= fs, the filter length of the resampling filter is 2*minHalfFilterLength+1. If fs y newFs the filter is maybe longer to reach the desired attenuation ///@param minHalfFilterLength If newFs >= fs, the filter length of the resampling filter is 2*minHalfFilterLength+1. If fs y newFs the filter is maybe longer to reach the desired attenuation
void configure(float fs, float newFs, float attenuation=100, int32_t minHalfFilterLength=20);
void configure(float fs, float newFs);
///@param input0 first input array/ channel ///@param input0 first input array/ channel
///@param input1 second input array/ channel ///@param input1 second input array/ channel
///@param inputLength length of each input array ///@param inputLength length of each input array
void addToPos(double val); void addToPos(double val);
void fixStep(); void fixStep();
bool initialized() const; bool initialized() const;
double getAttenuation() const;
int32_t getHalfFilterLength() const;
//resampling NOCHANNELS channels. Performance is increased a lot if the number of channels is known at compile time -> the number of channels is a template argument //resampling NOCHANNELS channels. Performance is increased a lot if the number of channels is known at compile time -> the number of channels is a template argument
template <uint8_t NOCHANNELS> template <uint8_t NOCHANNELS>
float _buffer[MAX_NO_CHANNELS][MAX_HALF_FILTER_LENGTH*2]; float _buffer[MAX_NO_CHANNELS][MAX_HALF_FILTER_LENGTH*2];
float* _endOfBuffer[MAX_NO_CHANNELS]; float* _endOfBuffer[MAX_NO_CHANNELS];


int32_t _minHalfFilterLength;
int32_t _maxHalfFilterLength;
int32_t _overSamplingFactor; int32_t _overSamplingFactor;
int32_t _halfFilterLength; int32_t _halfFilterLength;
int32_t _filterLength; int32_t _filterLength;
double _cPos; double _cPos;
double _sum; double _sum;
double _oldDiffs[2]; double _oldDiffs[2];
double _attenuation=0;
float _targetAttenuation=100;
}; };


#endif #endif

+ 64
- 144
async_input_spdif3.cpp View File

#if defined(__IMXRT1052__) || defined(__IMXRT1062__) #if defined(__IMXRT1052__) || defined(__IMXRT1062__)


#include "async_input_spdif3.h" #include "async_input_spdif3.h"
#include "output_spdif3.h"

#include "biquad.h" #include "biquad.h"
#include <utility/imxrt_hw.h> #include <utility/imxrt_hw.h>
//Parameters //Parameters
#define SPDIF_RX_BUFFER_LENGTH AUDIO_BLOCK_SAMPLES #define SPDIF_RX_BUFFER_LENGTH AUDIO_BLOCK_SAMPLES
const int32_t bufferLength=8*AUDIO_BLOCK_SAMPLES; const int32_t bufferLength=8*AUDIO_BLOCK_SAMPLES;
const uint16_t noSamplerPerIsr=SPDIF_RX_BUFFER_LENGTH/4; const uint16_t noSamplerPerIsr=SPDIF_RX_BUFFER_LENGTH/4;
const float toFloatAudio= 1.f/pow(2., 23.);
} }
volatile bool AsyncAudioInputSPDIF3::resetResampler=true;


#ifdef DEBUG_SPDIF_IN #ifdef DEBUG_SPDIF_IN
volatile bool AsyncAudioInputSPDIF3::bufferOverflow=false; volatile bool AsyncAudioInputSPDIF3::bufferOverflow=false;
volatile int32_t AsyncAudioInputSPDIF3::buffer_offset = 0; // read by resample/ written in spdif input isr -> copied at the beginning of 'resmaple' protected by __disable_irq() in resample volatile int32_t AsyncAudioInputSPDIF3::buffer_offset = 0; // read by resample/ written in spdif input isr -> copied at the beginning of 'resmaple' protected by __disable_irq() in resample
int32_t AsyncAudioInputSPDIF3::resample_offset = 0; // read/written by resample/ read in spdif input isr -> no protection needed? int32_t AsyncAudioInputSPDIF3::resample_offset = 0; // read/written by resample/ read in spdif input isr -> no protection needed?


volatile bool AsyncAudioInputSPDIF3::lockChanged=false;
volatile bool AsyncAudioInputSPDIF3::locked=false;
DMAChannel AsyncAudioInputSPDIF3::dma(false); DMAChannel AsyncAudioInputSPDIF3::dma(false);


AsyncAudioInputSPDIF3::~AsyncAudioInputSPDIF3(){ AsyncAudioInputSPDIF3::~AsyncAudioInputSPDIF3(){
delete quantizer[1]; delete quantizer[1];
} }


PROGMEM
AsyncAudioInputSPDIF3::AsyncAudioInputSPDIF3(bool dither, bool noiseshaping,float attenuation, int32_t minHalfFilterLength) : AudioStream(0, NULL) {
_attenuation=attenuation;
_minHalfFilterLength=minHalfFilterLength;
FLASHMEM
AsyncAudioInputSPDIF3::AsyncAudioInputSPDIF3(bool dither, bool noiseshaping,float attenuation, int32_t minHalfFilterLength, int32_t maxHalfFilterLength):
AudioStream(0, NULL),
_resampler(attenuation, minHalfFilterLength, maxHalfFilterLength)
{
const float factor = powf(2, 15)-1.f; // to 16 bit audio const float factor = powf(2, 15)-1.f; // to 16 bit audio
quantizer[0]=new Quantizer(AUDIO_SAMPLE_RATE_EXACT); quantizer[0]=new Quantizer(AUDIO_SAMPLE_RATE_EXACT);
quantizer[0]->configure(noiseshaping, dither, factor); quantizer[0]->configure(noiseshaping, dither, factor);
quantizer[1]->configure(noiseshaping, dither, factor); quantizer[1]->configure(noiseshaping, dither, factor);
begin(); begin();
} }
PROGMEM
FLASHMEM
void AsyncAudioInputSPDIF3::begin() void AsyncAudioInputSPDIF3::begin()
{ {
AudioOutputSPDIF3::config_spdif3();
dma.begin(true); // Allocate the DMA channel first dma.begin(true); // Allocate the DMA channel first
const uint32_t noByteMinorLoop=2*4; const uint32_t noByteMinorLoop=2*4;
dma.TCD->SOFF = 4; dma.TCD->SOFF = 4;
dma.TCD->DADDR = spdif_rx_buffer; dma.TCD->DADDR = spdif_rx_buffer;
dma.triggerAtHardwareEvent(DMAMUX_SOURCE_SPDIF_RX); dma.triggerAtHardwareEvent(DMAMUX_SOURCE_SPDIF_RX);


SPDIF_SCR |=SPDIF_SCR_DMA_RX_EN; //DMA Receive Request Enable
//SPDIF_SCR |=SPDIF_SCR_DMA_RX_EN; //DMA Receive Request Enable
dma.enable(); dma.enable();
dma.attachInterrupt(isr); dma.attachInterrupt(isr);
config_spdifIn();
#ifdef DEBUG_SPDIF_IN #ifdef DEBUG_SPDIF_IN
while (!Serial); while (!Serial);
#endif #endif
_bufferLPFilter.numStages=1; _bufferLPFilter.numStages=1;
_bufferLPFilter.pState=new float[2]; _bufferLPFilter.pState=new float[2];
getCoefficients(_bufferLPFilter.pCoeffs, BiquadType::LOW_PASS, 0., 5., AUDIO_SAMPLE_RATE_EXACT/AUDIO_BLOCK_SAMPLES, 0.5); getCoefficients(_bufferLPFilter.pCoeffs, BiquadType::LOW_PASS, 0., 5., AUDIO_SAMPLE_RATE_EXACT/AUDIO_BLOCK_SAMPLES, 0.5);
SPDIF_SCR &=(~SPDIF_SCR_RXFIFO_OFF_ON); //receive fifo is turned on again
SPDIF_SRCD = 0;
SPDIF_SCR |= SPDIF_SCR_DMA_RX_EN;
CORE_PIN15_CONFIG = 3;
IOMUXC_SPDIF_IN_SELECT_INPUT = 0; // GPIO_AD_B1_03_ALT3
} }
bool AsyncAudioInputSPDIF3::isLocked() const {
__disable_irq();
bool l=locked;
__enable_irq();
return l;
}
void AsyncAudioInputSPDIF3::spdif_interrupt(){
if(SPDIF_SIS & SPDIF_SIS_LOCK){
if (!locked){
locked=true;
lockChanged=true;
}
}
else if(SPDIF_SIS & SPDIF_SIS_LOCKLOSS){
if (locked){
locked=false;
lockChanged=true;
resetResampler=true;
}
}
SPDIF_SIC |= SPDIF_SIC_LOCKLOSS;//clear SPDIF_SIC_LOCKLOSS interrupt
SPDIF_SIC |= SPDIF_SIC_LOCK; //clear SPDIF_SIC_LOCK interrupt
bool AsyncAudioInputSPDIF3::isLocked() {
return (SPDIF_SRPC & SPDIF_SRPC_LOCK) == SPDIF_SRPC_LOCK;
} }


void AsyncAudioInputSPDIF3::resample(int16_t* data_left, int16_t* data_right, int32_t& block_offset){ void AsyncAudioInputSPDIF3::resample(int16_t* data_left, int16_t* data_right, int32_t& block_offset){
block_offset=0; block_offset=0;
if(!_resampler.initialized()){
return;
}
__disable_irq();
if(!locked){
__enable_irq();
if(!_resampler.initialized() || !isLocked()){
return; return;
} }
int32_t bOffset=buffer_offset; int32_t bOffset=buffer_offset;
int32_t resOffset=resample_offset; int32_t resOffset=resample_offset;
__enable_irq();
uint16_t inputBufferStop = bOffset >= resOffset ? bOffset-resOffset : bufferLength-resOffset; uint16_t inputBufferStop = bOffset >= resOffset ? bOffset-resOffset : bufferLength-resOffset;
if (inputBufferStop==0){ if (inputBufferStop==0){
#endif #endif
float *destR = &(bufferR[buffer_offset]); float *destR = &(bufferR[buffer_offset]);
float *destL = &(bufferL[buffer_offset]); float *destL = &(bufferL[buffer_offset]);
const float factor= pow(2., 23.)+1;
do { do {
int32_t n=(*src) & 0x800000 ? (*src)|0xFF800000 : (*src) & 0xFFFFFF; int32_t n=(*src) & 0x800000 ? (*src)|0xFF800000 : (*src) & 0xFFFFFF;
*destL++ = (float)(n)/factor;
*destL++ = (float)(n)*toFloatAudio;
++src; ++src;


n=(*src) & 0x800000 ? (*src)|0xFF800000 : (*src) & 0xFFFFFF; n=(*src) & 0x800000 ? (*src)|0xFF800000 : (*src) & 0xFFFFFF;
*destR++ = (float)(n)/factor;
*destR++ = (float)(n)*toFloatAudio;
++src; ++src;
} while (src < end); } while (src < end);
buffer_offset=(buffer_offset+SPDIF_RX_BUFFER_LENGTH/4)%bufferLength; buffer_offset=(buffer_offset+SPDIF_RX_BUFFER_LENGTH/4)%bufferLength;
} }
double AsyncAudioInputSPDIF3::getNewValidInputFrequ(){ double AsyncAudioInputSPDIF3::getNewValidInputFrequ(){
//page 2129: FrequMeas[23:0]=FreqMeas_CLK / BUS_CLK * 2^10 * GAIN //page 2129: FrequMeas[23:0]=FreqMeas_CLK / BUS_CLK * 2^10 * GAIN
if (SPDIF_SRPC & SPDIF_SRPC_LOCK){
const double f=(float)F_BUS_ACTUAL/(1024.*1024.*24.*128.);// bit clock = 128 * sampling frequency
if (isLocked()){
const double f=(float)F_BUS_ACTUAL/(1024.*1024.*AudioOutputSPDIF3::dpll_Gain()*128.);// bit clock = 128 * sampling frequency
const double freqMeas=(SPDIF_SRFM & 0xFFFFFF)*f; const double freqMeas=(SPDIF_SRFM & 0xFFFFFF)*f;
if (_lastValidInputFrequ != freqMeas){//frequency not stable yet; if (_lastValidInputFrequ != freqMeas){//frequency not stable yet;
_lastValidInputFrequ=freqMeas; _lastValidInputFrequ=freqMeas;
} }


void AsyncAudioInputSPDIF3::configure(){ void AsyncAudioInputSPDIF3::configure(){
__disable_irq();
if(resetResampler){
if(!isLocked()){
_resampler.reset(); _resampler.reset();
resetResampler=false;
}
if(!locked){
__enable_irq();
#ifdef DEBUG_SPDIF_IN
Serial.println("lock lost");
#endif
return; return;
}
}
#ifdef DEBUG_SPDIF_IN #ifdef DEBUG_SPDIF_IN
const bool bOverf=bufferOverflow; const bool bOverf=bufferOverflow;
bufferOverflow=false; bufferOverflow=false;
#endif
const bool lc=lockChanged;
__enable_irq();

#ifdef DEBUG_SPDIF_IN
if (bOverf){ if (bOverf){
Serial.print("buffer overflow, buffer offset: "); Serial.print("buffer overflow, buffer offset: ");
Serial.print(buffer_offset); Serial.print(buffer_offset);
} }
} }
#endif #endif
if (lc || !_resampler.initialized()){
const double inputF=getNewValidInputFrequ(); //returns: -1 ... invalid frequency
if (inputF > 0.){
const double inputF=getNewValidInputFrequ(); //returns: -1 ... invalid frequency
if (inputF > 0.){
//we got a valid sample frequency
const double frequDiff=inputF/_inputFrequency-1.;
if (abs(frequDiff) > 0.01 || !_resampler.initialized()){
//the new sample frequency differs from the last one -> configure the _resampler again
_inputFrequency=inputF;
_targetLatencyS=max(0.001,(noSamplerPerIsr*3./2./_inputFrequency));
_maxLatency=max(2.*_blockDuration, 2*noSamplerPerIsr/_inputFrequency);
const int32_t targetLatency=round(_targetLatencyS*inputF);
__disable_irq(); __disable_irq();
lockChanged=false; //only reset lockChanged if a valid frequency was received (inputFrequ > 0.)
resample_offset = targetLatency <= buffer_offset ? buffer_offset - targetLatency : bufferLength -(targetLatency-buffer_offset);
__enable_irq(); __enable_irq();
//we got a valid sample frequency
const double frequDiff=inputF/_inputFrequency-1.;
if (abs(frequDiff) > 0.01 || !_resampler.initialized()){
//the new sample frequency differs from the last one -> configure the _resampler again
_inputFrequency=inputF;
const int32_t targetLatency=round(_targetLatencyS*inputF);
_targetLatencyS=max(0.001,(noSamplerPerIsr*3./2./_inputFrequency));
__disable_irq();
resample_offset = targetLatency <= buffer_offset ? buffer_offset - targetLatency : bufferLength -(targetLatency-buffer_offset);
__enable_irq();
_resampler.configure(inputF, AUDIO_SAMPLE_RATE_EXACT, _attenuation, _minHalfFilterLength);
#ifdef DEBUG_SPDIF_IN
Serial.print("_maxLatency: ");
Serial.println(_maxLatency);
Serial.print("targetLatency: ");
Serial.println(targetLatency);
Serial.print("relative frequ diff: ");
Serial.println(frequDiff, 8);
Serial.print("configure _resampler with frequency ");
Serial.println(inputF,8);
#endif
}
_resampler.configure(inputF, AUDIO_SAMPLE_RATE_EXACT);
#ifdef DEBUG_SPDIF_IN
Serial.print("_maxLatency: ");
Serial.println(_maxLatency);
Serial.print("targetLatency: ");
Serial.println(targetLatency);
Serial.print("relative frequ diff: ");
Serial.println(frequDiff, 8);
Serial.print("configure _resampler with frequency ");
Serial.println(inputF,8);
#endif
} }
} }
} }
while (resample_offset<0){ while (resample_offset<0){
resample_offset+=bufferLength; resample_offset+=bufferLength;
} }
//int32_t b_offset=buffer_offset;
#ifdef DEBUG_SPDIF_IN #ifdef DEBUG_SPDIF_IN
double bTimeFixed = resample_offset <= buffer_offset ? (buffer_offset-resample_offset-_resampler.getXPos())/_lastValidInputFrequ+dmaOffset : (bufferLength-resample_offset +buffer_offset-_resampler.getXPos())/_lastValidInputFrequ+dmaOffset; //[seconds] double bTimeFixed = resample_offset <= buffer_offset ? (buffer_offset-resample_offset-_resampler.getXPos())/_lastValidInputFrequ+dmaOffset : (bufferLength-resample_offset +buffer_offset-_resampler.getXPos())/_lastValidInputFrequ+dmaOffset; //[seconds]
#endif #endif
__enable_irq(); __enable_irq();
#ifdef DEBUG_SPDIF_IN #ifdef DEBUG_SPDIF_IN
// Serial.print("settled: ");
// Serial.println(settled);
Serial.print("settled: ");
Serial.println(settled);
Serial.print("bTime: "); Serial.print("bTime: ");
Serial.print(bTime*1e6,3);
Serial.println(bTime*1e6,3);
Serial.print("_maxLatency: "); Serial.print("_maxLatency: ");
Serial.println(_maxLatency*1e6,3); Serial.println(_maxLatency*1e6,3);
Serial.print("bTime-dmaOffset: "); Serial.print("bTime-dmaOffset: ");
Serial.print((bTime-dmaOffset)*1e6,3);
Serial.println((bTime-dmaOffset)*1e6,3);
Serial.print(", _blockDuration: "); Serial.print(", _blockDuration: ");
Serial.print(_blockDuration*1e6,3);
Serial.println(_blockDuration*1e6,3);
Serial.print("bTimeFixed: "); Serial.print("bTimeFixed: ");
Serial.print(bTimeFixed*1e6,3);
Serial.println(bTimeFixed*1e6,3);


#endif #endif
preload(&_bufferLPFilter, diff); preload(&_bufferLPFilter, diff);
__disable_irq(); __disable_irq();
double f=_lastValidInputFrequ; double f=_lastValidInputFrequ;
__enable_irq(); __enable_irq();
return f;
return isLocked() ? f : 0.;
} }
double AsyncAudioInputSPDIF3::getTargetLantency() const { double AsyncAudioInputSPDIF3::getTargetLantency() const {
__disable_irq(); __disable_irq();
__enable_irq(); __enable_irq();
return l ; return l ;
} }
void AsyncAudioInputSPDIF3::config_spdifIn(){
//CCM Clock Gating Register 5, imxrt1060_rev1.pdf page 1145
CCM_CCGR5 |=CCM_CCGR5_SPDIF(CCM_CCGR_ON); //turn spdif clock on - necessary for receiver!
SPDIF_SCR |=SPDIF_SCR_RXFIFO_OFF_ON; //turn receive fifo off 1->off, 0->on

SPDIF_SCR&=~(SPDIF_SCR_RXFIFO_CTR); //reset rx fifo control: normal opertation

SPDIF_SCR&=~(SPDIF_SCR_RXFIFOFULL_SEL(3)); //reset rx full select
SPDIF_SCR|=SPDIF_SCR_RXFIFOFULL_SEL(2); //full interrupt if at least 8 sample in Rx left and right FIFOs

SPDIF_SCR|=SPDIF_SCR_RXAUTOSYNC; //Rx FIFO auto sync on

SPDIF_SCR&=(~SPDIF_SCR_USRC_SEL(3)); //No embedded U channel

CORE_PIN15_CONFIG = 3; //pin 15 set to alt3 -> spdif input

/// from eval board sample code
// IOMUXC_SetPinConfig(
// IOMUXC_GPIO_AD_B1_03_SPDIF_IN, /* GPIO_AD_B1_03 PAD functional properties : */
// 0x10B0u); /* Slew Rate Field: Slow Slew Rate
// Drive Strength Field: R0/6
// Speed Field: medium(100MHz)
// Open Drain Enable Field: Open Drain Disabled
// Pull / Keep Enable Field: Pull/Keeper Enabled
// Pull / Keep Select Field: Keeper
// Pull Up / Down Config. Field: 100K Ohm Pull Down
// Hyst. Enable Field: Hysteresis Disabled */
CORE_PIN15_PADCONFIG=0x10B0;
SPDIF_SCR &=(~SPDIF_SCR_RXFIFO_OFF_ON); //receive fifo is turned on again


SPDIF_SRPC &= ~SPDIF_SRPC_CLKSRC_SEL(15); //reset clock selection page 2136
//SPDIF_SRPC |=SPDIF_SRPC_CLKSRC_SEL(6); //if (DPLL Locked) SPDIF_RxClk else tx_clk (SPDIF0_CLK_ROOT)
//page 2129: FrequMeas[23:0]=FreqMeas_CLK / BUS_CLK * 2^10 * GAIN
SPDIF_SRPC &=~SPDIF_SRPC_GAINSEL(7); //reset gain select 0 -> gain = 24*2^10
//SPDIF_SRPC |= SPDIF_SRPC_GAINSEL(3); //gain select: 8*2^10
//==============================================

//interrupts
SPDIF_SIE |= SPDIF_SIE_LOCK; //enable spdif receiver lock interrupt
SPDIF_SIE |=SPDIF_SIE_LOCKLOSS;

lockChanged=true;
attachInterruptVector(IRQ_SPDIF, spdif_interrupt);
NVIC_SET_PRIORITY(IRQ_SPDIF, 208); // 255 = lowest priority, 208 = priority of update
NVIC_ENABLE_IRQ(IRQ_SPDIF);

SPDIF_SIC |= SPDIF_SIC_LOCK; //clear SPDIF_SIC_LOCK interrupt
SPDIF_SIC |= SPDIF_SIC_LOCKLOSS;//clear SPDIF_SIC_LOCKLOSS interrupt
locked=(SPDIF_SRPC & SPDIF_SRPC_LOCK);
double AsyncAudioInputSPDIF3::getAttenuation() const{
return _resampler.getAttenuation();
} }
int32_t AsyncAudioInputSPDIF3::getHalfFilterLength() const{
return _resampler.getHalfFilterLength();
}

#endif #endif



+ 11
- 20
async_input_spdif3.h View File

class AsyncAudioInputSPDIF3 : public AudioStream class AsyncAudioInputSPDIF3 : public AudioStream
{ {
public: public:
///@param attenuation target attenuation [dB] of the anti-aliasing filter. Only used if newFs<fs. The attenuation can't be reached if the needed filter length exceeds 2*MAX_FILTER_SAMPLES+1
///@param minHalfFilterLength If newFs >= fs, the filter length of the resampling filter is 2*minHalfFilterLength+1. If fs y newFs the filter is maybe longer to reach the desired attenuation
AsyncAudioInputSPDIF3(bool dither=true, bool noiseshaping=true,float attenuation=100, int32_t minHalfFilterLength=20);
///@param attenuation target attenuation [dB] of the anti-aliasing filter. Only used if AUDIO_SAMPLE_RATE_EXACT < input sample rate (input fs). The attenuation can't be reached if the needed filter length exceeds 2*MAX_FILTER_SAMPLES+1
///@param minHalfFilterLength If AUDIO_SAMPLE_RATE_EXACT >= input fs), the filter length of the resampling filter is 2*minHalfFilterLength+1. If AUDIO_SAMPLE_RATE_EXACT < input fs the filter is maybe longer to reach the desired attenuation
///@param maxHalfFilterLength Can be used to restrict the maximum filter length at the cost of a lower attenuation
AsyncAudioInputSPDIF3(bool dither=true, bool noiseshaping=true,float attenuation=100, int32_t minHalfFilterLength=20, int32_t maxHalfFilterLength=80);
~AsyncAudioInputSPDIF3(); ~AsyncAudioInputSPDIF3();
virtual void update(void);
void begin(); void begin();
void stop();
virtual void update(void);
double getBufferedTime() const; double getBufferedTime() const;
double getInputFrequency() const; double getInputFrequency() const;
bool isLocked() const;
static bool isLocked();
double getTargetLantency() const; double getTargetLantency() const;
double getAttenuation() const;
int32_t getHalfFilterLength() const;
protected: protected:
static DMAChannel dma; static DMAChannel dma;
static void isr(void); static void isr(void);
static volatile uint32_t microsLast; static volatile uint32_t microsLast;
//==================== //====================


// spdif lock-changed interrupt
static volatile bool locked;
static volatile bool lockChanged;
static volatile bool resetResampler;
static void spdif_interrupt();
#ifdef MEASURE_FREQ
static FrequencyMeasurement frequMeasure;
#endif
//=============================
float _attenuation;
int32_t _minHalfFilterLength;
Resampler _resampler; Resampler _resampler;
Quantizer* quantizer[2]; Quantizer* quantizer[2];
arm_biquad_cascade_df2T_instance_f32 _bufferLPFilter; arm_biquad_cascade_df2T_instance_f32 _bufferLPFilter;
volatile double _bufferedTime; volatile double _bufferedTime;
volatile double _lastValidInputFrequ; volatile double _lastValidInputFrequ;
double _inputFrequency;
double _inputFrequency=0.;
double _targetLatencyS; //target latency [seconds] double _targetLatencyS; //target latency [seconds]
const double _blockDuration=AUDIO_BLOCK_SAMPLES/AUDIO_SAMPLE_RATE; //[seconds]
const double _maxLatency=2.*_blockDuration;
const double _blockDuration=AUDIO_BLOCK_SAMPLES/AUDIO_SAMPLE_RATE_EXACT; //[seconds]
double _maxLatency=2.*_blockDuration;


#ifdef DEBUG_SPDIF_IN #ifdef DEBUG_SPDIF_IN
static volatile bool bufferOverflow; static volatile bool bufferOverflow;

+ 30
- 26
examples/HardwareTesting/PassThroughAsyncSpdif/PassThroughAsyncSpdif.ino View File



#include <Audio.h> #include <Audio.h>


AsyncAudioInputSPDIF3 spdifIn(false, false, 100, 20, 80); //dither = true, noiseshaping = true, anti-aliasing attenuation=100dB, minimum half resampling filter length=20, maximum half resampling filter length=80
AudioOutputSPDIF3 spdifOut; AudioOutputSPDIF3 spdifOut;
AsyncAudioInputSPDIF3 spdifIn(true, true, 100, 20); //dither = true, noiseshaping = true, anti-aliasing attenuation=100dB, minimum resampling filter length=20
//


AudioConnection patchCord1(spdifIn, 0, spdifOut, 0); AudioConnection patchCord1(spdifIn, 0, spdifOut, 0);
AudioConnection patchCord2(spdifIn, 1, spdifOut, 1); AudioConnection patchCord2(spdifIn, 1, spdifOut, 1);


void setup() { void setup() {

// put your setup code here, to run once:
AudioMemory(12); AudioMemory(12);
Serial.begin(57600);
while (!Serial); while (!Serial);


} }


void loop() { void loop() {
double bufferedTine=spdifIn.getBufferedTime();
//double targetLatency = spdifIn.getTargetLantency();
Serial.print("buffered time [micro seconds]: ");
Serial.println(bufferedTine*1e6,2);
// Serial.print(", target: ");
// Serial.println(targetLatency*1e6,2);
double pUsageIn=spdifIn.processorUsage();
Serial.print("processor usage [%]: ");
Serial.println(pUsageIn);

// bool islocked=spdifIn.isLocked();
// Serial.print("isLocked: ");
// Serial.println(islocked);

// double f=spdifIn.getInputFrequency();
// Serial.print("frequency: ");
// Serial.println(f);
// Serial.print("Memory max: ");
// Serial.println(AudioMemoryUsageMax());
delay(500);
}
double bufferedTime=spdifIn.getBufferedTime();
Serial.print("buffered time [micro seconds]: ");
Serial.println(bufferedTime*1e6,2);
Serial.print("locked: ");
Serial.println(spdifIn.isLocked());
Serial.print("input frequency: ");
double inputFrequency=spdifIn.getInputFrequency();
Serial.println(inputFrequency);
Serial.print("anti-aliasing attenuation: ");
Serial.println(spdifIn.getAttenuation());
Serial.print("resampling goup delay [milli seconds]: ");
Serial.println(spdifIn.getHalfFilterLength()/inputFrequency*1e3,2);
Serial.print("half filter length: ");
Serial.println(spdifIn.getHalfFilterLength());
double pUsageIn=spdifIn.processorUsage();
Serial.print("processor usage [%]: ");
Serial.println(pUsageIn);

Serial.print("max number of used blocks: ");
Serial.println(AudioMemoryUsageMax());

delay(500);
}

+ 1
- 0
output_spdif3.h View File

virtual void update(void); virtual void update(void);
void begin(void); void begin(void);
friend class AudioInputSPDIF3; friend class AudioInputSPDIF3;
friend class AsyncAudioInputSPDIF3;
static void mute_PCM(const bool mute); static void mute_PCM(const bool mute);
static bool pll_locked(void); static bool pll_locked(void);
protected: protected:

Loading…
Cancel
Save