From 3d5ef6d5d97d36750b7b62a7638f26f530fa2a37 Mon Sep 17 00:00:00 2001 From: PaulStoffregen Date: Fri, 1 Aug 2014 05:38:27 -0700 Subject: [PATCH 1/8] SPI Transactions for AVR --- hardware/arduino/avr/libraries/SPI/SPI.cpp | 104 ++++++-- hardware/arduino/avr/libraries/SPI/SPI.h | 266 +++++++++++++++++++-- 2 files changed, 325 insertions(+), 45 deletions(-) diff --git a/hardware/arduino/avr/libraries/SPI/SPI.cpp b/hardware/arduino/avr/libraries/SPI/SPI.cpp index 5e48073f7..9a7a400e1 100644 --- a/hardware/arduino/avr/libraries/SPI/SPI.cpp +++ b/hardware/arduino/avr/libraries/SPI/SPI.cpp @@ -1,5 +1,6 @@ /* * Copyright (c) 2010 by Cristian Maglie + * Copyright (c) 2014 by Paul Stoffregen (Transaction API) * SPI Master library for arduino. * * This file is free software; you can redistribute it and/or modify @@ -8,13 +9,20 @@ * published by the Free Software Foundation. */ -#include "pins_arduino.h" #include "SPI.h" +#include "pins_arduino.h" SPIClass SPI; -void SPIClass::begin() { +uint8_t SPIClass::interruptMode = 0; +uint8_t SPIClass::interruptMask = 0; +uint8_t SPIClass::interruptSave = 0; +#ifdef SPI_TRANSACTION_MISMATCH_LED +uint8_t SPIClass::inTransactionFlag = 0; +#endif +void SPIClass::begin() +{ // Set SS to high so a connected chip will be "deselected" by default digitalWrite(SS, HIGH); @@ -39,28 +47,86 @@ void SPIClass::begin() { pinMode(MOSI, OUTPUT); } - void SPIClass::end() { SPCR &= ~_BV(SPE); } -void SPIClass::setBitOrder(uint8_t bitOrder) +// mapping of interrupt numbers to bits within SPI_AVR_EIMSK +#if defined(__AVR_ATmega32U4__) + #define SPI_INT0_MASK (1< 1) return; + + noInterrupts(); + switch (interruptNumber) { + #ifdef SPI_INT0_MASK + case 0: mask = SPI_INT0_MASK; break; + #endif + #ifdef SPI_INT1_MASK + case 1: mask = SPI_INT1_MASK; break; + #endif + #ifdef SPI_INT2_MASK + case 2: mask = SPI_INT2_MASK; break; + #endif + #ifdef SPI_INT3_MASK + case 3: mask = SPI_INT3_MASK; break; + #endif + #ifdef SPI_INT4_MASK + case 4: mask = SPI_INT4_MASK; break; + #endif + #ifdef SPI_INT5_MASK + case 5: mask = SPI_INT5_MASK; break; + #endif + #ifdef SPI_INT6_MASK + case 6: mask = SPI_INT6_MASK; break; + #endif + #ifdef SPI_INT7_MASK + case 7: mask = SPI_INT7_MASK; break; + #endif + default: + interruptMode = 2; + interrupts(); + return; } -} - -void SPIClass::setDataMode(uint8_t mode) -{ - SPCR = (SPCR & ~SPI_MODE_MASK) | mode; -} - -void SPIClass::setClockDivider(uint8_t rate) -{ - SPCR = (SPCR & ~SPI_CLOCK_MASK) | (rate & SPI_CLOCK_MASK); - SPSR = (SPSR & ~SPI_2XCLOCK_MASK) | ((rate >> 2) & SPI_2XCLOCK_MASK); + interruptMode = 1; + interruptMask |= mask; + interrupts(); } diff --git a/hardware/arduino/avr/libraries/SPI/SPI.h b/hardware/arduino/avr/libraries/SPI/SPI.h index f647d5c89..962100bc0 100644 --- a/hardware/arduino/avr/libraries/SPI/SPI.h +++ b/hardware/arduino/avr/libraries/SPI/SPI.h @@ -1,5 +1,7 @@ /* * Copyright (c) 2010 by Cristian Maglie + * Copyright (c) 2014 by Paul Stoffregen (Transaction API) + * Copyright (c) 2014 by Matthijs Kooijman (SPISettings AVR) * SPI Master library for arduino. * * This file is free software; you can redistribute it and/or modify @@ -11,9 +13,24 @@ #ifndef _SPI_H_INCLUDED #define _SPI_H_INCLUDED -#include #include -#include + +// SPI_HAS_TRANSACTION means SPI has beginTransaction(), endTransaction(), +// usingInterrupt(), and SPISetting(clock, bitOrder, dataMode) +#define SPI_HAS_TRANSACTION 1 + +// Uncomment this line to add detection of mismatched begin/end transactions. +// A mismatch occurs if other libraries fail to use SPI.endTransaction() for +// each SPI.beginTransaction(). Connect a LED to this pin. The LED will turn +// on if any mismatch is ever detected. +//#define SPI_TRANSACTION_MISMATCH_LED 5 + +#ifndef LSBFIRST +#define LSBFIRST 0 +#endif +#ifndef MSBFIRST +#define MSBFIRST 1 +#endif #define SPI_CLOCK_DIV4 0x00 #define SPI_CLOCK_DIV16 0x01 @@ -22,7 +39,6 @@ #define SPI_CLOCK_DIV2 0x04 #define SPI_CLOCK_DIV8 0x05 #define SPI_CLOCK_DIV32 0x06 -//#define SPI_CLOCK_DIV64 0x07 #define SPI_MODE0 0x00 #define SPI_MODE1 0x04 @@ -33,38 +49,236 @@ #define SPI_CLOCK_MASK 0x03 // SPR1 = bit 1, SPR0 = bit 0 on SPCR #define SPI_2XCLOCK_MASK 0x01 // SPI2X = bit 0 on SPSR +// define SPI_AVR_EIMSK for AVR boards with external interrupt pins +#if defined(EIMSK) + #define SPI_AVR_EIMSK EIMSK +#elif defined(GICR) + #define SPI_AVR_EIMSK GICR +#elif defined(GIMSK) + #define SPI_AVR_EIMSK GIMSK +#endif + +class SPISettings { +public: + SPISettings(uint32_t clock, uint8_t bitOrder, uint8_t dataMode) { + if (__builtin_constant_p(clock)) { + init_AlwaysInline(clock, bitOrder, dataMode); + } else { + init_MightInline(clock, bitOrder, dataMode); + } + } + SPISettings() { + init_AlwaysInline(4000000, MSBFIRST, SPI_MODE0); + } +private: + void init_MightInline(uint32_t clock, uint8_t bitOrder, uint8_t dataMode) { + init_AlwaysInline(clock, bitOrder, dataMode); + } + void init_AlwaysInline(uint32_t clock, uint8_t bitOrder, uint8_t dataMode) + __attribute__((__always_inline__)) { + // Clock settings are defined as follows. Note that this shows SPI2X + // inverted, so the bits form increasing numbers. Also note that + // fosc/64 appears twice + // SPR1 SPR0 ~SPI2X Freq + // 0 0 0 fosc/2 + // 0 0 1 fosc/4 + // 0 1 0 fosc/8 + // 0 1 1 fosc/16 + // 1 0 0 fosc/32 + // 1 0 1 fosc/64 + // 1 1 0 fosc/64 + // 1 1 1 fosc/128 + + // We find the fastest clock that is less than or equal to the + // given clock rate. The clock divider that results in clock_setting + // is 2 ^^ (clock_div + 1). If nothing is slow enough, we'll use the + // slowest (128 == 2 ^^ 7, so clock_div = 6). + uint8_t clockDiv; + + // When the clock is known at compiletime, use this if-then-else + // cascade, which the compiler knows how to completely optimize + // away. When clock is not known, use a loop instead, which generates + // shorter code. + if (__builtin_constant_p(clock)) { + if (clock >= F_CPU / 2) { + clockDiv = 0; + } else if (clock >= F_CPU / 4) { + clockDiv = 1; + } else if (clock >= F_CPU / 8) { + clockDiv = 2; + } else if (clock >= F_CPU / 16) { + clockDiv = 3; + } else if (clock >= F_CPU / 32) { + clockDiv = 4; + } else if (clock >= F_CPU / 64) { + clockDiv = 5; + } else { + clockDiv = 6; + } + } else { + uint32_t clockSetting = F_CPU / 2; + clockDiv = 0; + while (clockDiv < 6 && clock < clockSetting) { + clockSetting /= 2; + clockDiv++; + } + } + + // Compensate for the duplicate fosc/64 + if (clockDiv == 6) + clockDiv = 7; + + // Invert the SPI2X bit + clockDiv ^= 0x1; + + // Pack into the SPISettings class + spcr = _BV(SPE) | _BV(MSTR) | ((bitOrder == LSBFIRST) ? _BV(DORD) : 0) | + (dataMode & SPI_MODE_MASK) | ((clockDiv >> 1) & SPI_CLOCK_MASK); + spsr = clockDiv & SPI_2XCLOCK_MASK; + } + uint8_t spcr; + uint8_t spsr; + friend class SPIClass; +}; + + class SPIClass { public: - inline static byte transfer(byte _data); + // Initialize the SPI library + static void begin(); - // SPI Configuration methods + // If SPI is to used from within an interrupt, this function registers + // that interrupt with the SPI library, so beginTransaction() can + // prevent conflicts. The input interruptNumber is the number used + // with attachInterrupt. If SPI is used from a different interrupt + // (eg, a timer), interruptNumber should be 255. + static void usingInterrupt(uint8_t interruptNumber); - inline static void attachInterrupt(); - inline static void detachInterrupt(); // Default + // Before using SPI.transfer() or asserting chip select pins, + // this function is used to gain exclusive access to the SPI bus + // and configure the correct settings. + inline static void beginTransaction(SPISettings settings) { + if (interruptMode > 0) { + #ifdef SPI_AVR_EIMSK + if (interruptMode == 1) { + interruptSave = SPI_AVR_EIMSK; + SPI_AVR_EIMSK &= ~interruptMask; + } else + #endif + { + interruptSave = SREG; + cli(); + } + } + #ifdef SPI_TRANSACTION_MISMATCH_LED + if (inTransactionFlag) { + pinMode(SPI_TRANSACTION_MISMATCH_LED, OUTPUT); + digitalWrite(SPI_TRANSACTION_MISMATCH_LED, HIGH); + } + inTransactionFlag = 1; + #endif + SPCR = settings.spcr; + SPSR = settings.spsr; + } - static void begin(); // Default + // Write to the SPI bus (MOSI pin) and also receive (MISO pin) + inline static uint8_t transfer(uint8_t data) { + SPDR = data; + asm volatile("nop"); + while (!(SPSR & _BV(SPIF))) ; // wait + return SPDR; + } + inline static uint16_t transfer16(uint16_t data) { + union { uint16_t val; struct { uint8_t lsb; uint8_t msb; }; } in, out; + in.val = data; + if (!(SPCR & _BV(DORD))) { + SPDR = in.msb; + while (!(SPSR & _BV(SPIF))) ; + out.msb = SPDR; + SPDR = in.lsb; + while (!(SPSR & _BV(SPIF))) ; + out.lsb = SPDR; + } else { + SPDR = in.lsb; + while (!(SPSR & _BV(SPIF))) ; + out.lsb = SPDR; + SPDR = in.msb; + while (!(SPSR & _BV(SPIF))) ; + out.msb = SPDR; + } + return out.val; + } + inline static void transfer(void *buf, size_t count) { + if (count == 0) return; + uint8_t *p = (uint8_t *)buf; + SPDR = *p; + while (--count > 0) { + uint8_t out = *(p + 1); + while (!(SPSR & _BV(SPIF))) ; + uint8_t in = SPDR; + SPDR = out; + *p++ = in; + } + while (!(SPSR & _BV(SPIF))) ; + *p = SPDR; + } + // After performing a group of transfers and releasing the chip select + // signal, this function allows others to access the SPI bus + inline static void endTransaction(void) { + #ifdef SPI_TRANSACTION_MISMATCH_LED + if (!inTransactionFlag) { + pinMode(SPI_TRANSACTION_MISMATCH_LED, OUTPUT); + digitalWrite(SPI_TRANSACTION_MISMATCH_LED, HIGH); + } + inTransactionFlag = 0; + #endif + if (interruptMode > 0) { + #ifdef SPI_AVR_EIMSK + if (interruptMode == 1) { + SPI_AVR_EIMSK = interruptSave; + } else + #endif + { + SREG = interruptSave; + } + } + } + + // Disable the SPI bus static void end(); - static void setBitOrder(uint8_t); - static void setDataMode(uint8_t); - static void setClockDivider(uint8_t); + // This function is deprecated. New applications should use + // beginTransaction() to configure SPI settings. + inline static void setBitOrder(uint8_t bitOrder) { + if (bitOrder == LSBFIRST) SPCR |= _BV(DORD); + else SPCR &= ~(_BV(DORD)); + } + // This function is deprecated. New applications should use + // beginTransaction() to configure SPI settings. + inline static void setDataMode(uint8_t dataMode) { + SPCR = (SPCR & ~SPI_MODE_MASK) | dataMode; + } + // This function is deprecated. New applications should use + // beginTransaction() to configure SPI settings. + inline static void setClockDivider(uint8_t clockDiv) { + SPCR = (SPCR & ~SPI_CLOCK_MASK) | (clockDiv & SPI_CLOCK_MASK); + SPSR = (SPSR & ~SPI_2XCLOCK_MASK) | ((clockDiv >> 2) & SPI_2XCLOCK_MASK); + } + // These undocumented functions should not be used. SPI.transfer() + // polls the hardware flag which is automatically cleared as the + // AVR responds to SPI's interrupt + inline static void attachInterrupt() { SPCR |= _BV(SPIE); } + inline static void detachInterrupt() { SPCR &= ~_BV(SPIE); } + +private: + static uint8_t interruptMode; // 0=none, 1=mask, 2=global + static uint8_t interruptMask; // which interrupts to mask + static uint8_t interruptSave; // temp storage, to restore state + #ifdef SPI_TRANSACTION_MISMATCH_LED + static uint8_t inTransactionFlag; + #endif }; extern SPIClass SPI; -byte SPIClass::transfer(byte _data) { - SPDR = _data; - while (!(SPSR & _BV(SPIF))) - ; - return SPDR; -} - -void SPIClass::attachInterrupt() { - SPCR |= _BV(SPIE); -} - -void SPIClass::detachInterrupt() { - SPCR &= ~_BV(SPIE); -} - #endif From abb37e202f771287bbee7814a0e204e39ce9d0f9 Mon Sep 17 00:00:00 2001 From: PaulStoffregen Date: Fri, 1 Aug 2014 05:57:13 -0700 Subject: [PATCH 2/8] SPI Transactions for Arduino Due --- hardware/arduino/sam/libraries/SPI/SPI.cpp | 83 +++++- hardware/arduino/sam/libraries/SPI/SPI.h | 318 ++++++++++++++++++++- 2 files changed, 397 insertions(+), 4 deletions(-) diff --git a/hardware/arduino/sam/libraries/SPI/SPI.cpp b/hardware/arduino/sam/libraries/SPI/SPI.cpp index 9517e2226..faa395f44 100644 --- a/hardware/arduino/sam/libraries/SPI/SPI.cpp +++ b/hardware/arduino/sam/libraries/SPI/SPI.cpp @@ -1,5 +1,6 @@ /* * Copyright (c) 2010 by Cristian Maglie + * Copyright (c) 2014 by Paul Stoffregen (Transaction API) * SPI Master library for arduino. * * This file is free software; you can redistribute it and/or modify @@ -18,7 +19,6 @@ SPIClass::SPIClass(Spi *_spi, uint32_t _id, void(*_initCb)(void)) : void SPIClass::begin() { init(); - // NPCS control is left to the user // Default speed set to 4Mhz @@ -46,12 +46,88 @@ void SPIClass::begin(uint8_t _pin) { void SPIClass::init() { if (initialized) return; + interruptMode = 0; + interruptMask = 0; + interruptSave = 0; initCb(); SPI_Configure(spi, id, SPI_MR_MSTR | SPI_MR_PS | SPI_MR_MODFDIS); SPI_Enable(spi); initialized = true; } +#ifndef interruptsStatus +#define interruptsStatus() __interruptsStatus() +static inline unsigned char __interruptsStatus(void) __attribute__((always_inline, unused)); +static inline unsigned char __interruptsStatus(void) { + unsigned int primask; + asm volatile ("mrs %0, primask" : "=r" (primask)); + if (primask) return 0; + return 1; +} +#endif + +void SPIClass::usingInterrupt(uint8_t interruptNumber) +{ + uint8_t irestore; + + irestore = interruptsStatus(); + noInterrupts(); + if (interruptMode < 2) { + if (interruptNumber > NUM_DIGITAL_PINS) { + interruptMode = 2; + } else { + uint8_t imask = interruptMask; + Pio *pio = g_APinDescription[interruptNumber].pPort; + if (pio == PIOA) { + imask |= 1; + } else if (pio == PIOB) { + imask |= 2; + } else if (pio == PIOC) { + imask |= 4; + } else if (pio == PIOD) { + imask |= 8; + } + interruptMask = imask; + interruptMode = 1; + } + } + if (irestore) interrupts(); +} + +void SPIClass::beginTransaction(uint8_t pin, SPISettings settings) +{ + if (interruptMode > 0) { + if (interruptMode == 1) { + uint8_t imask = interruptMask; + if (imask & 1) NVIC_DisableIRQ(PIOA_IRQn); + if (imask & 2) NVIC_DisableIRQ(PIOB_IRQn); + if (imask & 4) NVIC_DisableIRQ(PIOC_IRQn); + if (imask & 8) NVIC_DisableIRQ(PIOD_IRQn); + } else { + interruptSave = interruptsStatus(); + noInterrupts(); + } + } + uint32_t ch = BOARD_PIN_TO_SPI_CHANNEL(pin); + bitOrder[ch] = settings.border; + SPI_ConfigureNPCS(spi, ch, settings.config); +} + +void SPIClass::endTransaction(void) +{ + if (interruptMode > 0) { + if (interruptMode == 1) { + uint8_t imask = interruptMask; + if (imask & 1) NVIC_EnableIRQ(PIOA_IRQn); + if (imask & 2) NVIC_EnableIRQ(PIOB_IRQn); + if (imask & 4) NVIC_EnableIRQ(PIOC_IRQn); + if (imask & 8) NVIC_EnableIRQ(PIOD_IRQn); + } else { + if (interruptSave) interrupts(); + } + } +} + void SPIClass::end(uint8_t _pin) { uint32_t spiPin = BOARD_PIN_TO_SPI_PIN(_pin); // Setting the pin as INPUT will disconnect it from SPI peripheral @@ -95,12 +171,12 @@ byte SPIClass::transfer(byte _pin, uint8_t _data, SPITransferMode _mode) { // SPI_Write(spi, _channel, _data); while ((spi->SPI_SR & SPI_SR_TDRE) == 0) - ; + ; spi->SPI_TDR = d; // return SPI_Read(spi); while ((spi->SPI_SR & SPI_SR_RDRF) == 0) - ; + ; d = spi->SPI_RDR; // Reverse bit order if (bitOrder[ch] == LSBFIRST) @@ -137,3 +213,4 @@ static void SPI_0_Init(void) { SPIClass SPI(SPI_INTERFACE, SPI_INTERFACE_ID, SPI_0_Init); #endif + diff --git a/hardware/arduino/sam/libraries/SPI/SPI.h b/hardware/arduino/sam/libraries/SPI/SPI.h index 735bd4bf9..49cfe3771 100644 --- a/hardware/arduino/sam/libraries/SPI/SPI.h +++ b/hardware/arduino/sam/libraries/SPI/SPI.h @@ -1,5 +1,6 @@ /* * Copyright (c) 2010 by Cristian Maglie + * Copyright (c) 2014 by Paul Stoffregen (Transaction API) * SPI Master library for arduino. * * This file is free software; you can redistribute it and/or modify @@ -24,6 +25,301 @@ enum SPITransferMode { SPI_LAST }; +class SPISettings { +public: + SPISettings(uint32_t clock, BitOrder bitOrder, uint8_t dataMode) { + if (__builtin_constant_p(clock)) { + init_AlwaysInline(clock, bitOrder, dataMode); + } else { + init_MightInline(clock, bitOrder, dataMode); + } + } + SPISettings() { + init_AlwaysInline(4000000, MSBFIRST, SPI_MODE0); + } +private: + void init_MightInline(uint32_t clock, BitOrder bitOrder, uint8_t dataMode) { + init_AlwaysInline(clock, bitOrder, dataMode); + } + void init_AlwaysInline(uint32_t clock, BitOrder bitOrder, uint8_t dataMode) + __attribute__((__always_inline__)) { + uint8_t div; + border = bitOrder; + if (__builtin_constant_p(clock)) { + if (clock >= F_CPU / 2) div = 2; + else if (clock >= F_CPU / 3) div = 3; + else if (clock >= F_CPU / 4) div = 4; + else if (clock >= F_CPU / 5) div = 5; + else if (clock >= F_CPU / 6) div = 6; + else if (clock >= F_CPU / 7) div = 7; + else if (clock >= F_CPU / 8) div = 8; + else if (clock >= F_CPU / 9) div = 9; + else if (clock >= F_CPU / 10) div = 10; + else if (clock >= F_CPU / 11) div = 11; + else if (clock >= F_CPU / 12) div = 12; + else if (clock >= F_CPU / 13) div = 13; + else if (clock >= F_CPU / 14) div = 14; + else if (clock >= F_CPU / 15) div = 15; + else if (clock >= F_CPU / 16) div = 16; + else if (clock >= F_CPU / 17) div = 17; + else if (clock >= F_CPU / 18) div = 18; + else if (clock >= F_CPU / 19) div = 19; + else if (clock >= F_CPU / 20) div = 20; + else if (clock >= F_CPU / 21) div = 21; + else if (clock >= F_CPU / 22) div = 22; + else if (clock >= F_CPU / 23) div = 23; + else if (clock >= F_CPU / 24) div = 24; + else if (clock >= F_CPU / 25) div = 25; + else if (clock >= F_CPU / 26) div = 26; + else if (clock >= F_CPU / 27) div = 27; + else if (clock >= F_CPU / 28) div = 28; + else if (clock >= F_CPU / 29) div = 29; + else if (clock >= F_CPU / 30) div = 30; + else if (clock >= F_CPU / 31) div = 31; + else if (clock >= F_CPU / 32) div = 32; + else if (clock >= F_CPU / 33) div = 33; + else if (clock >= F_CPU / 34) div = 34; + else if (clock >= F_CPU / 35) div = 35; + else if (clock >= F_CPU / 36) div = 36; + else if (clock >= F_CPU / 37) div = 37; + else if (clock >= F_CPU / 38) div = 38; + else if (clock >= F_CPU / 39) div = 39; + else if (clock >= F_CPU / 40) div = 40; + else if (clock >= F_CPU / 41) div = 41; + else if (clock >= F_CPU / 42) div = 42; + else if (clock >= F_CPU / 43) div = 43; + else if (clock >= F_CPU / 44) div = 44; + else if (clock >= F_CPU / 45) div = 45; + else if (clock >= F_CPU / 46) div = 46; + else if (clock >= F_CPU / 47) div = 47; + else if (clock >= F_CPU / 48) div = 48; + else if (clock >= F_CPU / 49) div = 49; + else if (clock >= F_CPU / 50) div = 50; + else if (clock >= F_CPU / 51) div = 51; + else if (clock >= F_CPU / 52) div = 52; + else if (clock >= F_CPU / 53) div = 53; + else if (clock >= F_CPU / 54) div = 54; + else if (clock >= F_CPU / 55) div = 55; + else if (clock >= F_CPU / 56) div = 56; + else if (clock >= F_CPU / 57) div = 57; + else if (clock >= F_CPU / 58) div = 58; + else if (clock >= F_CPU / 59) div = 59; + else if (clock >= F_CPU / 60) div = 60; + else if (clock >= F_CPU / 61) div = 61; + else if (clock >= F_CPU / 62) div = 62; + else if (clock >= F_CPU / 63) div = 63; + else if (clock >= F_CPU / 64) div = 64; + else if (clock >= F_CPU / 65) div = 65; + else if (clock >= F_CPU / 66) div = 66; + else if (clock >= F_CPU / 67) div = 67; + else if (clock >= F_CPU / 68) div = 68; + else if (clock >= F_CPU / 69) div = 69; + else if (clock >= F_CPU / 70) div = 70; + else if (clock >= F_CPU / 71) div = 71; + else if (clock >= F_CPU / 72) div = 72; + else if (clock >= F_CPU / 73) div = 73; + else if (clock >= F_CPU / 74) div = 74; + else if (clock >= F_CPU / 75) div = 75; + else if (clock >= F_CPU / 76) div = 76; + else if (clock >= F_CPU / 77) div = 77; + else if (clock >= F_CPU / 78) div = 78; + else if (clock >= F_CPU / 79) div = 79; + else if (clock >= F_CPU / 80) div = 80; + else if (clock >= F_CPU / 81) div = 81; + else if (clock >= F_CPU / 82) div = 82; + else if (clock >= F_CPU / 83) div = 83; + else if (clock >= F_CPU / 84) div = 84; + else if (clock >= F_CPU / 85) div = 85; + else if (clock >= F_CPU / 86) div = 86; + else if (clock >= F_CPU / 87) div = 87; + else if (clock >= F_CPU / 88) div = 88; + else if (clock >= F_CPU / 89) div = 89; + else if (clock >= F_CPU / 90) div = 90; + else if (clock >= F_CPU / 91) div = 91; + else if (clock >= F_CPU / 92) div = 92; + else if (clock >= F_CPU / 93) div = 93; + else if (clock >= F_CPU / 94) div = 94; + else if (clock >= F_CPU / 95) div = 95; + else if (clock >= F_CPU / 96) div = 96; + else if (clock >= F_CPU / 97) div = 97; + else if (clock >= F_CPU / 98) div = 98; + else if (clock >= F_CPU / 99) div = 99; + else if (clock >= F_CPU / 100) div = 100; + else if (clock >= F_CPU / 101) div = 101; + else if (clock >= F_CPU / 102) div = 102; + else if (clock >= F_CPU / 103) div = 103; + else if (clock >= F_CPU / 104) div = 104; + else if (clock >= F_CPU / 105) div = 105; + else if (clock >= F_CPU / 106) div = 106; + else if (clock >= F_CPU / 107) div = 107; + else if (clock >= F_CPU / 108) div = 108; + else if (clock >= F_CPU / 109) div = 109; + else if (clock >= F_CPU / 110) div = 110; + else if (clock >= F_CPU / 111) div = 111; + else if (clock >= F_CPU / 112) div = 112; + else if (clock >= F_CPU / 113) div = 113; + else if (clock >= F_CPU / 114) div = 114; + else if (clock >= F_CPU / 115) div = 115; + else if (clock >= F_CPU / 116) div = 116; + else if (clock >= F_CPU / 117) div = 117; + else if (clock >= F_CPU / 118) div = 118; + else if (clock >= F_CPU / 119) div = 119; + else if (clock >= F_CPU / 120) div = 120; + else if (clock >= F_CPU / 121) div = 121; + else if (clock >= F_CPU / 122) div = 122; + else if (clock >= F_CPU / 123) div = 123; + else if (clock >= F_CPU / 124) div = 124; + else if (clock >= F_CPU / 125) div = 125; + else if (clock >= F_CPU / 126) div = 126; + else if (clock >= F_CPU / 127) div = 127; + else if (clock >= F_CPU / 128) div = 128; + else if (clock >= F_CPU / 129) div = 129; + else if (clock >= F_CPU / 130) div = 130; + else if (clock >= F_CPU / 131) div = 131; + else if (clock >= F_CPU / 132) div = 132; + else if (clock >= F_CPU / 133) div = 133; + else if (clock >= F_CPU / 134) div = 134; + else if (clock >= F_CPU / 135) div = 135; + else if (clock >= F_CPU / 136) div = 136; + else if (clock >= F_CPU / 137) div = 137; + else if (clock >= F_CPU / 138) div = 138; + else if (clock >= F_CPU / 139) div = 139; + else if (clock >= F_CPU / 140) div = 140; + else if (clock >= F_CPU / 141) div = 141; + else if (clock >= F_CPU / 142) div = 142; + else if (clock >= F_CPU / 143) div = 143; + else if (clock >= F_CPU / 144) div = 144; + else if (clock >= F_CPU / 145) div = 145; + else if (clock >= F_CPU / 146) div = 146; + else if (clock >= F_CPU / 147) div = 147; + else if (clock >= F_CPU / 148) div = 148; + else if (clock >= F_CPU / 149) div = 149; + else if (clock >= F_CPU / 150) div = 150; + else if (clock >= F_CPU / 151) div = 151; + else if (clock >= F_CPU / 152) div = 152; + else if (clock >= F_CPU / 153) div = 153; + else if (clock >= F_CPU / 154) div = 154; + else if (clock >= F_CPU / 155) div = 155; + else if (clock >= F_CPU / 156) div = 156; + else if (clock >= F_CPU / 157) div = 157; + else if (clock >= F_CPU / 158) div = 158; + else if (clock >= F_CPU / 159) div = 159; + else if (clock >= F_CPU / 160) div = 160; + else if (clock >= F_CPU / 161) div = 161; + else if (clock >= F_CPU / 162) div = 162; + else if (clock >= F_CPU / 163) div = 163; + else if (clock >= F_CPU / 164) div = 164; + else if (clock >= F_CPU / 165) div = 165; + else if (clock >= F_CPU / 166) div = 166; + else if (clock >= F_CPU / 167) div = 167; + else if (clock >= F_CPU / 168) div = 168; + else if (clock >= F_CPU / 169) div = 169; + else if (clock >= F_CPU / 170) div = 170; + else if (clock >= F_CPU / 171) div = 171; + else if (clock >= F_CPU / 172) div = 172; + else if (clock >= F_CPU / 173) div = 173; + else if (clock >= F_CPU / 174) div = 174; + else if (clock >= F_CPU / 175) div = 175; + else if (clock >= F_CPU / 176) div = 176; + else if (clock >= F_CPU / 177) div = 177; + else if (clock >= F_CPU / 178) div = 178; + else if (clock >= F_CPU / 179) div = 179; + else if (clock >= F_CPU / 180) div = 180; + else if (clock >= F_CPU / 181) div = 181; + else if (clock >= F_CPU / 182) div = 182; + else if (clock >= F_CPU / 183) div = 183; + else if (clock >= F_CPU / 184) div = 184; + else if (clock >= F_CPU / 185) div = 185; + else if (clock >= F_CPU / 186) div = 186; + else if (clock >= F_CPU / 187) div = 187; + else if (clock >= F_CPU / 188) div = 188; + else if (clock >= F_CPU / 189) div = 189; + else if (clock >= F_CPU / 190) div = 190; + else if (clock >= F_CPU / 191) div = 191; + else if (clock >= F_CPU / 192) div = 192; + else if (clock >= F_CPU / 193) div = 193; + else if (clock >= F_CPU / 194) div = 194; + else if (clock >= F_CPU / 195) div = 195; + else if (clock >= F_CPU / 196) div = 196; + else if (clock >= F_CPU / 197) div = 197; + else if (clock >= F_CPU / 198) div = 198; + else if (clock >= F_CPU / 199) div = 199; + else if (clock >= F_CPU / 200) div = 200; + else if (clock >= F_CPU / 201) div = 201; + else if (clock >= F_CPU / 202) div = 202; + else if (clock >= F_CPU / 203) div = 203; + else if (clock >= F_CPU / 204) div = 204; + else if (clock >= F_CPU / 205) div = 205; + else if (clock >= F_CPU / 206) div = 206; + else if (clock >= F_CPU / 207) div = 207; + else if (clock >= F_CPU / 208) div = 208; + else if (clock >= F_CPU / 209) div = 209; + else if (clock >= F_CPU / 210) div = 210; + else if (clock >= F_CPU / 211) div = 211; + else if (clock >= F_CPU / 212) div = 212; + else if (clock >= F_CPU / 213) div = 213; + else if (clock >= F_CPU / 214) div = 214; + else if (clock >= F_CPU / 215) div = 215; + else if (clock >= F_CPU / 216) div = 216; + else if (clock >= F_CPU / 217) div = 217; + else if (clock >= F_CPU / 218) div = 218; + else if (clock >= F_CPU / 219) div = 219; + else if (clock >= F_CPU / 220) div = 220; + else if (clock >= F_CPU / 221) div = 221; + else if (clock >= F_CPU / 222) div = 222; + else if (clock >= F_CPU / 223) div = 223; + else if (clock >= F_CPU / 224) div = 224; + else if (clock >= F_CPU / 225) div = 225; + else if (clock >= F_CPU / 226) div = 226; + else if (clock >= F_CPU / 227) div = 227; + else if (clock >= F_CPU / 228) div = 228; + else if (clock >= F_CPU / 229) div = 229; + else if (clock >= F_CPU / 230) div = 230; + else if (clock >= F_CPU / 231) div = 231; + else if (clock >= F_CPU / 232) div = 232; + else if (clock >= F_CPU / 233) div = 233; + else if (clock >= F_CPU / 234) div = 234; + else if (clock >= F_CPU / 235) div = 235; + else if (clock >= F_CPU / 236) div = 236; + else if (clock >= F_CPU / 237) div = 237; + else if (clock >= F_CPU / 238) div = 238; + else if (clock >= F_CPU / 239) div = 239; + else if (clock >= F_CPU / 240) div = 240; + else if (clock >= F_CPU / 241) div = 241; + else if (clock >= F_CPU / 242) div = 242; + else if (clock >= F_CPU / 243) div = 243; + else if (clock >= F_CPU / 244) div = 244; + else if (clock >= F_CPU / 245) div = 245; + else if (clock >= F_CPU / 246) div = 246; + else if (clock >= F_CPU / 247) div = 247; + else if (clock >= F_CPU / 248) div = 248; + else if (clock >= F_CPU / 249) div = 249; + else if (clock >= F_CPU / 250) div = 250; + else if (clock >= F_CPU / 251) div = 251; + else if (clock >= F_CPU / 252) div = 252; + else if (clock >= F_CPU / 253) div = 253; + else if (clock >= F_CPU / 254) div = 254; + else /* clock >= F_CPU / 255 */ div = 255; + /* + #! /usr/bin/perl + for ($i=2; $i<256; $i++) { + printf "\t\t\telse if (clock >= F_CPU / %3d) div = %3d;\n", $i, $i; + } + */ + } else { + for (div=2; div<255; div++) { + if (clock >= F_CPU / div) break; + } + } + config = (dataMode & 3) | SPI_CSR_CSAAT | SPI_CSR_SCBR(div) | SPI_CSR_DLYBCT(1); + } + uint32_t config; + BitOrder border; + friend class SPIClass; +}; + + + class SPIClass { public: SPIClass(Spi *_spi, uint32_t _id, void(*_initCb)(void)); @@ -31,8 +327,15 @@ class SPIClass { byte transfer(uint8_t _data, SPITransferMode _mode = SPI_LAST) { return transfer(BOARD_SPI_DEFAULT_SS, _data, _mode); } byte transfer(byte _channel, uint8_t _data, SPITransferMode _mode = SPI_LAST); - // SPI Configuration methods + // Transaction Functions + void usingInterrupt(uint8_t interruptNumber); + void beginTransaction(uint8_t pin, SPISettings settings); + void beginTransaction(SPISettings settings) { + beginTransaction(BOARD_SPI_DEFAULT_SS, settings); + } + void endTransaction(void); + // SPI Configuration methods void attachInterrupt(void); void detachInterrupt(void); @@ -63,10 +366,23 @@ class SPIClass { uint32_t mode[SPI_CHANNELS_NUM]; void (*initCb)(void); bool initialized; + uint8_t interruptMode; // 0=none, 1=mask, 2=global + uint8_t interruptMask; // bits 0:3=pin change + uint8_t interruptSave; // temp storage, to restore state }; #if SPI_INTERFACES_COUNT > 0 extern SPIClass SPI; #endif +// For compatibility with sketches designed for AVR @ 16 MHz +// New programs should use SPI.beginTransaction to set the SPI clock +#define SPI_CLOCK_DIV2 11 +#define SPI_CLOCK_DIV4 21 +#define SPI_CLOCK_DIV8 42 +#define SPI_CLOCK_DIV16 84 +#define SPI_CLOCK_DIV32 168 +#define SPI_CLOCK_DIV64 255 +#define SPI_CLOCK_DIV128 255 + #endif From 53924e9d58456ebf77cf3e7fd5529b29886b0bd1 Mon Sep 17 00:00:00 2001 From: PaulStoffregen Date: Fri, 1 Aug 2014 06:03:38 -0700 Subject: [PATCH 3/8] Move Ethernet socket level stuff to utility/socket.cpp --- libraries/Ethernet/src/EthernetClient.cpp | 6 +++--- libraries/Ethernet/src/EthernetUdp.cpp | 4 ++-- libraries/Ethernet/src/utility/socket.cpp | 12 ++++++++++++ libraries/Ethernet/src/utility/socket.h | 2 ++ 4 files changed, 19 insertions(+), 5 deletions(-) diff --git a/libraries/Ethernet/src/EthernetClient.cpp b/libraries/Ethernet/src/EthernetClient.cpp index 44a21dcc8..7a36a3288 100644 --- a/libraries/Ethernet/src/EthernetClient.cpp +++ b/libraries/Ethernet/src/EthernetClient.cpp @@ -40,7 +40,7 @@ int EthernetClient::connect(IPAddress ip, uint16_t port) { return 0; for (int i = 0; i < MAX_SOCK_NUM; i++) { - uint8_t s = W5100.readSnSR(i); + uint8_t s = socketStatus(i); if (s == SnSR::CLOSED || s == SnSR::FIN_WAIT || s == SnSR::CLOSE_WAIT) { _sock = i; break; @@ -88,7 +88,7 @@ size_t EthernetClient::write(const uint8_t *buf, size_t size) { int EthernetClient::available() { if (_sock != MAX_SOCK_NUM) - return W5100.getRXReceivedSize(_sock); + return recvAvailable(_sock); return 0; } @@ -153,7 +153,7 @@ uint8_t EthernetClient::connected() { uint8_t EthernetClient::status() { if (_sock == MAX_SOCK_NUM) return SnSR::CLOSED; - return W5100.readSnSR(_sock); + return socketStatus(_sock); } // the next function allows us to use the client returned by diff --git a/libraries/Ethernet/src/EthernetUdp.cpp b/libraries/Ethernet/src/EthernetUdp.cpp index b0df74ba9..b5dcb78cc 100644 --- a/libraries/Ethernet/src/EthernetUdp.cpp +++ b/libraries/Ethernet/src/EthernetUdp.cpp @@ -41,7 +41,7 @@ uint8_t EthernetUDP::begin(uint16_t port) { return 0; for (int i = 0; i < MAX_SOCK_NUM; i++) { - uint8_t s = W5100.readSnSR(i); + uint8_t s = socketStatus(i); if (s == SnSR::CLOSED || s == SnSR::FIN_WAIT) { _sock = i; break; @@ -120,7 +120,7 @@ int EthernetUDP::parsePacket() // discard any remaining bytes in the last packet flush(); - if (W5100.getRXReceivedSize(_sock) > 0) + if (recvAvailable(_sock) > 0) { //HACK - hand-parse the UDP packet using TCP recv method uint8_t tmpBuf[8]; diff --git a/libraries/Ethernet/src/utility/socket.cpp b/libraries/Ethernet/src/utility/socket.cpp index b6d76f1a8..ff2ec3d78 100644 --- a/libraries/Ethernet/src/utility/socket.cpp +++ b/libraries/Ethernet/src/utility/socket.cpp @@ -30,6 +30,12 @@ uint8_t socket(SOCKET s, uint8_t protocol, uint16_t port, uint8_t flag) } +uint8_t socketStatus(SOCKET s) +{ + return W5100.readSnSR(s); +} + + /** * @brief This function close the socket and parameter is "s" which represent the socket number */ @@ -176,6 +182,12 @@ int16_t recv(SOCKET s, uint8_t *buf, int16_t len) } +int16_t recvAvailable(SOCKET s) +{ + return W5100.getRXReceivedSize(s); +} + + /** * @brief Returns the first byte in the receive queue (no checking) * diff --git a/libraries/Ethernet/src/utility/socket.h b/libraries/Ethernet/src/utility/socket.h index 682e84709..37ba85424 100644 --- a/libraries/Ethernet/src/utility/socket.h +++ b/libraries/Ethernet/src/utility/socket.h @@ -4,12 +4,14 @@ #include "utility/w5100.h" extern uint8_t socket(SOCKET s, uint8_t protocol, uint16_t port, uint8_t flag); // Opens a socket(TCP or UDP or IP_RAW mode) +extern uint8_t socketStatus(SOCKET s); extern void close(SOCKET s); // Close socket extern uint8_t connect(SOCKET s, uint8_t * addr, uint16_t port); // Establish TCP connection (Active connection) extern void disconnect(SOCKET s); // disconnect the connection extern uint8_t listen(SOCKET s); // Establish TCP connection (Passive connection) extern uint16_t send(SOCKET s, const uint8_t * buf, uint16_t len); // Send data (TCP) extern int16_t recv(SOCKET s, uint8_t * buf, int16_t len); // Receive data (TCP) +extern int16_t recvAvailable(SOCKET s); extern uint16_t peek(SOCKET s, uint8_t *buf); extern uint16_t sendto(SOCKET s, const uint8_t * buf, uint16_t len, uint8_t * addr, uint16_t port); // Send data (UDP/IP RAW) extern uint16_t recvfrom(SOCKET s, uint8_t * buf, uint16_t len, uint8_t * addr, uint16_t *port); // Receive data (UDP/IP RAW) From 8aaca2fbb662b293f7089f1505e4a8e922e49b0d Mon Sep 17 00:00:00 2001 From: PaulStoffregen Date: Fri, 1 Aug 2014 06:34:34 -0700 Subject: [PATCH 4/8] Use SPI transactions in Ethernet library --- libraries/Ethernet/src/Ethernet.cpp | 14 +++++ libraries/Ethernet/src/utility/socket.cpp | 63 +++++++++++++++++++++-- libraries/Ethernet/src/utility/w5100.cpp | 2 - libraries/Ethernet/src/utility/w5100.h | 8 +++ 4 files changed, 80 insertions(+), 7 deletions(-) diff --git a/libraries/Ethernet/src/Ethernet.cpp b/libraries/Ethernet/src/Ethernet.cpp index 0f9effb1a..3eea69a2a 100644 --- a/libraries/Ethernet/src/Ethernet.cpp +++ b/libraries/Ethernet/src/Ethernet.cpp @@ -16,8 +16,10 @@ int EthernetClass::begin(uint8_t *mac_address) // Initialise the basic info W5100.init(); + SPI.beginTransaction(SPI_ETHERNET_SETTINGS); W5100.setMACAddress(mac_address); W5100.setIPAddress(IPAddress(0,0,0,0).raw_address()); + SPI.endTransaction(); // Now try to get our config info from a DHCP server int ret = _dhcp->beginWithDHCP(mac_address); @@ -25,9 +27,11 @@ int EthernetClass::begin(uint8_t *mac_address) { // We've successfully found a DHCP server and got our configuration info, so set things // accordingly + SPI.beginTransaction(SPI_ETHERNET_SETTINGS); W5100.setIPAddress(_dhcp->getLocalIp().raw_address()); W5100.setGatewayIp(_dhcp->getGatewayIp().raw_address()); W5100.setSubnetMask(_dhcp->getSubnetMask().raw_address()); + SPI.endTransaction(); _dnsServerAddress = _dhcp->getDnsServerIp(); } @@ -61,10 +65,12 @@ void EthernetClass::begin(uint8_t *mac_address, IPAddress local_ip, IPAddress dn void EthernetClass::begin(uint8_t *mac, IPAddress local_ip, IPAddress dns_server, IPAddress gateway, IPAddress subnet) { W5100.init(); + SPI.beginTransaction(SPI_ETHERNET_SETTINGS); W5100.setMACAddress(mac); W5100.setIPAddress(local_ip.raw_address()); W5100.setGatewayIp(gateway.raw_address()); W5100.setSubnetMask(subnet.raw_address()); + SPI.endTransaction(); _dnsServerAddress = dns_server; } @@ -80,9 +86,11 @@ int EthernetClass::maintain(){ case DHCP_CHECK_RENEW_OK: case DHCP_CHECK_REBIND_OK: //we might have got a new IP. + SPI.beginTransaction(SPI_ETHERNET_SETTINGS); W5100.setIPAddress(_dhcp->getLocalIp().raw_address()); W5100.setGatewayIp(_dhcp->getGatewayIp().raw_address()); W5100.setSubnetMask(_dhcp->getSubnetMask().raw_address()); + SPI.endTransaction(); _dnsServerAddress = _dhcp->getDnsServerIp(); break; default: @@ -96,21 +104,27 @@ int EthernetClass::maintain(){ IPAddress EthernetClass::localIP() { IPAddress ret; + SPI.beginTransaction(SPI_ETHERNET_SETTINGS); W5100.getIPAddress(ret.raw_address()); + SPI.endTransaction(); return ret; } IPAddress EthernetClass::subnetMask() { IPAddress ret; + SPI.beginTransaction(SPI_ETHERNET_SETTINGS); W5100.getSubnetMask(ret.raw_address()); + SPI.endTransaction(); return ret; } IPAddress EthernetClass::gatewayIP() { IPAddress ret; + SPI.beginTransaction(SPI_ETHERNET_SETTINGS); W5100.getGatewayIp(ret.raw_address()); + SPI.endTransaction(); return ret; } diff --git a/libraries/Ethernet/src/utility/socket.cpp b/libraries/Ethernet/src/utility/socket.cpp index ff2ec3d78..4ed4317ea 100644 --- a/libraries/Ethernet/src/utility/socket.cpp +++ b/libraries/Ethernet/src/utility/socket.cpp @@ -12,6 +12,7 @@ uint8_t socket(SOCKET s, uint8_t protocol, uint16_t port, uint8_t flag) if ((protocol == SnMR::TCP) || (protocol == SnMR::UDP) || (protocol == SnMR::IPRAW) || (protocol == SnMR::MACRAW) || (protocol == SnMR::PPPOE)) { close(s); + SPI.beginTransaction(SPI_ETHERNET_SETTINGS); W5100.writeSnMR(s, protocol | flag); if (port != 0) { W5100.writeSnPORT(s, port); @@ -22,7 +23,7 @@ uint8_t socket(SOCKET s, uint8_t protocol, uint16_t port, uint8_t flag) } W5100.execCmdSn(s, Sock_OPEN); - + SPI.endTransaction(); return 1; } @@ -32,7 +33,10 @@ uint8_t socket(SOCKET s, uint8_t protocol, uint16_t port, uint8_t flag) uint8_t socketStatus(SOCKET s) { - return W5100.readSnSR(s); + SPI.beginTransaction(SPI_ETHERNET_SETTINGS); + uint8_t status = W5100.readSnSR(s); + SPI.endTransaction(); + return status; } @@ -41,8 +45,10 @@ uint8_t socketStatus(SOCKET s) */ void close(SOCKET s) { + SPI.beginTransaction(SPI_ETHERNET_SETTINGS); W5100.execCmdSn(s, Sock_CLOSE); W5100.writeSnIR(s, 0xFF); + SPI.endTransaction(); } @@ -52,9 +58,13 @@ void close(SOCKET s) */ uint8_t listen(SOCKET s) { - if (W5100.readSnSR(s) != SnSR::INIT) + SPI.beginTransaction(SPI_ETHERNET_SETTINGS); + if (W5100.readSnSR(s) != SnSR::INIT) { + SPI.endTransaction(); return 0; + } W5100.execCmdSn(s, Sock_LISTEN); + SPI.endTransaction(); return 1; } @@ -76,9 +86,11 @@ uint8_t connect(SOCKET s, uint8_t * addr, uint16_t port) return 0; // set destination IP + SPI.beginTransaction(SPI_ETHERNET_SETTINGS); W5100.writeSnDIPR(s, addr); W5100.writeSnDPORT(s, port); W5100.execCmdSn(s, Sock_CONNECT); + SPI.endTransaction(); return 1; } @@ -91,7 +103,9 @@ uint8_t connect(SOCKET s, uint8_t * addr, uint16_t port) */ void disconnect(SOCKET s) { + SPI.beginTransaction(SPI_ETHERNET_SETTINGS); W5100.execCmdSn(s, Sock_DISCON); + SPI.endTransaction(); } @@ -113,17 +127,21 @@ uint16_t send(SOCKET s, const uint8_t * buf, uint16_t len) // if freebuf is available, start. do { + SPI.beginTransaction(SPI_ETHERNET_SETTINGS); freesize = W5100.getTXFreeSize(s); status = W5100.readSnSR(s); + SPI.endTransaction(); if ((status != SnSR::ESTABLISHED) && (status != SnSR::CLOSE_WAIT)) { ret = 0; break; } + yield(); } while (freesize < ret); // copy data + SPI.beginTransaction(SPI_ETHERNET_SETTINGS); W5100.send_data_processing(s, (uint8_t *)buf, ret); W5100.execCmdSn(s, Sock_SEND); @@ -133,12 +151,17 @@ uint16_t send(SOCKET s, const uint8_t * buf, uint16_t len) /* m2008.01 [bj] : reduce code */ if ( W5100.readSnSR(s) == SnSR::CLOSED ) { + SPI.endTransaction(); close(s); return 0; } + SPI.endTransaction(); + yield(); + SPI.beginTransaction(SPI_ETHERNET_SETTINGS); } /* +2008.01 bj */ W5100.writeSnIR(s, SnIR::SEND_OK); + SPI.endTransaction(); return ret; } @@ -152,6 +175,7 @@ uint16_t send(SOCKET s, const uint8_t * buf, uint16_t len) int16_t recv(SOCKET s, uint8_t *buf, int16_t len) { // Check how much data is available + SPI.beginTransaction(SPI_ETHERNET_SETTINGS); int16_t ret = W5100.getRXReceivedSize(s); if ( ret == 0 ) { @@ -178,13 +202,17 @@ int16_t recv(SOCKET s, uint8_t *buf, int16_t len) W5100.recv_data_processing(s, buf, ret); W5100.execCmdSn(s, Sock_RECV); } + SPI.endTransaction(); return ret; } int16_t recvAvailable(SOCKET s) { - return W5100.getRXReceivedSize(s); + SPI.beginTransaction(SPI_ETHERNET_SETTINGS); + int16_t ret = W5100.getRXReceivedSize(s); + SPI.endTransaction(); + return ret; } @@ -195,8 +223,9 @@ int16_t recvAvailable(SOCKET s) */ uint16_t peek(SOCKET s, uint8_t *buf) { + SPI.beginTransaction(SPI_ETHERNET_SETTINGS); W5100.recv_data_processing(s, buf, 1, 1); - + SPI.endTransaction(); return 1; } @@ -225,6 +254,7 @@ uint16_t sendto(SOCKET s, const uint8_t *buf, uint16_t len, uint8_t *addr, uint1 } else { + SPI.beginTransaction(SPI_ETHERNET_SETTINGS); W5100.writeSnDIPR(s, addr); W5100.writeSnDPORT(s, port); @@ -239,12 +269,17 @@ uint16_t sendto(SOCKET s, const uint8_t *buf, uint16_t len, uint8_t *addr, uint1 { /* +2008.01 [bj]: clear interrupt */ W5100.writeSnIR(s, (SnIR::SEND_OK | SnIR::TIMEOUT)); /* clear SEND_OK & TIMEOUT */ + SPI.endTransaction(); return 0; } + SPI.endTransaction(); + yield(); + SPI.beginTransaction(SPI_ETHERNET_SETTINGS); } /* +2008.01 bj */ W5100.writeSnIR(s, SnIR::SEND_OK); + SPI.endTransaction(); } return ret; } @@ -264,6 +299,7 @@ uint16_t recvfrom(SOCKET s, uint8_t *buf, uint16_t len, uint8_t *addr, uint16_t if ( len > 0 ) { + SPI.beginTransaction(SPI_ETHERNET_SETTINGS); ptr = W5100.readSnRX_RD(s); switch (W5100.readSnMR(s) & 0x07) { @@ -318,6 +354,7 @@ uint16_t recvfrom(SOCKET s, uint8_t *buf, uint16_t len, uint8_t *addr, uint16_t break; } W5100.execCmdSn(s, Sock_RECV); + SPI.endTransaction(); } return data_len; } @@ -341,6 +378,7 @@ uint16_t igmpsend(SOCKET s, const uint8_t * buf, uint16_t len) if (ret == 0) return 0; + SPI.beginTransaction(SPI_ETHERNET_SETTINGS); W5100.send_data_processing(s, (uint8_t *)buf, ret); W5100.execCmdSn(s, Sock_SEND); @@ -350,18 +388,24 @@ uint16_t igmpsend(SOCKET s, const uint8_t * buf, uint16_t len) { /* in case of igmp, if send fails, then socket closed */ /* if you want change, remove this code. */ + SPI.endTransaction(); close(s); return 0; } + SPI.endTransaction(); + yield(); + SPI.beginTransaction(SPI_ETHERNET_SETTINGS); } W5100.writeSnIR(s, SnIR::SEND_OK); + SPI.endTransaction(); return ret; } uint16_t bufferData(SOCKET s, uint16_t offset, const uint8_t* buf, uint16_t len) { uint16_t ret =0; + SPI.beginTransaction(SPI_ETHERNET_SETTINGS); if (len > W5100.getTXFreeSize(s)) { ret = W5100.getTXFreeSize(s); // check size not to exceed MAX size. @@ -371,6 +415,7 @@ uint16_t bufferData(SOCKET s, uint16_t offset, const uint8_t* buf, uint16_t len) ret = len; } W5100.send_data_processing_offset(s, offset, buf, ret); + SPI.endTransaction(); return ret; } @@ -386,14 +431,17 @@ int startUDP(SOCKET s, uint8_t* addr, uint16_t port) } else { + SPI.beginTransaction(SPI_ETHERNET_SETTINGS); W5100.writeSnDIPR(s, addr); W5100.writeSnDPORT(s, port); + SPI.endTransaction(); return 1; } } int sendUDP(SOCKET s) { + SPI.beginTransaction(SPI_ETHERNET_SETTINGS); W5100.execCmdSn(s, Sock_SEND); /* +2008.01 bj */ @@ -403,12 +451,17 @@ int sendUDP(SOCKET s) { /* +2008.01 [bj]: clear interrupt */ W5100.writeSnIR(s, (SnIR::SEND_OK|SnIR::TIMEOUT)); + SPI.endTransaction(); return 0; } + SPI.endTransaction(); + yield(); + SPI.beginTransaction(SPI_ETHERNET_SETTINGS); } /* +2008.01 bj */ W5100.writeSnIR(s, SnIR::SEND_OK); + SPI.endTransaction(); /* Sent ok */ return 1; diff --git a/libraries/Ethernet/src/utility/w5100.cpp b/libraries/Ethernet/src/utility/w5100.cpp index 7e8b6348a..a70107344 100644 --- a/libraries/Ethernet/src/utility/w5100.cpp +++ b/libraries/Ethernet/src/utility/w5100.cpp @@ -15,8 +15,6 @@ // W5100 controller instance W5100Class W5100; -#define SPI_CS 10 - #define TX_RX_MAX_BUF_SIZE 2048 #define TX_BUF 0x1100 #define RX_BUF (TX_BUF + TX_RX_MAX_BUF_SIZE) diff --git a/libraries/Ethernet/src/utility/w5100.h b/libraries/Ethernet/src/utility/w5100.h index 3b5a69336..ba72e2181 100644 --- a/libraries/Ethernet/src/utility/w5100.h +++ b/libraries/Ethernet/src/utility/w5100.h @@ -12,6 +12,14 @@ #include +#define SPI_CS 10 + +#if defined(ARDUINO_ARCH_AVR) +#define SPI_ETHERNET_SETTINGS SPISettings(4000000, MSBFIRST, SPI_MODE0) +#else +#define SPI_ETHERNET_SETTINGS SPI_CS,SPISettings(4000000, MSBFIRST, SPI_MODE0) +#endif + #define MAX_SOCK_NUM 4 typedef uint8_t SOCKET; From a0f5a2ee4ca50a6ea6a796c6ac6d2dfd659c35b0 Mon Sep 17 00:00:00 2001 From: PaulStoffregen Date: Fri, 1 Aug 2014 11:52:09 -0700 Subject: [PATCH 5/8] Use SPI transaction in Ethernet W5100 init --- libraries/Ethernet/src/utility/w5100.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libraries/Ethernet/src/utility/w5100.cpp b/libraries/Ethernet/src/utility/w5100.cpp index a70107344..9e72744c2 100644 --- a/libraries/Ethernet/src/utility/w5100.cpp +++ b/libraries/Ethernet/src/utility/w5100.cpp @@ -35,9 +35,11 @@ void W5100Class::init(void) SPI.setClockDivider(SPI_CS, 21); SPI.setDataMode(SPI_CS, SPI_MODE0); #endif + SPI.beginTransaction(SPI_ETHERNET_SETTINGS); writeMR(1< Date: Fri, 1 Aug 2014 12:19:51 -0700 Subject: [PATCH 6/8] Use SPI transactions and SPISettings in SD library --- libraries/SD/src/utility/Sd2Card.cpp | 41 +++++++++++++++------------- 1 file changed, 22 insertions(+), 19 deletions(-) diff --git a/libraries/SD/src/utility/Sd2Card.cpp b/libraries/SD/src/utility/Sd2Card.cpp index 830f65789..7e7cbf8ac 100644 --- a/libraries/SD/src/utility/Sd2Card.cpp +++ b/libraries/SD/src/utility/Sd2Card.cpp @@ -24,6 +24,7 @@ #ifndef SOFTWARE_SPI #ifdef USE_SPI_LIB #include +static SPISettings settings; #endif // functions for hardware SPI /** Send a byte to the card */ @@ -158,9 +159,15 @@ uint32_t Sd2Card::cardSize(void) { //------------------------------------------------------------------------------ void Sd2Card::chipSelectHigh(void) { digitalWrite(chipSelectPin_, HIGH); +#ifdef USE_SPI_LIB + SPI.endTransaction(); +#endif } //------------------------------------------------------------------------------ void Sd2Card::chipSelectLow(void) { +#ifdef USE_SPI_LIB + SPI.beginTransaction(settings); +#endif digitalWrite(chipSelectPin_, LOW); } //------------------------------------------------------------------------------ @@ -233,7 +240,7 @@ uint8_t Sd2Card::init(uint8_t sckRateID, uint8_t chipSelectPin) { // set pin modes pinMode(chipSelectPin_, OUTPUT); - chipSelectHigh(); + digitalWrite(chipSelectPin_, HIGH); #ifndef USE_SPI_LIB pinMode(SPI_MISO_PIN, INPUT); pinMode(SPI_MOSI_PIN, OUTPUT); @@ -251,16 +258,18 @@ uint8_t Sd2Card::init(uint8_t sckRateID, uint8_t chipSelectPin) { SPSR &= ~(1 << SPI2X); #else // USE_SPI_LIB SPI.begin(); -#ifdef SPI_CLOCK_DIV128 - SPI.setClockDivider(SPI_CLOCK_DIV128); -#else - SPI.setClockDivider(255); -#endif + settings = SPISettings(250000, MSBFIRST, SPI_MODE0); #endif // USE_SPI_LIB #endif // SOFTWARE_SPI // must supply min of 74 clock cycles with CS high. +#ifdef USE_SPI_LIB + SPI.beginTransaction(settings); +#endif for (uint8_t i = 0; i < 10; i++) spiSend(0XFF); +#ifdef USE_SPI_LIB + SPI.endTransaction(); +#endif chipSelectLow(); @@ -497,21 +506,15 @@ uint8_t Sd2Card::setSckRate(uint8_t sckRateID) { SPCR |= (sckRateID & 4 ? (1 << SPR1) : 0) | (sckRateID & 2 ? (1 << SPR0) : 0); #else // USE_SPI_LIB - int v; -#ifdef SPI_CLOCK_DIV128 switch (sckRateID) { - case 0: v=SPI_CLOCK_DIV2; break; - case 1: v=SPI_CLOCK_DIV4; break; - case 2: v=SPI_CLOCK_DIV8; break; - case 3: v=SPI_CLOCK_DIV16; break; - case 4: v=SPI_CLOCK_DIV32; break; - case 5: v=SPI_CLOCK_DIV64; break; - case 6: v=SPI_CLOCK_DIV128; break; + case 0: settings = SPISettings(25000000, MSBFIRST, SPI_MODE0); break; + case 1: settings = SPISettings(4000000, MSBFIRST, SPI_MODE0); break; + case 2: settings = SPISettings(2000000, MSBFIRST, SPI_MODE0); break; + case 3: settings = SPISettings(1000000, MSBFIRST, SPI_MODE0); break; + case 4: settings = SPISettings(500000, MSBFIRST, SPI_MODE0); break; + case 5: settings = SPISettings(250000, MSBFIRST, SPI_MODE0); break; + default: settings = SPISettings(125000, MSBFIRST, SPI_MODE0); } -#else // SPI_CLOCK_DIV128 - v = 2 << sckRateID; -#endif // SPI_CLOCK_DIV128 - SPI.setClockDivider(v); #endif // USE_SPI_LIB return true; } From ef06410d1659b6eafae9c935d906050b031c15cb Mon Sep 17 00:00:00 2001 From: PaulStoffregen Date: Fri, 1 Aug 2014 13:00:29 -0700 Subject: [PATCH 7/8] Add SPI_HAS_TRANSACTION symbol for Arduino Due --- hardware/arduino/sam/libraries/SPI/SPI.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/hardware/arduino/sam/libraries/SPI/SPI.h b/hardware/arduino/sam/libraries/SPI/SPI.h index 49cfe3771..b0101392e 100644 --- a/hardware/arduino/sam/libraries/SPI/SPI.h +++ b/hardware/arduino/sam/libraries/SPI/SPI.h @@ -15,6 +15,10 @@ #include "variant.h" #include +// SPI_HAS_TRANSACTION means SPI has beginTransaction(), endTransaction(), +// usingInterrupt(), and SPISetting(clock, bitOrder, dataMode) +#define SPI_HAS_TRANSACTION 1 + #define SPI_MODE0 0x02 #define SPI_MODE1 0x00 #define SPI_MODE2 0x03 From daa7e7dcc97e8d769c5acd93018a2e34552f0c48 Mon Sep 17 00:00:00 2001 From: PaulStoffregen Date: Fri, 1 Aug 2014 16:44:47 -0700 Subject: [PATCH 8/8] Fix interrupt masking on Arduino Due --- hardware/arduino/sam/libraries/SPI/SPI.cpp | 62 +++++++++++++--------- hardware/arduino/sam/libraries/SPI/SPI.h | 9 ++-- 2 files changed, 43 insertions(+), 28 deletions(-) diff --git a/hardware/arduino/sam/libraries/SPI/SPI.cpp b/hardware/arduino/sam/libraries/SPI/SPI.cpp index faa395f44..ee70e4272 100644 --- a/hardware/arduino/sam/libraries/SPI/SPI.cpp +++ b/hardware/arduino/sam/libraries/SPI/SPI.cpp @@ -47,8 +47,11 @@ void SPIClass::init() { if (initialized) return; interruptMode = 0; - interruptMask = 0; interruptSave = 0; + interruptMask[0] = 0; + interruptMask[1] = 0; + interruptMask[2] = 0; + interruptMask[3] = 0; initCb(); SPI_Configure(spi, id, SPI_MR_MSTR | SPI_MR_PS | SPI_MR_MODFDIS); SPI_Enable(spi); @@ -59,9 +62,11 @@ void SPIClass::init() { #define interruptsStatus() __interruptsStatus() static inline unsigned char __interruptsStatus(void) __attribute__((always_inline, unused)); static inline unsigned char __interruptsStatus(void) { - unsigned int primask; + unsigned int primask, faultmask; asm volatile ("mrs %0, primask" : "=r" (primask)); if (primask) return 0; + asm volatile ("mrs %0, faultmask" : "=r" (faultmask)); + if (faultmask) return 0; return 1; } #endif @@ -72,23 +77,27 @@ void SPIClass::usingInterrupt(uint8_t interruptNumber) irestore = interruptsStatus(); noInterrupts(); - if (interruptMode < 2) { + if (interruptMode < 16) { if (interruptNumber > NUM_DIGITAL_PINS) { - interruptMode = 2; + interruptMode = 16; } else { - uint8_t imask = interruptMask; Pio *pio = g_APinDescription[interruptNumber].pPort; + uint32_t mask = g_APinDescription[interruptNumber].ulPin; if (pio == PIOA) { - imask |= 1; + interruptMode |= 1; + interruptMask[0] |= mask; } else if (pio == PIOB) { - imask |= 2; + interruptMode |= 2; + interruptMask[1] |= mask; } else if (pio == PIOC) { - imask |= 4; + interruptMode |= 4; + interruptMask[2] |= mask; } else if (pio == PIOD) { - imask |= 8; + interruptMode |= 8; + interruptMask[3] |= mask; + } else { + interruptMode = 16; } - interruptMask = imask; - interruptMode = 1; } } if (irestore) interrupts(); @@ -96,13 +105,13 @@ void SPIClass::usingInterrupt(uint8_t interruptNumber) void SPIClass::beginTransaction(uint8_t pin, SPISettings settings) { - if (interruptMode > 0) { - if (interruptMode == 1) { - uint8_t imask = interruptMask; - if (imask & 1) NVIC_DisableIRQ(PIOA_IRQn); - if (imask & 2) NVIC_DisableIRQ(PIOB_IRQn); - if (imask & 4) NVIC_DisableIRQ(PIOC_IRQn); - if (imask & 8) NVIC_DisableIRQ(PIOD_IRQn); + uint8_t mode = interruptMode; + if (mode > 0) { + if (mode < 16) { + if (mode & 1) PIOA->PIO_IDR = interruptMask[0]; + if (mode & 2) PIOB->PIO_IDR = interruptMask[1]; + if (mode & 4) PIOC->PIO_IDR = interruptMask[2]; + if (mode & 8) PIOD->PIO_IDR = interruptMask[3]; } else { interruptSave = interruptsStatus(); noInterrupts(); @@ -111,17 +120,20 @@ void SPIClass::beginTransaction(uint8_t pin, SPISettings settings) uint32_t ch = BOARD_PIN_TO_SPI_CHANNEL(pin); bitOrder[ch] = settings.border; SPI_ConfigureNPCS(spi, ch, settings.config); + //setBitOrder(pin, settings.border); + //setDataMode(pin, settings.datamode); + //setClockDivider(pin, settings.clockdiv); } void SPIClass::endTransaction(void) { - if (interruptMode > 0) { - if (interruptMode == 1) { - uint8_t imask = interruptMask; - if (imask & 1) NVIC_EnableIRQ(PIOA_IRQn); - if (imask & 2) NVIC_EnableIRQ(PIOB_IRQn); - if (imask & 4) NVIC_EnableIRQ(PIOC_IRQn); - if (imask & 8) NVIC_EnableIRQ(PIOD_IRQn); + uint8_t mode = interruptMode; + if (mode > 0) { + if (mode < 16) { + if (mode & 1) PIOA->PIO_IER = interruptMask[0]; + if (mode & 2) PIOB->PIO_IER = interruptMask[1]; + if (mode & 4) PIOC->PIO_IER = interruptMask[2]; + if (mode & 8) PIOD->PIO_IER = interruptMask[3]; } else { if (interruptSave) interrupts(); } diff --git a/hardware/arduino/sam/libraries/SPI/SPI.h b/hardware/arduino/sam/libraries/SPI/SPI.h index b0101392e..efb7afe74 100644 --- a/hardware/arduino/sam/libraries/SPI/SPI.h +++ b/hardware/arduino/sam/libraries/SPI/SPI.h @@ -316,8 +316,11 @@ private: } } config = (dataMode & 3) | SPI_CSR_CSAAT | SPI_CSR_SCBR(div) | SPI_CSR_DLYBCT(1); + //clockdiv = div; + //datamode = dataMode; } uint32_t config; + //uint8_t clockdiv, datamode; BitOrder border; friend class SPIClass; }; @@ -370,9 +373,9 @@ class SPIClass { uint32_t mode[SPI_CHANNELS_NUM]; void (*initCb)(void); bool initialized; - uint8_t interruptMode; // 0=none, 1=mask, 2=global - uint8_t interruptMask; // bits 0:3=pin change - uint8_t interruptSave; // temp storage, to restore state + uint8_t interruptMode; // 0=none, 1-15=mask, 16=global + uint8_t interruptSave; // temp storage, to restore state + uint32_t interruptMask[4]; }; #if SPI_INTERFACES_COUNT > 0