From 4efe39eb4908109bdbd96e9c4f23894e7e5b4523 Mon Sep 17 00:00:00 2001
From: Sandeep Mistry <s.mistry@arduino.cc>
Date: Tue, 8 Sep 2015 17:47:30 -0400
Subject: [PATCH] Changes to get Wire slave receiver working

---
 cores/arduino/SERCOM.cpp | 36 ++++++++++++++++++-----------
 cores/arduino/SERCOM.h   |  2 +-
 libraries/Wire/Wire.cpp  | 50 +++++++++++++++++++++++++---------------
 3 files changed, 56 insertions(+), 32 deletions(-)

diff --git a/cores/arduino/SERCOM.cpp b/cores/arduino/SERCOM.cpp
index 2cfb172a..08297882 100644
--- a/cores/arduino/SERCOM.cpp
+++ b/cores/arduino/SERCOM.cpp
@@ -410,14 +410,12 @@ void SERCOM::initSlaveWIRE( uint8_t ucAddress )
   // Set slave mode
   sercom->I2CS.CTRLA.bit.MODE = I2C_SLAVE_OPERATION ;
 
-  // Enable Quick Command
-  sercom->I2CM.CTRLB.bit.QCEN = 1 ;
-
   sercom->I2CS.ADDR.reg = SERCOM_I2CS_ADDR_ADDR( ucAddress & 0x7Ful ) | // 0x7F, select only 7 bits
                           SERCOM_I2CS_ADDR_ADDRMASK( 0x3FFul ) ;    // 0x3FF all bits set
 
   // Set the interrupt register
-  sercom->I2CS.INTENSET.reg = SERCOM_I2CS_INTENSET_AMATCH | // Address Match
+  sercom->I2CS.INTENSET.reg = SERCOM_I2CS_INTENSET_PREC |   // Stop
+                              SERCOM_I2CS_INTENSET_AMATCH | // Address Match
                               SERCOM_I2CS_INTENSET_DRDY ;   // Data Ready
 
   while ( sercom->I2CM.SYNCBUSY.bit.SYSOP != 0 )
@@ -450,23 +448,35 @@ void SERCOM::initMasterWIRE( uint32_t baudrate )
 
 void SERCOM::prepareNackBitWIRE( void )
 {
-  // Send a NACK
-  sercom->I2CM.CTRLB.bit.ACKACT = 1;
+  if(isMasterWIRE()) {
+    // Send a NACK
+    sercom->I2CM.CTRLB.bit.ACKACT = 1;
+  } else {
+    sercom->I2CS.CTRLB.bit.ACKACT = 1;
+  }
 }
 
 void SERCOM::prepareAckBitWIRE( void )
 {
-  // Send an ACK
-  sercom->I2CM.CTRLB.bit.ACKACT = 0;
+  if(isMasterWIRE()) {
+    // Send an ACK
+    sercom->I2CM.CTRLB.bit.ACKACT = 0;
+  } else {
+    sercom->I2CS.CTRLB.bit.ACKACT = 0;
+  }
 }
 
-void SERCOM::prepareCommandBitsWire(SercomMasterCommandWire cmd)
+void SERCOM::prepareCommandBitsWire(uint8_t cmd)
 {
-  sercom->I2CM.CTRLB.bit.CMD = cmd;
+  if(isMasterWIRE()) {
+    sercom->I2CM.CTRLB.bit.CMD = cmd;
 
-  while(sercom->I2CM.SYNCBUSY.bit.SYSOP)
-  {
-    // Waiting for synchronization
+    while(sercom->I2CM.SYNCBUSY.bit.SYSOP)
+    {
+      // Waiting for synchronization
+    }
+  } else {
+    sercom->I2CS.CTRLB.bit.CMD = cmd;
   }
 }
 
diff --git a/cores/arduino/SERCOM.h b/cores/arduino/SERCOM.h
index fbd27e62..974cebd7 100644
--- a/cores/arduino/SERCOM.h
+++ b/cores/arduino/SERCOM.h
@@ -191,7 +191,7 @@ class SERCOM
     void disableWIRE( void );
     void prepareNackBitWIRE( void ) ;
     void prepareAckBitWIRE( void ) ;
-    void prepareCommandBitsWire(SercomMasterCommandWire cmd);
+    void prepareCommandBitsWire(uint8_t cmd);
 		bool startTransmissionWIRE(uint8_t address, SercomWireReadWriteFlag flag) ;
 		bool sendDataMasterWIRE(uint8_t data) ;
 		bool sendDataSlaveWIRE(uint8_t data) ;
diff --git a/libraries/Wire/Wire.cpp b/libraries/Wire/Wire.cpp
index 31e0a1d8..273b03e7 100644
--- a/libraries/Wire/Wire.cpp
+++ b/libraries/Wire/Wire.cpp
@@ -47,6 +47,9 @@ void TwoWire::begin(uint8_t address) {
   //Slave mode
   sercom->initSlaveWIRE(address);
   sercom->enableWIRE();
+
+  pinPeripheral(_uc_pinSDA, g_APinDescription[_uc_pinSDA].ulPinType);
+  pinPeripheral(_uc_pinSCL, g_APinDescription[_uc_pinSCL].ulPinType);
 }
 
 void TwoWire::end() {
@@ -216,26 +219,11 @@ void TwoWire::onService(void)
 {
   if ( sercom->isSlaveWIRE() )
   {
-    //Received data
-    if(sercom->isDataReadyWIRE())
+    if(sercom->isAddressMatch())  //Address Match
     {
-      //Store data
-      rxBuffer.store_char(sercom->readDataWIRE());
-
-      //Stop or Restart detected
-      if(sercom->isStopDetectedWIRE() || sercom->isRestartDetectedWIRE())
-      {
-        //Calling onReceiveCallback, if exists
-        if(onReceiveCallback)
-        {
-          onReceiveCallback(available());
-        }
-      }
-    }
+      sercom->prepareAckBitWIRE();
+      sercom->prepareCommandBitsWire(0x03);
 
-    //Address Match
-    if(sercom->isAddressMatch())
-    {
       //Is a request ?
       if(sercom->isMasterReadOperationWIRE())
       {
@@ -246,6 +234,32 @@ void TwoWire::onService(void)
         }
       }
     }
+    else if(sercom->isDataReadyWIRE()) //Received data
+    {
+      if (rxBuffer.isFull()) {
+        sercom->prepareNackBitWIRE(); 
+      } else {
+        //Store data
+        rxBuffer.store_char(sercom->readDataWIRE());
+
+        sercom->prepareAckBitWIRE(); 
+      }
+
+      sercom->prepareCommandBitsWire(0x03);
+    }
+    else if(sercom->isStopDetectedWIRE() || sercom->isRestartDetectedWIRE()) //Stop or Restart detected
+    {
+      sercom->prepareAckBitWIRE();
+      sercom->prepareCommandBitsWire(0x03);
+
+      //Calling onReceiveCallback, if exists
+      if(onReceiveCallback)
+      {
+        onReceiveCallback(available());
+      }
+      
+      rxBuffer.clear();
+    }
   }
 }
 
-- 
GitLab