From 3c6f9b55f7700ce480e8feb77b78486f01abbc67 Mon Sep 17 00:00:00 2001
From: Jonathan BAUDIN <jonathan.baudin@atmel.com>
Date: Fri, 9 May 2014 14:07:29 +0200
Subject: [PATCH]  Initialize clock

---
 cores/arduino/SERCOM.cpp          | 122 ++++++++++++++++++++++--------
 cores/arduino/SERCOM.h            |   5 +-
 variants/arduino_zero/variant.cpp |  42 +++++-----
 3 files changed, 113 insertions(+), 56 deletions(-)

diff --git a/cores/arduino/SERCOM.cpp b/cores/arduino/SERCOM.cpp
index 99b3ed57..4fdd9f44 100644
--- a/cores/arduino/SERCOM.cpp
+++ b/cores/arduino/SERCOM.cpp
@@ -1,18 +1,27 @@
 #include "SERCOM.h"
 
 
-SERCOM::SERCOM(Sercom* sercom)
+SERCOM::SERCOM(Sercom* s)
 {
-	this->sercom = sercom;
+	sercom = s;
 }
 
 /* 	=========================
  *	===== Sercom UART
  *	=========================
 */
+// Constants for Clock multiplexers
+#define GENERIC_CLOCK_SERCOM0	(0x14ul)
+#define GENERIC_CLOCK_SERCOM1	(0x15ul)
+#define GENERIC_CLOCK_SERCOM2	(0x16ul)
+#define GENERIC_CLOCK_SERCOM3	(0x17ul)
+#define GENERIC_CLOCK_SERCOM4	(0x18ul)
+#define GENERIC_CLOCK_SERCOM5	(0x19ul)
+
 void SERCOM::initUART(SercomUartMode mode, SercomUartSampleRate sampleRate, uint32_t baudrate)
 {
 	resetUART();
+	initClock();
 	
 	//Setting the CTRLA register
 	sercom->USART.CTRLA.reg =	SERCOM_USART_CTRLA_MODE(mode) |
@@ -35,7 +44,13 @@ void SERCOM::initUART(SercomUartMode mode, SercomUartSampleRate sampleRate, uint
 			sampleRateValue = 3;
 		
 		//Asynchronous arithmetic mode
-		sercom->USART.BAUD.reg = 65535 * ( 1 - sampleRateValue * division(baudrate,SERCOM_FREQ_REF));
+		//sercom->USART.BAUD.reg = 65535 * ( 1 - sampleRateValue * division(baudrate,SERCOM_FREQ_REF));
+		int tmpBaud = (baudrate / SERCOM_FREQ_REF);
+		tmpBaud = ( 1 - sampleRateValue * tmpBaud);
+		tmpBaud = (65535ul) * tmpBaud;
+		
+		tmpBaud = 40369;
+		sercom->USART.BAUD.reg = tmpBaud;
 	}
 }
 void SERCOM::initFrame(SercomUartCharSize charSize, SercomDataOrder dataOrder, SercomParityMode parityMode, SercomNumberStopBit nbStopBits)
@@ -132,7 +147,7 @@ int SERCOM::writeDataUART(uint8_t data)
 	flushUART();
 
 	//Put data into DATA register
-	sercom->USART.DATA.bit.DATA = data;
+	sercom->USART.DATA.reg = (uint16_t)data;
 	return 1;
 }
 
@@ -155,7 +170,7 @@ void SERCOM::initSPI(SercomSpiTXPad mosi, SercomRXPad miso, SercomSpiCharSize ch
 							(0x1ul) << SERCOM_SPI_CTRLB_RXEN_Pos;	//Active the SPI receiver.
 }
 
