From a69eacb31ab45155515468d0c4e49edd19100fed Mon Sep 17 00:00:00 2001
From: KillzoneKid <killzone_kid@hotmail.co.uk>
Date: Wed, 28 Jul 2021 13:05:34 +0100
Subject: [PATCH 1/2] new method enableMasterClock(fsMultiplier)

Simplified MCK out with optional MCK frequency param, default 256fs
---
 libraries/I2S/src/I2S.cpp                    | 40 ++++++++++++++++++--
 libraries/I2S/src/I2S.h                      |  9 ++++-
 libraries/I2S/src/utility/SAMD21_I2SDevice.h |  8 ++++
 3 files changed, 51 insertions(+), 6 deletions(-)

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..66582d4f7 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 driven as outputs using 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;
   }

From 3b7c0911de822eb43ff76ad25b75324381f3cfcd Mon Sep 17 00:00:00 2001
From: KillzoneKid <killzone_kid@hotmail.co.uk>
Date: Wed, 28 Jul 2021 15:37:36 +0100
Subject: [PATCH 2/2] Unintentional change of comment, fixed

Unintentional change of comment, fixed
---
 libraries/I2S/src/I2S.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/libraries/I2S/src/I2S.h b/libraries/I2S/src/I2S.h
index 66582d4f7..9e0f28103 100644
--- a/libraries/I2S/src/I2S.h
+++ b/libraries/I2S/src/I2S.h
@@ -40,7 +40,7 @@ class I2SClass : public Stream
 
   // 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 driven as outputs using the sample rate
+  // the SCK and FS pins are inputs, other side controls the sample rate
   int begin(int mode, int bitsPerSample);
   void end();