diff --git a/cores/arduino/Arduino.h b/cores/arduino/Arduino.h index 05eac732f..1be6d7171 100644 --- a/cores/arduino/Arduino.h +++ b/cores/arduino/Arduino.h @@ -62,7 +62,7 @@ void loop( void ) ; #ifdef __cplusplus } // extern "C" -#endif // __cplusplus +#endif // The following headers are for C++ only compilation #ifdef __cplusplus @@ -72,9 +72,11 @@ void loop( void ) ; #include "WMath.h" #include "HardwareSerial.h" #include "pulse.h" - #include "delay.h" +#endif +#include "delay.h" +#ifdef __cplusplus #include "Uart.h" -#endif // __cplusplus +#endif // Include board variant #include "variant.h" diff --git a/cores/arduino/IPAddress.cpp b/cores/arduino/IPAddress.cpp index 6803110ea..899cbd4ed 100644 --- a/cores/arduino/IPAddress.cpp +++ b/cores/arduino/IPAddress.cpp @@ -1,5 +1,6 @@ /* - Copyright (c) 2014 Arduino. All right reserved. + IPAddress.cpp - Base class that provides IPAddress + Copyright (c) 2011 Adrian McEwen. All right reserved. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public @@ -8,8 +9,8 @@ This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - See the GNU Lesser General Public License for more details. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software @@ -21,42 +22,42 @@ IPAddress::IPAddress() { - memset(_address, 0, sizeof(_address)); + _address.dword = 0; } IPAddress::IPAddress(uint8_t first_octet, uint8_t second_octet, uint8_t third_octet, uint8_t fourth_octet) { - _address[0] = first_octet; - _address[1] = second_octet; - _address[2] = third_octet; - _address[3] = fourth_octet; + _address.bytes[0] = first_octet; + _address.bytes[1] = second_octet; + _address.bytes[2] = third_octet; + _address.bytes[3] = fourth_octet; } IPAddress::IPAddress(uint32_t address) { - memcpy(_address, &address, sizeof(_address)); + _address.dword = address; } IPAddress::IPAddress(const uint8_t *address) { - memcpy(_address, address, sizeof(_address)); + memcpy(_address.bytes, address, sizeof(_address.bytes)); } IPAddress& IPAddress::operator=(const uint8_t *address) { - memcpy(_address, address, sizeof(_address)); + memcpy(_address.bytes, address, sizeof(_address.bytes)); return *this; } IPAddress& IPAddress::operator=(uint32_t address) { - memcpy(_address, (const uint8_t *)&address, sizeof(_address)); + _address.dword = address; return *this; } bool IPAddress::operator==(const uint8_t* addr) const { - return memcmp(addr, _address, sizeof(_address)) == 0; + return memcmp(addr, _address.bytes, sizeof(_address.bytes)) == 0; } size_t IPAddress::printTo(Print& p) const @@ -64,10 +65,10 @@ size_t IPAddress::printTo(Print& p) const size_t n = 0; for (int i =0; i < 3; i++) { - n += p.print(_address[i], DEC); + n += p.print(_address.bytes[i], DEC); n += p.print('.'); } - n += p.print(_address[3], DEC); + n += p.print(_address.bytes[3], DEC); return n; } diff --git a/cores/arduino/IPAddress.h b/cores/arduino/IPAddress.h index b6f454bba..94acdc456 100644 --- a/cores/arduino/IPAddress.h +++ b/cores/arduino/IPAddress.h @@ -1,5 +1,6 @@ /* - Copyright (c) 2014 Arduino. All right reserved. + IPAddress.h - Base class that provides IPAddress + Copyright (c) 2011 Adrian McEwen. All right reserved. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public @@ -8,8 +9,8 @@ This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - See the GNU Lesser General Public License for more details. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software @@ -19,18 +20,23 @@ #ifndef IPAddress_h #define IPAddress_h +#include #include // A class to make it easier to handle and pass around IP addresses class IPAddress : public Printable { private: - uint8_t _address[4]; // IPv4 address + union { + uint8_t bytes[4]; // IPv4 address + uint32_t dword; + } _address; + // Access the raw byte array containing the address. Because this returns a pointer // to the internal structure rather than a copy of the address this function should only // be used when you know that the usage of the returned uint8_t* will be transient and not // stored. - uint8_t* raw_address() { return _address; }; + uint8_t* raw_address() { return _address.bytes; }; public: // Constructors @@ -41,13 +47,13 @@ class IPAddress : public Printable { // Overloaded cast operator to allow IPAddress objects to be used where a pointer // to a four-byte uint8_t array is expected - operator uint32_t() const { return *((uint32_t*)_address+0); }; - bool operator==(const IPAddress& addr) const { return (*((uint32_t*)_address)) == (*((uint32_t*)addr._address)); }; + operator uint32_t() const { return _address.dword; }; + bool operator==(const IPAddress& addr) const { return _address.dword == addr._address.dword; }; bool operator==(const uint8_t* addr) const; // Overloaded index operator to allow getting and setting individual octets of the address - uint8_t operator[](int index) const { return _address[index]; }; - uint8_t& operator[](int index) { return _address[index]; }; + uint8_t operator[](int index) const { return _address.bytes[index]; }; + uint8_t& operator[](int index) { return _address.bytes[index]; }; // Overloaded copy operators to allow initialisation of IPAddress objects from other types IPAddress& operator=(const uint8_t *address); diff --git a/cores/arduino/SERCOM.cpp b/cores/arduino/SERCOM.cpp index 7d7e7f9db..2cfb172aa 100644 --- a/cores/arduino/SERCOM.cpp +++ b/cores/arduino/SERCOM.cpp @@ -493,6 +493,12 @@ bool SERCOM::startTransmissionWIRE(uint8_t address, SercomWireReadWriteFlag flag { while( !sercom->I2CM.INTFLAG.bit.SB ) { + // If the slave NACKS the address, the MB bit will be set. + // In that case, send a stop condition and return false. + if (sercom->I2CM.INTFLAG.bit.MB) { + sercom->I2CM.CTRLB.bit.CMD = 3; // Stop condition + return false; + } // Wait transmission complete } @@ -518,7 +524,14 @@ bool SERCOM::sendDataMasterWIRE(uint8_t data) sercom->I2CM.DATA.bit.DATA = data; //Wait transmission successful - while(!sercom->I2CM.INTFLAG.bit.MB); + while(!sercom->I2CM.INTFLAG.bit.MB) { + + // If a bus error occurs, the MB bit may never be set. + // Check the bus error bit and bail if it's set. + if (sercom->I2CM.STATUS.bit.BUSERR) { + return false; + } + } //Problems on line? nack received? if(sercom->I2CM.STATUS.bit.RXNACK) diff --git a/cores/arduino/WInterrupts.c b/cores/arduino/WInterrupts.c index a28b9df64..2936452d7 100644 --- a/cores/arduino/WInterrupts.c +++ b/cores/arduino/WInterrupts.c @@ -21,212 +21,122 @@ #include -#ifdef __cplusplus -extern "C" { -#endif - -static struct -{ - uint32_t _ulPin ; - voidFuncPtr _callback ; -} callbacksInt[EXTERNAL_NUM_INTERRUPTS] ; +static voidFuncPtr callbacksInt[EXTERNAL_NUM_INTERRUPTS]; /* Configure I/O interrupt sources */ static void __initialize() { - memset( callbacksInt, 0, sizeof( callbacksInt ) ) ; + memset(callbacksInt, 0, sizeof(callbacksInt)); - NVIC_DisableIRQ( EIC_IRQn ) ; - NVIC_ClearPendingIRQ( EIC_IRQn ) ; - NVIC_SetPriority( EIC_IRQn, 0 ) ; - NVIC_EnableIRQ( EIC_IRQn ) ; + NVIC_DisableIRQ(EIC_IRQn); + NVIC_ClearPendingIRQ(EIC_IRQn); + NVIC_SetPriority(EIC_IRQn, 0); + NVIC_EnableIRQ(EIC_IRQn); // Enable GCLK for IEC (External Interrupt Controller) - GCLK->CLKCTRL.reg = (uint16_t) (GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN_GCLK0 | GCLK_CLKCTRL_ID( GCM_EIC )) ; + GCLK->CLKCTRL.reg = (uint16_t) (GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN_GCLK0 | GCLK_CLKCTRL_ID(GCM_EIC)); /* Shall we do that? // Do a software reset on EIC EIC->CTRL.SWRST.bit = 1 ; - - while ( (EIC->CTRL.SWRST.bit == 1) && (EIC->STATUS.SYNCBUSY.bit == 1) ) - { - // Waiting for synchronisation - } + while ((EIC->CTRL.SWRST.bit == 1) && (EIC->STATUS.SYNCBUSY.bit == 1)) { } */ // Enable EIC - EIC->CTRL.bit.ENABLE = 1 ; - - while ( EIC->STATUS.bit.SYNCBUSY == 1 ) - { - // Waiting for synchronisation - } - + EIC->CTRL.bit.ENABLE = 1; + while (EIC->STATUS.bit.SYNCBUSY == 1) { } } /* * \brief Specifies a named Interrupt Service Routine (ISR) to call when an interrupt occurs. * Replaces any previous function that was attached to the interrupt. */ -//void attachInterrupt( uint32_t ulPin, void (*callback)(void), EExt_IntMode mode ) -//void attachInterrupt( uint32_t ulPin, voidFuncPtr callback, EExt_IntMode mode ) -void attachInterrupt( uint32_t ulPin, voidFuncPtr callback, uint32_t ulMode ) +void attachInterrupt(uint32_t pin, voidFuncPtr callback, uint32_t mode) { - static int enabled = 0 ; - uint32_t ulConfig ; - uint32_t ulPos ; + static int enabled = 0; + uint32_t config; + uint32_t pos; - if ( digitalPinToInterrupt( ulPin ) == NOT_AN_INTERRUPT ) - { - return ; - } + EExt_Interrupts in = digitalPinToInterrupt(pin); + if (in == NOT_AN_INTERRUPT || in == EXTERNAL_INT_NMI) + return; - if ( !enabled ) - { - __initialize() ; - enabled = 1 ; + if (!enabled) { + __initialize(); + enabled = 1; } // Assign pin to EIC - pinPeripheral( ulPin, PIO_EXTINT ) ; + pinPeripheral(pin, PIO_EXTINT); // Assign callback to interrupt - callbacksInt[digitalPinToInterrupt( ulPin )]._ulPin = ulPin ; - callbacksInt[digitalPinToInterrupt( ulPin )]._callback = callback ; - - // Check if normal interrupt or NMI - if ( ulPin != 2 ) - { - // Look for right CONFIG register to be addressed - if ( digitalPinToInterrupt( ulPin ) > EXTERNAL_INT_7 ) - { - ulConfig = 1 ; - } - else - { - ulConfig = 0 ; - } - - // Configure the interrupt mode - ulPos = ((digitalPinToInterrupt( ulPin ) - (8*ulConfig) ) << 2) ; - switch ( ulMode ) - { - case LOW: - EIC->CONFIG[ulConfig].reg |= EIC_CONFIG_SENSE0_LOW_Val << ulPos ; - break ; - - case HIGH: - // EIC->CONFIG[ulConfig].reg = EIC_CONFIG_SENSE0_HIGH_Val << ((digitalPinToInterrupt( ulPin ) >> ulConfig ) << ulPos) ; - EIC->CONFIG[ulConfig].reg |= EIC_CONFIG_SENSE0_HIGH_Val << ulPos ; - break ; - - case CHANGE: - // EIC->CONFIG[ulConfig].reg = EIC_CONFIG_SENSE0_BOTH_Val << ((digitalPinToInterrupt( ulPin ) >> ulConfig ) << ulPos) ; - EIC->CONFIG[ulConfig].reg |= EIC_CONFIG_SENSE0_BOTH_Val << ulPos ; - break ; - - case FALLING: - // EIC->CONFIG[ulConfig].reg = EIC_CONFIG_SENSE0_FALL_Val << ((digitalPinToInterrupt( ulPin ) >> ulConfig ) << ulPos) ; - EIC->CONFIG[ulConfig].reg |= EIC_CONFIG_SENSE0_FALL_Val << ulPos ; - break ; - - case RISING: - // EIC->CONFIG[ulConfig].reg = EIC_CONFIG_SENSE0_RISE_Val << ((digitalPinToInterrupt( ulPin ) >> ulConfig ) << ulPos) ; - EIC->CONFIG[ulConfig].reg |= EIC_CONFIG_SENSE0_RISE_Val << ulPos ; - break ; - } + callbacksInt[in] = callback; - // Enable the interrupt - EIC->INTENSET.reg = EIC_INTENSET_EXTINT( 1 << digitalPinToInterrupt( ulPin ) ) ; + // Look for right CONFIG register to be addressed + if (in > EXTERNAL_INT_7) { + config = 1; + } else { + config = 0; } - else // Handles NMI on pin 2 + + // Configure the interrupt mode + pos = (in - (8 * config)) << 2; + switch (mode) { - // Configure the interrupt mode - switch ( ulMode ) - { - case LOW: - EIC->NMICTRL.reg = EIC_NMICTRL_NMISENSE_LOW ; - break ; + case LOW: + EIC->CONFIG[config].reg |= EIC_CONFIG_SENSE0_LOW_Val << pos; + break; - case HIGH: - EIC->NMICTRL.reg = EIC_NMICTRL_NMISENSE_HIGH ; - break ; + case HIGH: + EIC->CONFIG[config].reg |= EIC_CONFIG_SENSE0_HIGH_Val << pos; + break; - case CHANGE: - EIC->NMICTRL.reg = EIC_NMICTRL_NMISENSE_BOTH ; - break ; + case CHANGE: + EIC->CONFIG[config].reg |= EIC_CONFIG_SENSE0_BOTH_Val << pos; + break; - case FALLING: - EIC->NMICTRL.reg = EIC_NMICTRL_NMISENSE_FALL ; - break ; + case FALLING: + EIC->CONFIG[config].reg |= EIC_CONFIG_SENSE0_FALL_Val << pos; + break; - case RISING: - EIC->NMICTRL.reg= EIC_NMICTRL_NMISENSE_RISE ; - break ; - } + case RISING: + EIC->CONFIG[config].reg |= EIC_CONFIG_SENSE0_RISE_Val << pos; + break; } + + // Enable the interrupt + EIC->INTENSET.reg = EIC_INTENSET_EXTINT(1 << in); } /* * \brief Turns off the given interrupt. */ -void detachInterrupt( uint32_t ulPin ) +void detachInterrupt(uint32_t pin) { -/* - // Retrieve pin information - Pio *pio = g_APinDescription[pin].pPort; - uint32_t mask = g_APinDescription[pin].ulPin; + EExt_Interrupts in = digitalPinToInterrupt(pin); + if (in == NOT_AN_INTERRUPT || in == EXTERNAL_INT_NMI) + return; - // Disable interrupt - pio->PIO_IDR = mask; -*/ - if ( digitalPinToInterrupt( ulPin ) == NOT_AN_INTERRUPT ) - { - return ; - } - - EIC->INTENCLR.reg = EIC_INTENCLR_EXTINT( 1 << digitalPinToInterrupt( ulPin ) ) ; + EIC->INTENCLR.reg = EIC_INTENCLR_EXTINT(1 << in); } /* * External Interrupt Controller NVIC Interrupt Handler */ -void EIC_Handler( void ) +void EIC_Handler(void) { - uint32_t ul ; - // Test the 16 normal interrupts - for ( ul = EXTERNAL_INT_0 ; ul <= EXTERNAL_INT_15 ; ul++ ) + for (uint32_t i=EXTERNAL_INT_0; i<=EXTERNAL_INT_15; i++) { - if ( (EIC->INTFLAG.reg & ( 1 << ul ) ) != 0 ) + if ((EIC->INTFLAG.reg & (1 << i)) != 0) { // Call the callback function if assigned - if ( callbacksInt[ul]._callback != NULL ) - { - callbacksInt[ul]._callback() ; + if (callbacksInt[i]) { + callbacksInt[i](); } // Clear the interrupt - EIC->INTFLAG.reg = 1 << ul ; + EIC->INTFLAG.reg = 1 << i; } } } - -/* - * External Non-Maskable Interrupt Controller NVIC Interrupt Handler - */ -void NMI_Handler( void ) -{ - // Call the callback function if assigned - if ( callbacksInt[EXTERNAL_INT_NMI]._callback != NULL ) - { - callbacksInt[EXTERNAL_INT_NMI]._callback() ; - } - - // Clear the interrupt - EIC->NMIFLAG.reg = EIC_NMIFLAG_NMI ; -} - -#ifdef __cplusplus -} -#endif diff --git a/cores/arduino/WInterrupts.h b/cores/arduino/WInterrupts.h index 8314dff24..5d2b24a0d 100644 --- a/cores/arduino/WInterrupts.h +++ b/cores/arduino/WInterrupts.h @@ -1,5 +1,5 @@ /* - Copyright (c) 2014 Arduino. All right reserved. + Copyright (c) 2015 Arduino LLC. All right reserved. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public @@ -31,49 +31,24 @@ extern "C" { #define FALLING 3 #define RISING 4 -///* - //* Interrupt modes - //* The two first values are conflicting with the ones used by Digital API, so we use another name for each. - //*/ -//typedef enum _EExt_IntMode -//{ - //IM_LOW = 0, - //IM_HIGH = 1, - //CHANGE = 2, - //FALLING = 3, - //RISING = 4, - //IM_CHANGE = 2, - //IM_FALLING = 3, - //IM_RISING = 4, -//} EExt_IntMode ; - #define DEFAULT 1 #define EXTERNAL 0 -typedef void (*voidFuncPtr)( void ) ; +typedef void (*voidFuncPtr)(void); /* * \brief Specifies a named Interrupt Service Routine (ISR) to call when an interrupt occurs. * Replaces any previous function that was attached to the interrupt. */ -//void attachInterrupt( uint32_t ulPin, void (*callback)(void), EExt_IntMode mode ) ; -//void attachInterrupt( uint32_t ulPin, voidFuncPtr callback, EExt_IntMode mode ) ; -void attachInterrupt( uint32_t ulPin, voidFuncPtr callback, uint32_t mode ) ; +void attachInterrupt(uint32_t pin, voidFuncPtr callback, uint32_t mode); /* * \brief Turns off the given interrupt. */ -void detachInterrupt( uint32_t ulPin ) ; +void detachInterrupt(uint32_t pin); #ifdef __cplusplus } #endif -//#ifdef __cplusplus -//inline operator ::EExt_IntMode( uint32_t ul ) -//{ - //return (EExt_IntMode)ul ; -//} -//#endif - -#endif /* _WIRING_INTERRUPTS_ */ +#endif diff --git a/cores/arduino/WVariant.h b/cores/arduino/WVariant.h index bce4575ab..ad5aeaff0 100644 --- a/cores/arduino/WVariant.h +++ b/cores/arduino/WVariant.h @@ -111,25 +111,25 @@ typedef enum _EPortType PORTC=2, } EPortType ; -typedef enum _EExt_Interrupts +typedef enum { - EXTERNAL_INT_0 = 0, // Available on pin 11 - EXTERNAL_INT_1, // Available on pin 13 - EXTERNAL_INT_2, // Available on pins 10, A0, A5 - EXTERNAL_INT_3, // Available on pin 12 - EXTERNAL_INT_4, // Available on pin 6, 8, A3 - EXTERNAL_INT_5, // Available on pin 7, 9, A4 - EXTERNAL_INT_6, // Available on pin 16 - EXTERNAL_INT_7, // Available on pin 17 - EXTERNAL_INT_8, // Available on pin A1 - EXTERNAL_INT_9, // Available on pin 3, A2 - EXTERNAL_INT_10, // Available on pin 0, 21 - EXTERNAL_INT_11, // Available on pin 1, 20 - EXTERNAL_INT_12, // Available on pin 18 - EXTERNAL_INT_13, // Available on pin EDBG_GPIO0 (43) - EXTERNAL_INT_14, // Available on pin 4 - EXTERNAL_INT_15, // Available on pin 5 - EXTERNAL_INT_NMI, // Available on pin 2 + EXTERNAL_INT_0 = 0, + EXTERNAL_INT_1, + EXTERNAL_INT_2, + EXTERNAL_INT_3, + EXTERNAL_INT_4, + EXTERNAL_INT_5, + EXTERNAL_INT_6, + EXTERNAL_INT_7, + EXTERNAL_INT_8, + EXTERNAL_INT_9, + EXTERNAL_INT_10, + EXTERNAL_INT_11, + EXTERNAL_INT_12, + EXTERNAL_INT_13, + EXTERNAL_INT_14, + EXTERNAL_INT_15, + EXTERNAL_INT_NMI, EXTERNAL_NUM_INTERRUPTS, NOT_AN_INTERRUPT = -1, EXTERNAL_INT_NONE = NOT_AN_INTERRUPT, diff --git a/cores/arduino/wiring_digital.c b/cores/arduino/wiring_digital.c index 59f9e4f1d..3bee23d2c 100644 --- a/cores/arduino/wiring_digital.c +++ b/cores/arduino/wiring_digital.c @@ -69,29 +69,47 @@ void pinMode( uint32_t ulPin, uint32_t ulMode ) } } -void digitalWrite( uint32_t ulPin, uint32_t ulVal ) +void digitalWrite(uint32_t ulPin, uint32_t ulVal) { - // Handle the case the pin isn't usable as PIO - if ( g_APinDescription[ulPin].ulPinType == PIO_NOT_A_PIN ) + uint32_t ulGPIOPin=g_APinDescription[ulPin].ulPin; + PortGroup* port=&(PORT->Group[g_APinDescription[ulPin].ulPort]); + + // Handle the case the pin is invalid + if (ulPin >= PINS_COUNT) { return ; } - // Enable pull-up resistor - PORT->Group[g_APinDescription[ulPin].ulPort].PINCFG[g_APinDescription[ulPin].ulPin].reg=(uint8_t)(PORT_PINCFG_PULLEN) ; - - switch ( ulVal ) + // Test if pin is set to INPUT mode, then activate pull-up according to ulVal + if (port->DIR.reg & (1ul<Group[g_APinDescription[ulPin].ulPort].OUTCLR.reg = (1ul << g_APinDescription[ulPin].ulPin) ; - break ; - - case HIGH: - PORT->Group[g_APinDescription[ulPin].ulPort].OUTSET.reg = (1ul << g_APinDescription[ulPin].ulPin) ; - break ; - - default: - break ; + switch (ulVal) + { + case LOW: + // Disable pull-up resistor + port->PINCFG[ulGPIOPin].bit.PULLEN=0; + break; + + case HIGH: + default: + // Enable pull-up resistor + port->PINCFG[ulGPIOPin].bit.PULLEN=1; + break; + } + } + else // pin is set to OUTPUT mode, we output the requested voltage level + { + switch (ulVal) + { + case LOW: + port->OUTCLR.reg=(1ul<OUTSET.reg=(1ul<= PINS_COUNT) { - return LOW ; + return LOW; } if ( (PORT->Group[g_APinDescription[ulPin].ulPort].IN.reg & (1ul << g_APinDescription[ulPin].ulPin)) != 0 ) { - return HIGH ; + return HIGH; } - return LOW ; + return LOW; } #ifdef __cplusplus diff --git a/libraries/SPI/SPI.cpp b/libraries/SPI/SPI.cpp index e4af0464a..62d28c0d5 100644 --- a/libraries/SPI/SPI.cpp +++ b/libraries/SPI/SPI.cpp @@ -28,15 +28,20 @@ const SPISettings DEFAULT_SPI_SETTINGS = SPISettings(); -SPIClass::SPIClass(SERCOM *p_sercom, uint8_t uc_pinMISO, uint8_t uc_pinSCK, uint8_t uc_pinMOSI) +SPIClass::SPIClass(SERCOM *p_sercom, uint8_t uc_pinMISO, uint8_t uc_pinSCK, uint8_t uc_pinMOSI, SercomSpiTXPad PadTx, SercomRXPad PadRx) { initialized = false; assert(p_sercom != NULL); _p_sercom = p_sercom; + // pins _uc_pinMiso = uc_pinMISO; _uc_pinSCK = uc_pinSCK; _uc_pinMosi = uc_pinMOSI; + + // SERCOM pads + _padTx=PadTx; + _padRx=PadRx; } void SPIClass::begin() @@ -65,7 +70,7 @@ void SPIClass::config(SPISettings settings) { _p_sercom->disableSPI(); - _p_sercom->initSPI(SPI_PAD_2_SCK_3, SERCOM_RX_PAD_0, SPI_CHAR_SIZE_8_BITS, settings.bitOrder); + _p_sercom->initSPI(_padTx, _padRx, SPI_CHAR_SIZE_8_BITS, settings.bitOrder); _p_sercom->initSPIClock(settings.dataMode, settings.clockFreq); _p_sercom->enableSPI(); @@ -197,4 +202,23 @@ void SPIClass::detachInterrupt() { // Should be disableInterrupt() } -SPIClass SPI( &sercom4, PIN_SPI_MISO, PIN_SPI_SCK, PIN_SPI_MOSI ); +#if SPI_INTERFACES_COUNT > 0 + +/* In case new variant doesn't define these macros, + * we put here the ones for Arduino Zero. + * + * These values should be different on some variants! + * + * The SPI PAD values can be found in cores/arduino/SERCOM.h: + * - SercomSpiTXPad + * - SercomRXPad + */ +#ifndef PERIPH_SPI +#define PERIPH_SPI sercom4 +#define PAD_SPI_TX SPI_PAD_2_SCK_3 +#define PAD_SPI_RX SERCOM_RX_PAD_0 +#endif // PERIPH_SPI + +SPIClass SPI( &PERIPH_SPI, PIN_SPI_MISO, PIN_SPI_SCK, PIN_SPI_MOSI, PAD_SPI_TX, PAD_SPI_RX ); + +#endif // SPI_INTERFACES_COUNT > 0 diff --git a/libraries/SPI/SPI.h b/libraries/SPI/SPI.h index 6259d2d76..63f311710 100644 --- a/libraries/SPI/SPI.h +++ b/libraries/SPI/SPI.h @@ -91,7 +91,8 @@ class SPISettings { class SPIClass { public: - SPIClass(SERCOM *p_sercom, uint8_t uc_pinMISO, uint8_t uc_pinSCK, uint8_t uc_pinMOSI); + SPIClass(SERCOM *p_sercom, uint8_t uc_pinMISO, uint8_t uc_pinSCK, uint8_t uc_pinMOSI, SercomSpiTXPad, SercomRXPad); + byte transfer(uint8_t data); inline void transfer(void *buf, size_t count); @@ -120,6 +121,10 @@ class SPIClass { uint8_t _uc_pinMiso; uint8_t _uc_pinMosi; uint8_t _uc_pinSCK; + + SercomSpiTXPad _padTx; + SercomRXPad _padRx; + bool initialized; uint8_t interruptMode; char interruptSave; diff --git a/libraries/SPI/library.properties b/libraries/SPI/library.properties new file mode 100644 index 000000000..3aaa770b8 --- /dev/null +++ b/libraries/SPI/library.properties @@ -0,0 +1,8 @@ +name=SPI +version=1.0 +author=Jonathan BAUDIN, Thibaut VIARD, Arduino +maintainer=Arduino +sentence=Enables the communication with devices that use the Serial Peripheral Interface (SPI) Bus. Specific implementation for Arduino Zero. +paragraph= +url=http://www.arduino.cc/en/Reference/SPI +architectures=samd diff --git a/libraries/Wire/Wire.cpp b/libraries/Wire/Wire.cpp index aabc1eff6..31e0a1d8a 100644 --- a/libraries/Wire/Wire.cpp +++ b/libraries/Wire/Wire.cpp @@ -26,9 +26,11 @@ extern "C" { #include "Wire.h" -TwoWire::TwoWire(SERCOM * s) +TwoWire::TwoWire(SERCOM * s, uint8_t pinSDA, uint8_t pinSCL) { this->sercom = s; + this->_uc_pinSDA=pinSDA; + this->_uc_pinSCL=pinSCL; transmissionBegun = false; } @@ -37,8 +39,8 @@ void TwoWire::begin(void) { sercom->initMasterWIRE(TWI_CLOCK); sercom->enableWIRE(); - pinPeripheral(PIN_WIRE_SDA, g_APinDescription[PIN_WIRE_SDA].ulPinType); - pinPeripheral(PIN_WIRE_SCL, g_APinDescription[PIN_WIRE_SCL].ulPinType); + pinPeripheral(_uc_pinSDA, g_APinDescription[_uc_pinSDA].ulPinType); + pinPeripheral(_uc_pinSCL, g_APinDescription[_uc_pinSCL].ulPinType); } void TwoWire::begin(uint8_t address) { @@ -47,6 +49,10 @@ void TwoWire::begin(uint8_t address) { sercom->enableWIRE(); } +void TwoWire::end() { + sercom->disableWIRE(); +} + void TwoWire::setClock(uint32_t frequency) { // dummy funtion } @@ -66,22 +72,15 @@ uint8_t TwoWire::requestFrom(uint8_t address, size_t quantity, bool stopBit) rxBuffer.store_char(sercom->readDataWIRE()); // Connected to slave - //while(toRead--) - for(byteRead = 0; byteRead < quantity; ++byteRead) + for (byteRead = 1; byteRead < quantity; ++byteRead) { - if( byteRead == quantity - 1) // Stop transmission - { - sercom->prepareNackBitWIRE(); // Prepare NACK to stop slave transmission - //sercom->readDataWIRE(); // Clear data register to send NACK - sercom->prepareCommandBitsWire(WIRE_MASTER_ACT_STOP); // Send Stop - } - else // Continue transmission - { - sercom->prepareAckBitWIRE(); // Prepare Acknowledge - sercom->prepareCommandBitsWire(WIRE_MASTER_ACT_READ); // Prepare the ACK command for the slave - rxBuffer.store_char( sercom->readDataWIRE() ); // Read data and send the ACK - } + sercom->prepareAckBitWIRE(); // Prepare Acknowledge + sercom->prepareCommandBitsWire(WIRE_MASTER_ACT_READ); // Prepare the ACK command for the slave + rxBuffer.store_char(sercom->readDataWIRE()); // Read data and send the ACK } + sercom->prepareNackBitWIRE(); // Prepare NACK to stop slave transmission + //sercom->readDataWIRE(); // Clear data register to send NACK + sercom->prepareCommandBitsWire(WIRE_MASTER_ACT_STOP); // Send Stop } return byteRead; @@ -132,12 +131,8 @@ uint8_t TwoWire::endTransmission(bool stopBit) sercom->prepareCommandBitsWire(WIRE_MASTER_ACT_STOP); return 3 ; // Nack or error } - - if(txBuffer.available() == 0) - { - sercom->prepareCommandBitsWire(WIRE_MASTER_ACT_STOP); - } } + sercom->prepareCommandBitsWire(WIRE_MASTER_ACT_STOP); return 0; } @@ -254,102 +249,23 @@ void TwoWire::onService(void) } } -/* -void TwoWire::onService(void) -{ - // Retrieve interrupt status - uint32_t sr = TWI_GetStatus(twi); - - if (status == SLAVE_IDLE && TWI_STATUS_SVACC(sr)) { - TWI_DisableIt(twi, TWI_IDR_SVACC); - TWI_EnableIt(twi, TWI_IER_RXRDY | TWI_IER_GACC | TWI_IER_NACK - | TWI_IER_EOSACC | TWI_IER_SCL_WS | TWI_IER_TXCOMP); - - srvBufferLength = 0; - srvBufferIndex = 0; - - // Detect if we should go into RECV or SEND status - // SVREAD==1 means *master* reading -> SLAVE_SEND - if (!TWI_STATUS_SVREAD(sr)) { - status = SLAVE_RECV; - } else { - status = SLAVE_SEND; - - // Alert calling program to generate a response ASAP - if (onRequestCallback) - onRequestCallback(); - else - // create a default 1-byte response - write((uint8_t) 0); - } - } - - if (status != SLAVE_IDLE) { - if (TWI_STATUS_TXCOMP(sr) && TWI_STATUS_EOSACC(sr)) { - if (status == SLAVE_RECV && onReceiveCallback) { - // Copy data into rxBuffer - // (allows to receive another packet while the - // user program reads actual data) - for (uint8_t i = 0; i < srvBufferLength; ++i) - rxBuffer[i] = srvBuffer[i]; - rxBufferIndex = 0; - rxBufferLength = srvBufferLength; - - // Alert calling program - onReceiveCallback( rxBufferLength); - } +#if WIRE_INTERFACES_COUNT > 0 - // Transfer completed - TWI_EnableIt(twi, TWI_SR_SVACC); - TWI_DisableIt(twi, TWI_IDR_RXRDY | TWI_IDR_GACC | TWI_IDR_NACK - | TWI_IDR_EOSACC | TWI_IDR_SCL_WS | TWI_IER_TXCOMP); - status = SLAVE_IDLE; - } - } +/* In case new variant doesn't define these macros, + * we put here the ones for Arduino Zero. + * + * These values should be different on some variants! + */ - if (status == SLAVE_RECV) { - if (TWI_STATUS_RXRDY(sr)) { - if (srvBufferLength < BUFFER_LENGTH) - srvBuffer[srvBufferLength++] = TWI_ReadByte(twi); - } - } +#ifndef PERIPH_WIRE +# define PERIPH_WIRE sercom3 +# define WIRE_IT_HANDLER SERCOM3_Handler +#endif // PERIPH_WIRE - if (status == SLAVE_SEND) { - if (TWI_STATUS_TXRDY(sr) && !TWI_STATUS_NACK(sr)) { - uint8_t c = 'x'; - if (srvBufferIndex < srvBufferLength) - c = srvBuffer[srvBufferIndex++]; - TWI_WriteByte(twi, c); - } - } -} -*/ +TwoWire Wire(&PERIPH_WIRE, PIN_WIRE_SDA, PIN_WIRE_SCL); -#if WIRE_INTERFACES_COUNT > 0 -/*static void Wire_Init(void) { - pmc_enable_periph_clk(WIRE_INTERFACE_ID); - PIO_Configure( - g_APinDescription[PIN_WIRE_SDA].pPort, - g_APinDescription[PIN_WIRE_SDA].ulPinType, - g_APinDescription[PIN_WIRE_SDA].ulPin, - g_APinDescription[PIN_WIRE_SDA].ulPinConfiguration); - PIO_Configure( - g_APinDescription[PIN_WIRE_SCL].pPort, - g_APinDescription[PIN_WIRE_SCL].ulPinType, - g_APinDescription[PIN_WIRE_SCL].ulPin, - g_APinDescription[PIN_WIRE_SCL].ulPinConfiguration); - - NVIC_DisableIRQ(WIRE_ISR_ID); - NVIC_ClearPendingIRQ(WIRE_ISR_ID); - NVIC_SetPriority(WIRE_ISR_ID, 0); - NVIC_EnableIRQ(WIRE_ISR_ID); -}*/ - - -TwoWire Wire(&sercom3); - -void SERCOM3_Handler(void) { +void WIRE_IT_HANDLER(void) { Wire.onService(); } -#endif +#endif // WIRE_INTERFACES_COUNT > 0 diff --git a/libraries/Wire/Wire.h b/libraries/Wire/Wire.h index 844168e35..4b4ce1e44 100644 --- a/libraries/Wire/Wire.h +++ b/libraries/Wire/Wire.h @@ -28,12 +28,16 @@ #define BUFFER_LENGTH 32 + // WIRE_HAS_END means Wire has end() +#define WIRE_HAS_END 1 + class TwoWire : public Stream { public: - TwoWire(SERCOM *s); + TwoWire(SERCOM *s, uint8_t pinSDA, uint8_t pinSCL); void begin(); void begin(uint8_t); + void end(); void setClock(uint32_t); // dummy function void beginTransmission(uint8_t); @@ -59,6 +63,9 @@ class TwoWire : public Stream private: SERCOM * sercom; + uint8_t _uc_pinSDA; + uint8_t _uc_pinSCL; + bool transmissionBegun; // RX Buffer diff --git a/libraries/Wire/library.properties b/libraries/Wire/library.properties new file mode 100644 index 000000000..eff193aa2 --- /dev/null +++ b/libraries/Wire/library.properties @@ -0,0 +1,9 @@ +name=Wire +version=1.0 +author=Jonathan BAUDIN, Thibaut VIARD, Arduino +maintainer=Arduino +sentence=Allows the communication between devices or sensors connected via Two Wire Interface Bus. Specific implementation for Arduino Zero. +paragraph= +url=http://www.arduino.cc/en/Reference/Wire +architectures=samd + diff --git a/variants/arduino_zero/variant.cpp b/variants/arduino_zero/variant.cpp index 84df4033e..ed19dc342 100644 --- a/variants/arduino_zero/variant.cpp +++ b/variants/arduino_zero/variant.cpp @@ -127,8 +127,8 @@ const PinDescription g_APinDescription[]= { PORTA, 21, PIO_DIGITAL, (PIN_ATTR_DIGITAL), No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER, EXTERNAL_INT_5 }, // Digital High - { PORTA, 6, PIO_TIMER, (PIN_ATTR_DIGITAL|PIN_ATTR_PWM|PIN_ATTR_TIMER), No_ADC_Channel, PWM1_CH0, TCC1_CH0, EXTERNAL_INT_4 }, // TCC1/WO[0] - { PORTA, 7, PIO_TIMER, (PIN_ATTR_DIGITAL|PIN_ATTR_PWM|PIN_ATTR_TIMER), No_ADC_Channel, PWM1_CH1, TCC1_CH1, EXTERNAL_INT_5 }, // TCC1/WO[1] + { PORTA, 6, PIO_TIMER, (PIN_ATTR_DIGITAL|PIN_ATTR_PWM|PIN_ATTR_TIMER), No_ADC_Channel, PWM1_CH0, TCC1_CH0, EXTERNAL_INT_6 }, // TCC1/WO[0] + { PORTA, 7, PIO_TIMER, (PIN_ATTR_DIGITAL|PIN_ATTR_PWM|PIN_ATTR_TIMER), No_ADC_Channel, PWM1_CH1, TCC1_CH1, EXTERNAL_INT_7 }, // TCC1/WO[1] { PORTA, 18, PIO_TIMER, (PIN_ATTR_DIGITAL|PIN_ATTR_PWM|PIN_ATTR_TIMER), No_ADC_Channel, PWM3_CH0, TC3_CH0, EXTERNAL_INT_2 }, // TC3/WO[0] { PORTA, 16, PIO_TIMER, (PIN_ATTR_DIGITAL|PIN_ATTR_PWM|PIN_ATTR_TIMER), No_ADC_Channel, PWM2_CH0, TCC2_CH0, EXTERNAL_INT_0 }, // TCC2/WO[0] { PORTA, 19, PIO_TIMER_ALT, (PIN_ATTR_DIGITAL|PIN_ATTR_PWM|PIN_ATTR_TIMER), No_ADC_Channel, PWM0_CH3, TCC0_CH3, EXTERNAL_INT_3 }, // TCC0/WO[3] diff --git a/variants/arduino_zero/variant.h b/variants/arduino_zero/variant.h index a1f1506e4..2e84db490 100644 --- a/variants/arduino_zero/variant.h +++ b/variants/arduino_zero/variant.h @@ -129,6 +129,9 @@ static const uint8_t ATN = PIN_ATN; #define PIN_SPI_MISO (22u) #define PIN_SPI_MOSI (23u) #define PIN_SPI_SCK (24u) +#define PERIPH_SPI sercom4 +#define PAD_SPI_TX SPI_PAD_2_SCK_3 +#define PAD_SPI_RX SERCOM_RX_PAD_0 static const uint8_t SS = PIN_A2 ; // SERCOM4 last PAD is present on A2 but HW SS isn't used. Set here only for reference. static const uint8_t MOSI = PIN_SPI_MOSI ; @@ -142,6 +145,8 @@ static const uint8_t SCK = PIN_SPI_SCK ; #define PIN_WIRE_SDA (20u) #define PIN_WIRE_SCL (21u) +#define PERIPH_WIRE sercom3 +#define WIRE_IT_HANDLER SERCOM3_Handler /* * USB