-void SERCOM::initClock(SercomSpiClockMode clockMode, uint32_t baudrate)
+void SERCOM::initSPIClock(SercomSpiClockMode clockMode, uint32_t baudrate)
 {
 	//Extract data from clockMode
 	int cpha, cpol;
@@ -291,36 +306,77 @@ uint8_t SERCOM::calculateBaudrateSynchronous(uint32_t baudrate)
 
 uint32_t SERCOM::division(uint32_t dividend, uint32_t divisor)
 {
-	// division WITHOUT division operator
+	//// division WITHOUT division operator
+	//
+    //uint32_t denom = divisor;
+    //uint32_t current = 1;
+    //uint32_t answer = 0;
+//
+    //if ( denom > dividend) 
+        //return 0;
+//
+    //if ( denom == dividend)
+        //return 1;
+//
+    //while (denom <= dividend) {
+        //denom <<= 1;
+        //current <<= 1;
+    //}
+//
+    //denom >>= 1;
+    //current >>= 1;
+//
+    //while (current!=0) {
+        //if ( dividend >= denom) {
+            //dividend -= denom;
+            //answer |= current;
+        //}
+        //current >>= 1;
+        //denom >>= 1;
+    //}
+	//
+    //return answer;
+}
+
+void SERCOM::initClock()
+{
+	uint8_t clockId;
+	
+	if(sercom == SERCOM0)
+	{
+		clockId = GENERIC_CLOCK_SERCOM0;
+	}
+	else if(sercom == SERCOM1)
+	{
+		clockId = GENERIC_CLOCK_SERCOM1;
+	}
+	else if(sercom == SERCOM2)
+	{
+		clockId = GENERIC_CLOCK_SERCOM2;
+	}
+	else if(sercom == SERCOM3)
+	{
+		clockId = GENERIC_CLOCK_SERCOM3;
+	}
+	else if(sercom == SERCOM4)
+	{
+		clockId = GENERIC_CLOCK_SERCOM4;
+	}
+	else if(sercom == SERCOM5)
+	{
+		clockId = GENERIC_CLOCK_SERCOM5;
+	}
 	
-    uint32_t denom = divisor;
-    uint32_t current = 1;
-    uint32_t answer = 0;
-
-    if ( denom > dividend) 
-        return 0;
-
-    if ( denom == dividend)
-        return 1;
+	//Setting clock
+	GCLK->CLKCTRL.reg = GCLK_CLKCTRL_ID( clockId ) | // Generic Clock 0 (SERCOM0)
+	                    GCLK_CLKCTRL_GEN_GCLK0 | // Generic Clock Generator 0 is source
+	                    GCLK_CLKCTRL_CLKEN ;
+						
 
-    while (denom <= dividend) {
-        denom <<= 1;
-        current <<= 1;
-    }
-
-    denom >>= 1;
-    current >>= 1;
-
-    while (current!=0) {
-        if ( dividend >= denom) {
-            dividend -= denom;
-            answer |= current;
-        }
-        current >>= 1;
-        denom >>= 1;
-    }
-	
-    return answer;
+	while ( GCLK->STATUS.reg & GCLK_STATUS_SYNCBUSY )
+	{
+		/* Wait for synchronization */
+	}
 }
 
 
diff --git a/cores/arduino/SERCOM.h b/cores/arduino/SERCOM.h
index 3bbeca22..86b2a2ca 100644
--- a/cores/arduino/SERCOM.h
+++ b/cores/arduino/SERCOM.h
@@ -127,7 +127,7 @@ typedef enum
 class SERCOM
 {
 	public:
-		SERCOM(Sercom* sercom);
+		SERCOM(Sercom* s);
 		
 		/* ========== SERCOM OBJECT ========== */
 		static SERCOM * sercom0;
@@ -156,7 +156,7 @@ class SERCOM
         
 		/* ========== SPI ========== */
 		void initSPI(SercomSpiTXPad mosi, SercomRXPad miso, SercomSpiCharSize charSize, SercomDataOrder dataOrder);
-		void initClock(SercomSpiClockMode clockMode, uint32_t baudrate);
+		void initSPIClock(SercomSpiClockMode clockMode, uint32_t baudrate);
 		
 		void resetSPI();
 		void enableSPI();
@@ -198,6 +198,7 @@ class SERCOM
 		Sercom* sercom;
 		uint8_t calculateBaudrateSynchronous(uint32_t baudrate);
 		uint32_t division(uint32_t dividend, uint32_t divisor);
+		void initClock();
 };
 
 #endif
diff --git a/variants/arduino_zero/variant.cpp b/variants/arduino_zero/variant.cpp
index de13f0b5..2a6c7522 100644
--- a/variants/arduino_zero/variant.cpp
+++ b/variants/arduino_zero/variant.cpp
@@ -87,11 +87,11 @@
  */
 const PinDescription g_APinDescription[]=
 {
-	// 0 .. 19 - Digital pins
-	// ----------------------
-	// 0/1 - SERCOM/UART (Serial)
-	{ PORTA, 10, PIO_SERCOM, PIN_ATTR_DIGITAL, No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER }, // RX: SERCOM0/PAD[2]
-	{ PORTA, 11, PIO_SERCOM, PIN_ATTR_DIGITAL, No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER }, // TX: SERCOM0/PAD[3]
+  // 0 .. 19 - Digital pins
+  // ----------------------
+  // 0/1 - SERCOM/UART (Serial)
+  { PORTA, 10, PIO_SERCOM, PIN_ATTR_DIGITAL, No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER }, // RX: SERCOM0/PAD[2]
+  { PORTA, 11, PIO_SERCOM, PIN_ATTR_DIGITAL, No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER }, // TX: SERCOM0/PAD[3]
 
 	// 2..12
 	{ PORTA,  8, PIO_TIMER, (PIN_ATTR_DIGITAL|PIN_ATTR_PWM|PIN_ATTR_TIMER), No_ADC_Channel, PWM0_CH0, TCC0_CH0 }, // TCC0/WO[0]
@@ -116,28 +116,28 @@ const PinDescription g_APinDescription[]=
 	{ PORTA, 3, PIO_ANALOG, PIN_ATTR_ANALOG, No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER }, // DAC/VREFP
 
 	// 16..17 I2C (SDA/SCL)
-	{ PORTA, 22, PIO_SERCOM, PIN_ATTR_DIGITAL, No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER }, // SDA: SERCOM3/PAD[0]
-	{ PORTA, 23, PIO_SERCOM, PIN_ATTR_DIGITAL, No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER }, // SCL: SERCOM3/PAD[1]
+  { PORTA, 22, PIO_SERCOM, PIN_ATTR_DIGITAL, No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER }, // SDA: SERCOM3/PAD[0]
+  { PORTA, 23, PIO_SERCOM, PIN_ATTR_DIGITAL, No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER }, // SCL: SERCOM3/PAD[1]
 
 	// 18..23 SPI (ICSP:MISO,SCK,MOSI)
-	{ PORTA, 12, PIO_SERCOM, PIN_ATTR_DIGITAL, No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER }, // MISO: SERCOM4/PAD[0]
-	{ NOT_A_PORT, 0, PIO_NOT_A_PIN, PIN_ATTR_NONE, No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER }, // 5V0
-	{ PORTB, 11, PIO_SERCOM, PIN_ATTR_DIGITAL, No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER }, // SCK: SERCOM4/PAD[3]
-	{ PORTB, 10, PIO_SERCOM, PIN_ATTR_DIGITAL, No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER }, // MOSI: SERCOM4/PAD[2]
-	{ NOT_A_PORT, 0, PIO_NOT_A_PIN, PIN_ATTR_NONE, No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER }, // RESET
-	{ NOT_A_PORT, 0, PIO_NOT_A_PIN, PIN_ATTR_NONE, No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER }, // GND
-
-	// 24..29 - Analog pins
+  { PORTA, 12, PIO_SERCOM, PIN_ATTR_DIGITAL, No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER }, // MISO: SERCOM4/PAD[0]
+  { NOT_A_PORT, 0, PIO_NOT_A_PIN, PIN_ATTR_NONE, No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER }, // 5V0
+  { PORTB, 11, PIO_SERCOM, PIN_ATTR_DIGITAL, No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER }, // SCK: SERCOM4/PAD[3]
+  { PORTB, 10, PIO_SERCOM, PIN_ATTR_DIGITAL, No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER }, // MOSI: SERCOM4/PAD[2]
+  { NOT_A_PORT, 0, PIO_NOT_A_PIN, PIN_ATTR_NONE, No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER }, // RESET
+  { NOT_A_PORT, 0, PIO_NOT_A_PIN, PIN_ATTR_NONE, No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER }, // GND
+
+  // 24..29 - Analog pins
 	// --------------------
 	// 24 - A0 (DAC output)
 	{ PORTA,  2, PIO_ANALOG, PIN_ATTR_ANALOG, DAC_Channel0, NOT_ON_PWM, NOT_ON_TIMER }, // DAC/VOUT
 
 	// 25..29 - A1-A5
-	{ PORTB,  8, PIO_ANALOG, PIN_ATTR_ANALOG, ADC_Channel2, NOT_ON_PWM, NOT_ON_TIMER }, // ADC/AIN[2]
-	{ PORTB,  9, PIO_ANALOG, PIN_ATTR_ANALOG, ADC_Channel3, NOT_ON_PWM, NOT_ON_TIMER }, // ADC/AIN[3]
-	{ PORTA,  4, PIO_ANALOG, PIN_ATTR_ANALOG, ADC_Channel4, NOT_ON_PWM, NOT_ON_TIMER }, // ADC/AIN[4]
-	{ PORTA,  5, PIO_ANALOG, PIN_ATTR_ANALOG, ADC_Channel5, NOT_ON_PWM, NOT_ON_TIMER }, // ADC/AIN[5]
-	{ PORTA,  2, PIO_ANALOG, PIN_ATTR_ANALOG, ADC_Channel10, NOT_ON_PWM, NOT_ON_TIMER }, // ADC/AIN[10]
+  { PORTB,  8, PIO_ANALOG, PIN_ATTR_ANALOG, ADC_Channel2, NOT_ON_PWM, NOT_ON_TIMER }, // ADC/AIN[2]
+  { PORTB,  9, PIO_ANALOG, PIN_ATTR_ANALOG, ADC_Channel3, NOT_ON_PWM, NOT_ON_TIMER }, // ADC/AIN[3]
+  { PORTA,  4, PIO_ANALOG, PIN_ATTR_ANALOG, ADC_Channel4, NOT_ON_PWM, NOT_ON_TIMER }, // ADC/AIN[4]
+  { PORTA,  5, PIO_ANALOG, PIN_ATTR_ANALOG, ADC_Channel5, NOT_ON_PWM, NOT_ON_TIMER }, // ADC/AIN[5]
+  { PORTA,  2, PIO_ANALOG, PIN_ATTR_ANALOG, ADC_Channel10, NOT_ON_PWM, NOT_ON_TIMER }, // ADC/AIN[10]
 
 	// 30..31 - RX/TX LEDS (PB03/PA27)
 	{ PORTB,  3, PIO_OUTPUT, PIN_ATTR_DIGITAL, No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER }, // use as pure output
@@ -148,4 +148,4 @@ const PinDescription g_APinDescription[]=
 	{ PORTA, 24, PIO_COM, PIN_ATTR_NONE, No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER }, // USB/DM
 	{ PORTA, 25, PIO_COM, PIN_ATTR_NONE, No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER }, // USB/DP
 
-} ;
+} ;
\ No newline at end of file
-- 
GitLab