Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix use of use_mclk and tx_desc_auto_clear for ESP32 #630

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 11 additions & 4 deletions src/AudioGeneratorWAV.cpp
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/*
AudioGeneratorWAV
Audio output generator that reads 8 and 16-bit WAV files

Copyright (C) 2017 Earle F. Philhower, III

This program is free software: you can redistribute it and/or modify
Expand Down Expand Up @@ -53,7 +53,6 @@ bool AudioGeneratorWAV::isRunning()
return running;
}


// Handle buffered reading, reload each time we run out of data
bool AudioGeneratorWAV::GetBufferedData(int bytes, void *dest)
{
Expand All @@ -65,6 +64,9 @@ bool AudioGeneratorWAV::GetBufferedData(int bytes, void *dest)
buffPtr = 0;
uint32_t toRead = availBytes > buffSize ? buffSize : availBytes;
buffLen = file->read( buff, toRead );
if (toRead == 0 || buffLen != toRead) {
return false; // Unexpected end of file or read error
}
availBytes -= buffLen;
}
if (buffPtr >= buffLen)
Expand Down Expand Up @@ -105,8 +107,13 @@ bool AudioGeneratorWAV::loop()
} while (running && output->ConsumeSample(lastSample));

done:
file->loop();
output->loop();
if (file) {
file->loop();
}

if (output) {
output->loop();
}

return running;
}
Expand Down
35 changes: 23 additions & 12 deletions src/AudioOutputI2S.cpp
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/*
AudioOutputI2S
Base class for I2S interface port

Copyright (C) 2017 Earle F. Philhower, III

This program is free software: you can redistribute it and/or modify
Expand Down Expand Up @@ -29,7 +29,7 @@
#include "AudioOutputI2S.h"

#if defined(ESP32) || defined(ESP8266)
AudioOutputI2S::AudioOutputI2S(int port, int output_mode, int dma_buf_count, int use_apll)
AudioOutputI2S::AudioOutputI2S(int port, int output_mode, int dma_buf_count, int use_apll, int use_mclk, bool tx_desc_auto_clear)
{
this->portNo = port;
this->i2sOn = false;
Expand All @@ -39,6 +39,8 @@ AudioOutputI2S::AudioOutputI2S(int port, int output_mode, int dma_buf_count, int
}
this->output_mode = output_mode;
this->use_apll = use_apll;
this->use_mclk = use_mclk;
this->tx_desc_auto_clear = tx_desc_auto_clear;

//set defaults
mono = false;
Expand Down Expand Up @@ -80,13 +82,18 @@ bool AudioOutputI2S::SetPinout()
return false; // Not allowed

i2s_pin_config_t pins = {
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 4, 0)
.mck_io_num = mclkPin,
#endif
.bck_io_num = bclkPin,
.ws_io_num = wclkPin,
.data_out_num = doutPin,
.data_in_num = I2S_PIN_NO_CHANGE};
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 4, 0)
if (use_mclk) {
pins.mck_io_num = mclkPin;
} else {
pins.mck_io_num = I2S_PIN_NO_CHANGE;
}
#endif

i2s_set_pin((i2s_port_t)portNo, &pins);
return true;
#else
Expand Down Expand Up @@ -202,15 +209,15 @@ bool AudioOutputI2S::begin(bool txDAC)
#if CONFIG_IDF_TARGET_ESP32
mode = (i2s_mode_t)(mode | I2S_MODE_DAC_BUILT_IN);
#else
return false;
return false;
#endif
}
else if (output_mode == INTERNAL_PDM)
{
#if CONFIG_IDF_TARGET_ESP32
mode = (i2s_mode_t)(mode | I2S_MODE_PDM);
#else
return false;
return false;
#endif
}

Expand Down Expand Up @@ -250,13 +257,17 @@ bool AudioOutputI2S::begin(bool txDAC)
.dma_buf_count = dma_buf_count,
.dma_buf_len = 128,
.use_apll = use_apll, // Use audio PLL
.tx_desc_auto_clear = true, // Silence on underflow
.fixed_mclk = use_mclk, // Unused
.tx_desc_auto_clear = tx_desc_auto_clear, // Clear tx descriptor on underflow - seems like a bad idea
};
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 4, 0)
.mclk_multiple = I2S_MCLK_MULTIPLE_256, // Unused
.bits_per_chan = I2S_BITS_PER_CHAN_DEFAULT // Use bits per sample
i2s_config_dac.fixed_mclk = use_mclk; // If non-zero, this will be used as the fixed mclk frequency

if (use_mclk) {
i2s_config_dac.mclk_multiple = I2S_MCLK_MULTIPLE_256; // Unused
i2s_config_dac.bits_per_chan = I2S_BITS_PER_CHAN_DEFAULT; // Use bits per sample
}
#endif
};

audioLogger->printf("+%d %p\n", portNo, &i2s_config_dac);
if (i2s_driver_install((i2s_port_t)portNo, &i2s_config_dac, 0, NULL) != ESP_OK)
{
Expand Down
20 changes: 11 additions & 9 deletions src/AudioOutputI2S.h
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/*
AudioOutputI2S
Base class for an I2S output port

Copyright (C) 2017 Earle F. Philhower, III

This program is free software: you can redistribute it and/or modify
Expand Down Expand Up @@ -31,26 +31,26 @@ class AudioOutputI2S : public AudioOutput
{
public:
#if defined(ESP32) || defined(ESP8266)
AudioOutputI2S(int port=0, int output_mode=EXTERNAL_I2S, int dma_buf_count = 8, int use_apll=APLL_DISABLE);
AudioOutputI2S(int port=0, int output_mode=EXTERNAL_I2S, int dma_buf_count = 8, int use_apll=APLL_DISABLE, int use_mclk = 0, bool tx_desc_auto_clear = false);
enum : int { APLL_AUTO = -1, APLL_ENABLE = 1, APLL_DISABLE = 0 };
enum : int { EXTERNAL_I2S = 0, INTERNAL_DAC = 1, INTERNAL_PDM = 2 };
#elif defined(ARDUINO_ARCH_RP2040)
AudioOutputI2S(long sampleRate = 44100, pin_size_t sck = 26, pin_size_t data = 28);
#endif
bool SetPinout(int bclkPin, int wclkPin, int doutPin);
bool SetPinout(int bclkPin, int wclkPin, int doutPin, int mclkPin);
virtual ~AudioOutputI2S() override;
virtual bool SetRate(int hz) override;
virtual bool SetRate(int hz) override;
virtual bool SetBitsPerSample(int bits) override;
virtual bool SetChannels(int channels) override;
virtual bool begin() override { return begin(true); }
virtual bool ConsumeSample(int16_t sample[2]) override;
virtual void flush() override;
virtual bool stop() override;

bool begin(bool txDAC);

virtual ~AudioOutputI2S() override;
bool begin(bool txDAC);
bool SetOutputModeMono(bool mono); // Force mono output no matter the input
bool SetLsbJustified(bool lsbJustified); // Allow supporting non-I2S chips, e.g. PT8211
bool SetLsbJustified(bool lsbJustified); // Allow supporting non-I2S chips, e.g. PT8211
bool SetMclk(bool enabled); // Enable MCLK output (if supported)

protected:
Expand All @@ -63,11 +63,13 @@ class AudioOutputI2S : public AudioOutput
bool i2sOn;
int dma_buf_count;
int use_apll;
bool use_mclk;
int use_mclk = 0;
bool tx_desc_auto_clear = false;

// We can restore the old values and free up these pins when in NoDAC mode
uint32_t orig_bck;
uint32_t orig_ws;

uint8_t bclkPin;
uint8_t wclkPin;
uint8_t doutPin;
Expand Down