From 328f838cad183ac8042fdefd5cdd91869c5599bc Mon Sep 17 00:00:00 2001 From: Thibaut VIARD Date: Wed, 9 Sep 2015 17:41:28 +0200 Subject: [PATCH 01/21] [samd] fixing https://github.com/arduino/ArduinoCore-samd/issues/28 --- cores/arduino/wiring_digital.c | 52 +++++++++++++++++++++++----------- 1 file changed, 35 insertions(+), 17 deletions(-) diff --git a/cores/arduino/wiring_digital.c b/cores/arduino/wiring_digital.c index 59f9e4f1d..9a7ef08f9 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< Date: Fri, 24 Jul 2015 23:08:36 -0700 Subject: [PATCH 02/21] Fix two bugs that can cause deadlock conditions when i2c bus errors occur. The first occurs when starting a read transaction from a slave that doesn't respond. The code would wait until the SB (slave on bus) bit is set in the INTFLAGS register, but when a nack occurs that never happens so we're stuck in an infinite loop. The fix is to also look for the MB flag to be set. If it is, issue a stop condition and return. The second happens when a bus error (ie, an illegal stop condition) occurs while sending data as a master. In that case we are waiting for the MB (master on bus) flag to be set. When a bus error occurs that never happens, so again we end up in an infinite loop. The fix here is to also look for the BUSERR flag to be set. If it is, return an error condition. --- cores/arduino/SERCOM.cpp | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) 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) From b4378a1930d1c7b983a29215a824551f4790c5a5 Mon Sep 17 00:00:00 2001 From: Thibaut VIARD Date: Mon, 10 Aug 2015 13:36:31 +0200 Subject: [PATCH 03/21] [zero] prepare variant for SPI and Wire board parameters --- variants/arduino_zero/variant.h | 5 +++++ 1 file changed, 5 insertions(+) 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 From de9a5559f2acc352f1b6df452c775e76a627f1f9 Mon Sep 17 00:00:00 2001 From: Thibaut VIARD Date: Mon, 10 Aug 2015 13:39:31 +0200 Subject: [PATCH 04/21] [zero] Bring more customization to SPI class --- libraries/SPI/SPI.cpp | 15 ++++++++++++--- libraries/SPI/SPI.h | 7 ++++++- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/libraries/SPI/SPI.cpp b/libraries/SPI/SPI.cpp index e4af0464a..3bcb53c2b 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,8 @@ void SPIClass::detachInterrupt() { // Should be disableInterrupt() } -SPIClass SPI( &sercom4, PIN_SPI_MISO, PIN_SPI_SCK, PIN_SPI_MOSI ); +#if SPI_INTERFACES_COUNT > 0 + +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; From 6773245ce0e5e69339d5bb54cb55abdffc4c47f6 Mon Sep 17 00:00:00 2001 From: Thibaut VIARD Date: Mon, 10 Aug 2015 13:39:47 +0200 Subject: [PATCH 05/21] [zero] Bring more customization to Wire class --- libraries/Wire/Wire.cpp | 85 ++++------------------------------------- libraries/Wire/Wire.h | 5 ++- 2 files changed, 12 insertions(+), 78 deletions(-) diff --git a/libraries/Wire/Wire.cpp b/libraries/Wire/Wire.cpp index aabc1eff6..7679c9a1c 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) { @@ -254,77 +256,6 @@ 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); - } - - // 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; - } - } - - if (status == SLAVE_RECV) { - if (TWI_STATUS_RXRDY(sr)) { - if (srvBufferLength < BUFFER_LENGTH) - srvBuffer[srvBufferLength++] = TWI_ReadByte(twi); - } - } - - 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); - } - } -} -*/ - #if WIRE_INTERFACES_COUNT > 0 /*static void Wire_Init(void) { pmc_enable_periph_clk(WIRE_INTERFACE_ID); @@ -346,10 +277,10 @@ void TwoWire::onService(void) }*/ -TwoWire Wire(&sercom3); +TwoWire Wire(&PERIPH_WIRE, PIN_WIRE_SDA, PIN_WIRE_SCL); -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..a0bfa7363 100644 --- a/libraries/Wire/Wire.h +++ b/libraries/Wire/Wire.h @@ -31,7 +31,7 @@ class TwoWire : public Stream { public: - TwoWire(SERCOM *s); + TwoWire(SERCOM *s, uint8_t pinSDA, uint8_t pinSCL); void begin(); void begin(uint8_t); void setClock(uint32_t); // dummy function @@ -59,6 +59,9 @@ class TwoWire : public Stream private: SERCOM * sercom; + uint8_t _uc_pinSDA; + uint8_t _uc_pinSCL; + bool transmissionBegun; // RX Buffer From 5eea80bd027d7f856c2e9b1fa3bd36f26a18fe4b Mon Sep 17 00:00:00 2001 From: Thibaut VIARD Date: Tue, 11 Aug 2015 09:42:26 +0200 Subject: [PATCH 06/21] [zero/SPI] adding missing library properties --- libraries/SPI/library.properties | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 libraries/SPI/library.properties 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 From faa64900a59c1b79b3c188ab999650497349f015 Mon Sep 17 00:00:00 2001 From: Thibaut VIARD Date: Tue, 11 Aug 2015 09:42:44 +0200 Subject: [PATCH 07/21] [zero/Wire] adding missing library properties --- libraries/Wire/library.properties | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 libraries/Wire/library.properties 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 + From f81f69ceaa1992826899508a3e3f6637455caa20 Mon Sep 17 00:00:00 2001 From: Thibaut VIARD Date: Thu, 13 Aug 2015 12:05:14 +0200 Subject: [PATCH 08/21] [zero/SPI] Adding default values for SPI custom definitions --- libraries/SPI/SPI.cpp | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/libraries/SPI/SPI.cpp b/libraries/SPI/SPI.cpp index 3bcb53c2b..62d28c0d5 100644 --- a/libraries/SPI/SPI.cpp +++ b/libraries/SPI/SPI.cpp @@ -204,6 +204,21 @@ void SPIClass::detachInterrupt() { #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 From a3a0ff310f8d321f6a8bee726ce4ce77bbf494c2 Mon Sep 17 00:00:00 2001 From: Thibaut VIARD Date: Thu, 13 Aug 2015 12:09:25 +0200 Subject: [PATCH 09/21] [zero/Wire] Adding default values for Wire custom definitions --- libraries/Wire/Wire.cpp | 28 ++++++++++------------------ 1 file changed, 10 insertions(+), 18 deletions(-) diff --git a/libraries/Wire/Wire.cpp b/libraries/Wire/Wire.cpp index 7679c9a1c..af9ec1111 100644 --- a/libraries/Wire/Wire.cpp +++ b/libraries/Wire/Wire.cpp @@ -257,25 +257,17 @@ void TwoWire::onService(void) } #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); -}*/ +/* 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! + */ + +#ifndef PERIPH_WIRE +# define PERIPH_WIRE sercom3 +# define WIRE_IT_HANDLER SERCOM3_Handler +#endif // PERIPH_WIRE TwoWire Wire(&PERIPH_WIRE, PIN_WIRE_SDA, PIN_WIRE_SCL); From 00f1d7361599ebdfa3e84c9457c15b3f92d6376e Mon Sep 17 00:00:00 2001 From: Cristian Maglie Date: Thu, 13 Aug 2015 18:02:03 +0200 Subject: [PATCH 10/21] delay.h is included outside __cplusplus guards --- cores/arduino/Arduino.h | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) 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" From e3c69a227895903698aea0e1b3220179a7268766 Mon Sep 17 00:00:00 2001 From: Cristian Maglie Date: Thu, 13 Aug 2015 18:07:53 +0200 Subject: [PATCH 11/21] [Wire] simplified coding unnecessarily complex (hfvogt) In the wire library there are several functions where an unnecessarily complex coding has been used: - endTransmission: the availability of data is already checked in while(...), therefore need not be checked again in the loop. - requestFrom: the for-loop has a predefined and fixed number of loops. Therefore a check whether the last element has been reached is unnecessary and does not add any benefit. Fixes #20 --- libraries/Wire/Wire.cpp | 27 ++++++++------------------- 1 file changed, 8 insertions(+), 19 deletions(-) diff --git a/libraries/Wire/Wire.cpp b/libraries/Wire/Wire.cpp index af9ec1111..69ab284a1 100644 --- a/libraries/Wire/Wire.cpp +++ b/libraries/Wire/Wire.cpp @@ -68,22 +68,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; @@ -134,12 +127,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; } From 02d67509801028e5d8ddf9c3c42f8bb61713e425 Mon Sep 17 00:00:00 2001 From: Martino Facchin Date: Fri, 14 Aug 2015 10:35:57 +0200 Subject: [PATCH 12/21] relax digitalWrite parameter check calling digitalWrite with any value different from 0 will end in performing digitalWrite(HIGH) --- cores/arduino/wiring_digital.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/cores/arduino/wiring_digital.c b/cores/arduino/wiring_digital.c index 9a7ef08f9..3bee23d2c 100644 --- a/cores/arduino/wiring_digital.c +++ b/cores/arduino/wiring_digital.c @@ -117,18 +117,18 @@ void digitalWrite(uint32_t ulPin, uint32_t ulVal) int digitalRead( uint32_t ulPin ) { - // Handle the case the pin isn't usable as PIO - if ( g_APinDescription[ulPin].ulPinType == PIO_NOT_A_PIN ) + // Handle the case the pin is invalid + if (ulPin >= 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 From 7a3d29d73bc1520c963278b017667f3a5c8a1056 Mon Sep 17 00:00:00 2001 From: Cristian Maglie Date: Mon, 24 Aug 2015 12:26:44 +0200 Subject: [PATCH 13/21] Updated IPAddress class to the latest version --- cores/arduino/IPAddress.cpp | 31 ++++++++++++++++--------------- cores/arduino/IPAddress.h | 24 +++++++++++++++--------- 2 files changed, 31 insertions(+), 24 deletions(-) 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); From 2fd415a5088899d8d29eb6f2bada8ca253076874 Mon Sep 17 00:00:00 2001 From: Sandeep Mistry Date: Tue, 25 Aug 2015 10:48:54 -0400 Subject: [PATCH 14/21] implement Wire.end() for SAMD core --- libraries/Wire/Wire.cpp | 4 ++++ libraries/Wire/Wire.h | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/libraries/Wire/Wire.cpp b/libraries/Wire/Wire.cpp index 69ab284a1..31e0a1d8a 100644 --- a/libraries/Wire/Wire.cpp +++ b/libraries/Wire/Wire.cpp @@ -49,6 +49,10 @@ void TwoWire::begin(uint8_t address) { sercom->enableWIRE(); } +void TwoWire::end() { + sercom->disableWIRE(); +} + void TwoWire::setClock(uint32_t frequency) { // dummy funtion } diff --git a/libraries/Wire/Wire.h b/libraries/Wire/Wire.h index a0bfa7363..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, uint8_t pinSDA, uint8_t pinSCL); void begin(); void begin(uint8_t); + void end(); void setClock(uint32_t); // dummy function void beginTransmission(uint8_t); From c413e4d1372b0d29fb7c089ca29148d49dd2fb80 Mon Sep 17 00:00:00 2001 From: Cristian Maglie Date: Fri, 4 Sep 2015 15:09:04 +0200 Subject: [PATCH 15/21] Fixed EXT_INT numbers in variant for pin 8 and 9 See #30 --- variants/arduino_zero/variant.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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] From 67f74b9336d9cfbb74405827d33d718551bde201 Mon Sep 17 00:00:00 2001 From: Cristian Maglie Date: Fri, 4 Sep 2015 15:17:30 +0200 Subject: [PATCH 16/21] WInterrupts.c cosmetic fix --- cores/arduino/WInterrupts.c | 94 ++++++++++++++++--------------------- 1 file changed, 41 insertions(+), 53 deletions(-) diff --git a/cores/arduino/WInterrupts.c b/cores/arduino/WInterrupts.c index a28b9df64..93d888200 100644 --- a/cores/arduino/WInterrupts.c +++ b/cores/arduino/WInterrupts.c @@ -68,101 +68,89 @@ static void __initialize() * \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 ; - } + if (digitalPinToInterrupt(pin) == NOT_AN_INTERRUPT) + 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 ; + callbacksInt[digitalPinToInterrupt(pin)]._ulPin = pin; + callbacksInt[digitalPinToInterrupt(pin)]._callback = callback; // Check if normal interrupt or NMI - if ( ulPin != 2 ) + if (pin != 2) { // Look for right CONFIG register to be addressed - if ( digitalPinToInterrupt( ulPin ) > EXTERNAL_INT_7 ) - { - ulConfig = 1 ; - } - else - { - ulConfig = 0 ; + if (digitalPinToInterrupt(pin) > EXTERNAL_INT_7) { + config = 1; + } else { + config = 0; } // Configure the interrupt mode - ulPos = ((digitalPinToInterrupt( ulPin ) - (8*ulConfig) ) << 2) ; - switch ( ulMode ) + pos = ((digitalPinToInterrupt(pin) - (8 * config)) << 2); + switch (mode) { case LOW: - EIC->CONFIG[ulConfig].reg |= EIC_CONFIG_SENSE0_LOW_Val << ulPos ; - break ; + EIC->CONFIG[config].reg |= EIC_CONFIG_SENSE0_LOW_Val << pos; + 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 ; + EIC->CONFIG[config].reg |= EIC_CONFIG_SENSE0_HIGH_Val << pos; + 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 ; + EIC->CONFIG[config].reg |= EIC_CONFIG_SENSE0_BOTH_Val << pos; + 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 ; + EIC->CONFIG[config].reg |= EIC_CONFIG_SENSE0_FALL_Val << pos; + 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 ; + EIC->CONFIG[config].reg |= EIC_CONFIG_SENSE0_RISE_Val << pos; + break; } // Enable the interrupt - EIC->INTENSET.reg = EIC_INTENSET_EXTINT( 1 << digitalPinToInterrupt( ulPin ) ) ; + EIC->INTENSET.reg = EIC_INTENSET_EXTINT(1 << digitalPinToInterrupt(pin)); } else // Handles NMI on pin 2 { // Configure the interrupt mode - switch ( ulMode ) + switch (mode) { case LOW: - EIC->NMICTRL.reg = EIC_NMICTRL_NMISENSE_LOW ; - break ; + EIC->NMICTRL.reg = EIC_NMICTRL_NMISENSE_LOW; + break; case HIGH: - EIC->NMICTRL.reg = EIC_NMICTRL_NMISENSE_HIGH ; - break ; + EIC->NMICTRL.reg = EIC_NMICTRL_NMISENSE_HIGH; + break; case CHANGE: - EIC->NMICTRL.reg = EIC_NMICTRL_NMISENSE_BOTH ; - break ; + EIC->NMICTRL.reg = EIC_NMICTRL_NMISENSE_BOTH; + break; case FALLING: - EIC->NMICTRL.reg = EIC_NMICTRL_NMISENSE_FALL ; - break ; + EIC->NMICTRL.reg = EIC_NMICTRL_NMISENSE_FALL; + break; case RISING: - EIC->NMICTRL.reg= EIC_NMICTRL_NMISENSE_RISE ; - break ; + EIC->NMICTRL.reg= EIC_NMICTRL_NMISENSE_RISE; + break; } } } From 7edab1a4ccd62aacd0e75866365d39e5cf30e4d9 Mon Sep 17 00:00:00 2001 From: Cristian Maglie Date: Fri, 4 Sep 2015 15:20:26 +0200 Subject: [PATCH 17/21] NMI interrupts are now correctly ignored by attach/detachInterrupt Fixes #30 --- cores/arduino/WInterrupts.c | 121 +++++++++++------------------------- 1 file changed, 35 insertions(+), 86 deletions(-) diff --git a/cores/arduino/WInterrupts.c b/cores/arduino/WInterrupts.c index 93d888200..be6db38b9 100644 --- a/cores/arduino/WInterrupts.c +++ b/cores/arduino/WInterrupts.c @@ -76,6 +76,8 @@ void attachInterrupt(uint32_t pin, voidFuncPtr callback, uint32_t mode) if (digitalPinToInterrupt(pin) == NOT_AN_INTERRUPT) return; + if (digitalPinToInterrupt(pin) == EXTERNAL_INT_NMI) + return; if (!enabled) { __initialize(); @@ -89,91 +91,53 @@ void attachInterrupt(uint32_t pin, voidFuncPtr callback, uint32_t mode) callbacksInt[digitalPinToInterrupt(pin)]._ulPin = pin; callbacksInt[digitalPinToInterrupt(pin)]._callback = callback; - // Check if normal interrupt or NMI - if (pin != 2) - { - // Look for right CONFIG register to be addressed - if (digitalPinToInterrupt(pin) > EXTERNAL_INT_7) { - config = 1; - } else { - config = 0; - } - - // Configure the interrupt mode - pos = ((digitalPinToInterrupt(pin) - (8 * config)) << 2); - switch (mode) - { - case LOW: - EIC->CONFIG[config].reg |= EIC_CONFIG_SENSE0_LOW_Val << pos; - break; - - case HIGH: - EIC->CONFIG[config].reg |= EIC_CONFIG_SENSE0_HIGH_Val << pos; - break; - - case CHANGE: - EIC->CONFIG[config].reg |= EIC_CONFIG_SENSE0_BOTH_Val << pos; - break; - - case FALLING: - EIC->CONFIG[config].reg |= EIC_CONFIG_SENSE0_FALL_Val << pos; - break; - - case RISING: - EIC->CONFIG[config].reg |= EIC_CONFIG_SENSE0_RISE_Val << pos; - break; - } - - // Enable the interrupt - EIC->INTENSET.reg = EIC_INTENSET_EXTINT(1 << digitalPinToInterrupt(pin)); + // Look for right CONFIG register to be addressed + if (digitalPinToInterrupt(pin) > EXTERNAL_INT_7) { + config = 1; + } else { + config = 0; } - else // Handles NMI on pin 2 + + // Configure the interrupt mode + pos = ((digitalPinToInterrupt(pin) - (8 * config)) << 2); + switch (mode) { - // Configure the interrupt mode - switch (mode) - { - 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 << digitalPinToInterrupt(pin)); } /* * \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; - - // Disable interrupt - pio->PIO_IDR = mask; -*/ - if ( digitalPinToInterrupt( ulPin ) == NOT_AN_INTERRUPT ) - { - return ; - } + if (digitalPinToInterrupt(pin) == NOT_AN_INTERRUPT) + return; + if (digitalPinToInterrupt(pin) == EXTERNAL_INT_NMI) + return; - EIC->INTENCLR.reg = EIC_INTENCLR_EXTINT( 1 << digitalPinToInterrupt( ulPin ) ) ; + EIC->INTENCLR.reg = EIC_INTENCLR_EXTINT(1 << digitalPinToInterrupt(pin)); } /* @@ -200,21 +164,6 @@ void EIC_Handler( void ) } } -/* - * 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 From 4e83b1db5db707399de6653a699168a9787d8d13 Mon Sep 17 00:00:00 2001 From: Cristian Maglie Date: Fri, 4 Sep 2015 15:35:38 +0200 Subject: [PATCH 18/21] Simplified "callbacksInt" structure in WInterrupts.c --- cores/arduino/WInterrupts.c | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/cores/arduino/WInterrupts.c b/cores/arduino/WInterrupts.c index be6db38b9..2c6ed74e1 100644 --- a/cores/arduino/WInterrupts.c +++ b/cores/arduino/WInterrupts.c @@ -25,16 +25,12 @@ 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 ) ; @@ -88,8 +84,7 @@ void attachInterrupt(uint32_t pin, voidFuncPtr callback, uint32_t mode) pinPeripheral(pin, PIO_EXTINT); // Assign callback to interrupt - callbacksInt[digitalPinToInterrupt(pin)]._ulPin = pin; - callbacksInt[digitalPinToInterrupt(pin)]._callback = callback; + callbacksInt[digitalPinToInterrupt(pin)] = callback; // Look for right CONFIG register to be addressed if (digitalPinToInterrupt(pin) > EXTERNAL_INT_7) { @@ -153,9 +148,8 @@ void EIC_Handler( void ) if ( (EIC->INTFLAG.reg & ( 1 << ul ) ) != 0 ) { // Call the callback function if assigned - if ( callbacksInt[ul]._callback != NULL ) - { - callbacksInt[ul]._callback() ; + if (callbacksInt[ul]) { + callbacksInt[ul](); } // Clear the interrupt From 6fd2090e2047cf15fa6fd40b996cfcf055882c8d Mon Sep 17 00:00:00 2001 From: Cristian Maglie Date: Fri, 4 Sep 2015 17:16:21 +0200 Subject: [PATCH 19/21] Cosmetic changes in WInterrupt.* --- cores/arduino/WInterrupts.c | 39 +++++++++++++------------------------ cores/arduino/WInterrupts.h | 35 +++++---------------------------- cores/arduino/WVariant.h | 36 +++++++++++++++++----------------- 3 files changed, 37 insertions(+), 73 deletions(-) diff --git a/cores/arduino/WInterrupts.c b/cores/arduino/WInterrupts.c index 2c6ed74e1..23b3d0710 100644 --- a/cores/arduino/WInterrupts.c +++ b/cores/arduino/WInterrupts.c @@ -32,32 +32,23 @@ static void __initialize() { 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) { } } /* @@ -138,22 +129,20 @@ void detachInterrupt(uint32_t pin) /* * 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]) { - callbacksInt[ul](); + if (callbacksInt[i]) { + callbacksInt[i](); } // Clear the interrupt - EIC->INTFLAG.reg = 1 << ul ; + EIC->INTFLAG.reg = 1 << i; } } } 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, From 66003049dad68efd6e77c5d2681cf4b544c32ebf Mon Sep 17 00:00:00 2001 From: Cristian Maglie Date: Fri, 4 Sep 2015 17:17:22 +0200 Subject: [PATCH 20/21] Removed redundant #ifdef __cplusplus in WInterrupts.c --- cores/arduino/WInterrupts.c | 8 -------- 1 file changed, 8 deletions(-) diff --git a/cores/arduino/WInterrupts.c b/cores/arduino/WInterrupts.c index 23b3d0710..a49c19ef6 100644 --- a/cores/arduino/WInterrupts.c +++ b/cores/arduino/WInterrupts.c @@ -21,10 +21,6 @@ #include -#ifdef __cplusplus -extern "C" { -#endif - static voidFuncPtr callbacksInt[EXTERNAL_NUM_INTERRUPTS]; /* Configure I/O interrupt sources */ @@ -146,7 +142,3 @@ void EIC_Handler(void) } } } - -#ifdef __cplusplus -} -#endif From 7f435b8f4ba80aa99c402e93b209b50d36048c07 Mon Sep 17 00:00:00 2001 From: Cristian Maglie Date: Fri, 4 Sep 2015 17:21:19 +0200 Subject: [PATCH 21/21] WInterrupts: optimized use of digitalPinToInterrupt() --- cores/arduino/WInterrupts.c | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/cores/arduino/WInterrupts.c b/cores/arduino/WInterrupts.c index a49c19ef6..2936452d7 100644 --- a/cores/arduino/WInterrupts.c +++ b/cores/arduino/WInterrupts.c @@ -57,9 +57,8 @@ void attachInterrupt(uint32_t pin, voidFuncPtr callback, uint32_t mode) uint32_t config; uint32_t pos; - if (digitalPinToInterrupt(pin) == NOT_AN_INTERRUPT) - return; - if (digitalPinToInterrupt(pin) == EXTERNAL_INT_NMI) + EExt_Interrupts in = digitalPinToInterrupt(pin); + if (in == NOT_AN_INTERRUPT || in == EXTERNAL_INT_NMI) return; if (!enabled) { @@ -71,17 +70,17 @@ void attachInterrupt(uint32_t pin, voidFuncPtr callback, uint32_t mode) pinPeripheral(pin, PIO_EXTINT); // Assign callback to interrupt - callbacksInt[digitalPinToInterrupt(pin)] = callback; + callbacksInt[in] = callback; // Look for right CONFIG register to be addressed - if (digitalPinToInterrupt(pin) > EXTERNAL_INT_7) { + if (in > EXTERNAL_INT_7) { config = 1; } else { config = 0; } // Configure the interrupt mode - pos = ((digitalPinToInterrupt(pin) - (8 * config)) << 2); + pos = (in - (8 * config)) << 2; switch (mode) { case LOW: @@ -106,7 +105,7 @@ void attachInterrupt(uint32_t pin, voidFuncPtr callback, uint32_t mode) } // Enable the interrupt - EIC->INTENSET.reg = EIC_INTENSET_EXTINT(1 << digitalPinToInterrupt(pin)); + EIC->INTENSET.reg = EIC_INTENSET_EXTINT(1 << in); } /* @@ -114,12 +113,11 @@ void attachInterrupt(uint32_t pin, voidFuncPtr callback, uint32_t mode) */ void detachInterrupt(uint32_t pin) { - if (digitalPinToInterrupt(pin) == NOT_AN_INTERRUPT) - return; - if (digitalPinToInterrupt(pin) == EXTERNAL_INT_NMI) + EExt_Interrupts in = digitalPinToInterrupt(pin); + if (in == NOT_AN_INTERRUPT || in == EXTERNAL_INT_NMI) return; - EIC->INTENCLR.reg = EIC_INTENCLR_EXTINT(1 << digitalPinToInterrupt(pin)); + EIC->INTENCLR.reg = EIC_INTENCLR_EXTINT(1 << in); } /*