diff --git a/libraries/I2S/src/I2S.cpp b/libraries/I2S/src/I2S.cpp index a62bc5114..5c165ce73 100644 --- a/libraries/I2S/src/I2S.cpp +++ b/libraries/I2S/src/I2S.cpp @@ -28,12 +28,14 @@ static I2SDevice_SAMD21G18x i2sd(*I2S); int I2SClass::_beginCount = 0; -I2SClass::I2SClass(uint8_t deviceIndex, uint8_t clockGenerator, uint8_t sdPin, uint8_t sckPin, uint8_t fsPin) : +I2SClass::I2SClass(uint8_t deviceIndex, uint8_t clockGenerator, uint8_t sdPin, uint8_t sckPin, uint8_t fsPin, uint8_t mckPin) : _deviceIndex(deviceIndex), _clockGenerator(clockGenerator), _sdPin(sdPin), _sckPin(sckPin), _fsPin(fsPin), + _mckPin(mckPin), + _mckFsMultiplier(0), _state(I2S_STATE_IDLE), _dmaChannel(-1), @@ -108,7 +110,16 @@ int I2SClass::begin(int mode, long sampleRate, int bitsPerSample, bool driveCloc if (driveClock) { // set up clock - enableClock(sampleRate * 2 * bitsPerSample); + int F_BCKL = sampleRate * 2 * bitsPerSample; // LRCLOCK + int F_MCKL = _mckFsMultiplier * sampleRate; // SYSCLK + + enableClock(_mckFsMultiplier ? F_MCKL : F_BCKL); + + if (_mckFsMultiplier) { + i2sd.enableMasterClock(_deviceIndex); + i2sd.setMasterClockDiv(_deviceIndex, F_MCKL / F_BCKL - 1); + pinPeripheral(_mckPin, PIO_COM); + } i2sd.setSerialClockSelectMasterClockDiv(_deviceIndex); i2sd.setFrameSyncSelectSerialClockDiv(_deviceIndex); @@ -168,6 +179,11 @@ void I2SClass::end() pinMode(_fsPin, INPUT); pinMode(_sckPin, INPUT); + if (_mckFsMultiplier) { + pinMode(_mckPin, INPUT); + _mckFsMultiplier = 0; + } + disableClock(); _beginCount--; @@ -401,9 +417,25 @@ void I2SClass::setBufferSize(int bufferSize) _doubleBuffer.setSize(bufferSize); } +void I2SClass::enableMasterClock(int mckFsMultiplier) +{ + switch (mckFsMultiplier) { + case 128: + case 192: + case 256: + case 384: + case 512: + _mckFsMultiplier = mckFsMultiplier; + return; + + default: + _mckFsMultiplier = 256; + } +} + void I2SClass::enableClock(int divider) { - int div = SystemCoreClock / divider; + int div = (float)SystemCoreClock / divider + 0.5f; int src = GCLK_GENCTRL_SRC_DFLL48M_Val; if (div > 255) { @@ -529,5 +561,5 @@ void I2SClass::onDmaTransferComplete(int channel) } #if I2S_INTERFACES_COUNT > 0 -I2SClass I2S(I2S_DEVICE, I2S_CLOCK_GENERATOR, PIN_I2S_SD, PIN_I2S_SCK, PIN_I2S_FS); +I2SClass I2S(I2S_DEVICE, I2S_CLOCK_GENERATOR, PIN_I2S_SD, PIN_I2S_SCK, PIN_I2S_FS, PIN_I2S_MCK); #endif diff --git a/libraries/I2S/src/I2S.h b/libraries/I2S/src/I2S.h index 7f78b7191..9e0f28103 100644 --- a/libraries/I2S/src/I2S.h +++ b/libraries/I2S/src/I2S.h @@ -24,6 +24,7 @@ #include "utility/I2SDoubleBuffer.h" #define I2S_HAS_SET_BUFFER_SIZE 1 +#define PIN_I2S_MCK PIN_WIRE_SCL //I2S_MCK[0] typedef enum { I2S_PHILIPS_MODE, @@ -35,11 +36,11 @@ class I2SClass : public Stream { public: // the device index and pins must map to the "COM" pads in Table 6-1 of the datasheet - I2SClass(uint8_t deviceIndex, uint8_t clockGenerator, uint8_t sdPin, uint8_t sckPin, uint8_t fsPin); + I2SClass(uint8_t deviceIndex, uint8_t clockGenerator, uint8_t sdPin, uint8_t sckPin, uint8_t fsPin, uint8_t mckPin); // the SCK and FS pins are driven as outputs using the sample rate int begin(int mode, long sampleRate, int bitsPerSample); - // the SCK and FS pins are inputs, other side controls sample rate + // the SCK and FS pins are inputs, other side controls the sample rate int begin(int mode, int bitsPerSample); void end(); @@ -65,6 +66,7 @@ class I2SClass : public Stream void onReceive(void(*)(void)); void setBufferSize(int bufferSize); + void enableMasterClock(int _mckFsMultiplier = 256); private: int begin(int mode, long sampleRate, int bitsPerSample, bool driveClock); @@ -94,6 +96,9 @@ class I2SClass : public Stream uint8_t _sckPin; uint8_t _fsPin; + uint8_t _mckPin; + int _mckFsMultiplier; + i2s_state_t _state; int _dmaChannel; int _bitsPerSample; diff --git a/libraries/I2S/src/utility/SAMD21_I2SDevice.h b/libraries/I2S/src/utility/SAMD21_I2SDevice.h index 261583921..25bac43e8 100644 --- a/libraries/I2S/src/utility/SAMD21_I2SDevice.h +++ b/libraries/I2S/src/utility/SAMD21_I2SDevice.h @@ -47,6 +47,14 @@ class I2SDevice_SAMD21G18x { return (index == 0) ? I2S_GCLK_ID_0 : I2S_GCLK_ID_1; } + inline void setMasterClockDiv(int index, int div) { + i2s.CLKCTRL[index].bit.MCKDIV = div; + } + + inline void enableMasterClock(int index) { + i2s.CLKCTRL[index].bit.MCKEN = 1; + } + inline void setSerialClockSelectMasterClockDiv(int index) { i2s.CLKCTRL[index].bit.SCKSEL = I2S_CLKCTRL_SCKSEL_MCKDIV_Val; }