From 2bb742afd2e8cf0a3708b3b50a94089b5b39a3a8 Mon Sep 17 00:00:00 2001 From: "erik.nyquist" Date: Thu, 12 May 2016 11:15:04 -0700 Subject: [PATCH 1/3] Add support for SPI1 device to SPIClass SPI1 can now be used (SPI1.begin()) to access the SPI device connected to the Arduino 101's on-board SPI flash device --- libraries/SPI/src/SPI.cpp | 39 ++++++++++--------- libraries/SPI/src/SPI.h | 59 +++++++++++++++++++++-------- libraries/SPI/src/SPI_registers.h | 11 +++--- variants/arduino_101/pins_arduino.h | 2 +- variants/arduino_101/variant.cpp | 1 + 5 files changed, 72 insertions(+), 40 deletions(-) mode change 100644 => 100755 libraries/SPI/src/SPI.cpp mode change 100644 => 100755 libraries/SPI/src/SPI.h mode change 100644 => 100755 libraries/SPI/src/SPI_registers.h diff --git a/libraries/SPI/src/SPI.cpp b/libraries/SPI/src/SPI.cpp old mode 100644 new mode 100755 index 9f24b834..e4ca4841 --- a/libraries/SPI/src/SPI.cpp +++ b/libraries/SPI/src/SPI.cpp @@ -18,30 +18,32 @@ */ #include "SPI.h" -SPIClass SPI; +SPIClass SPI(SPIDEV_1); +SPIClass SPI1(SPIDEV_0); void SPIClass::setClockDivider(uint8_t clockDiv) { /* disable controller */ - SPI1_M_REG_VAL(SPIEN) &= SPI_DISABLE; + SPI_M_REG_VAL(spi_addr, SPIEN) &= SPI_DISABLE; /* Set SPI Clock Divider */ - SPI1_M_REG_VAL(BAUDR) = clockDiv & SPI_CLOCK_MASK; + SPI_M_REG_VAL(spi_addr, BAUDR) = clockDiv & SPI_CLOCK_MASK; /* re-enable controller */ - SPI1_M_REG_VAL(SPIEN) |= SPI_ENABLE; + SPI_M_REG_VAL(spi_addr, SPIEN) |= SPI_ENABLE; } void SPIClass::setDataMode(uint8_t dataMode) { /* disable controller */ - SPI1_M_REG_VAL(SPIEN) &= SPI_DISABLE; + SPI_M_REG_VAL(spi_addr, SPIEN) &= SPI_DISABLE; /* Set frame size, bus mode and transfer mode */ - SPI1_M_REG_VAL(CTRL0) = (SPI1_M_REG_VAL(CTRL0) & ~(SPI_MODE_MASK)) | ((dataMode << SPI_MODE_SHIFT) & SPI_MODE_MASK); + SPI_M_REG_VAL(spi_addr, CTRL0) = (SPI_M_REG_VAL(spi_addr, CTRL0) + & ~(SPI_MODE_MASK)) | ((dataMode << SPI_MODE_SHIFT) & SPI_MODE_MASK); /* re-enable controller */ - SPI1_M_REG_VAL(SPIEN) |= SPI_ENABLE; + SPI_M_REG_VAL(spi_addr, SPIEN) |= SPI_ENABLE; } void SPIClass::begin() @@ -60,29 +62,30 @@ void SPIClass::begin() // Set SS to high so a connected chip will be "deselected" by default // TODO - confirm that data register is updated even if pin is set as input - digitalWrite(SS, HIGH); + digitalWrite(ss_gpio, HIGH); // When the SS pin is set as OUTPUT, it can be used as // a general purpose output port (it doesn't influence // SPI operations). - pinMode(SS, OUTPUT); + pinMode(ss_gpio, OUTPUT); /* disable controller */ - SPI1_M_REG_VAL(SPIEN) &= SPI_DISABLE; + SPI_M_REG_VAL(spi_addr, SPIEN) &= SPI_DISABLE; /* Enable clock to peripheral */ - MMIO_REG_VAL(PERIPH_CLK_GATE_CTRL) |= ENABLE_SPI_MASTER_1; + MMIO_REG_VAL(PERIPH_CLK_GATE_CTRL) |= enable_val; /* Configure defaults for clock divider, frame size and data mode */ - SPI1_M_REG_VAL(BAUDR) = SPI_CLOCK_DIV4; - SPI1_M_REG_VAL(CTRL0) = (frameSize << SPI_FSIZE_SHIFT) | (SPI_MODE0 << SPI_MODE_SHIFT); + SPI_M_REG_VAL(spi_addr, BAUDR) = SPI_CLOCK_DIV4; + SPI_M_REG_VAL(spi_addr, CTRL0) = + (frameSize << SPI_FSIZE_SHIFT) | (SPI_MODE0 << SPI_MODE_SHIFT); /* Disable interrupts */ - SPI1_M_REG_VAL(IMR) = SPI_DISABLE_INT; /* Enable at least one slave device (mandatory, though SS signals are unused) */ - SPI1_M_REG_VAL(SER) = 0x1; + SPI_M_REG_VAL(spi_addr, IMR) = SPI_DISABLE_INT; + SPI_M_REG_VAL(spi_addr, SER) = 0x1; /* Enable controller */ - SPI1_M_REG_VAL(SPIEN) |= SPI_ENABLE; + SPI_M_REG_VAL(spi_addr, SPIEN) |= SPI_ENABLE; /* Set SoC pin mux configuration */ SET_PIN_MODE(g_APinDescription[MOSI].ulSocPin, SPI_MUX_MODE); @@ -104,8 +107,8 @@ void SPIClass::end() { initialized--; // If there are no more references disable SPI if (!initialized) { - SPI1_M_REG_VAL(SPIEN) &= SPI_DISABLE; - MMIO_REG_VAL(PERIPH_CLK_GATE_CTRL) &= DISABLE_SPI_MASTER_1; + SPI_M_REG_VAL(spi_addr, SPIEN) &= SPI_DISABLE; + MMIO_REG_VAL(PERIPH_CLK_GATE_CTRL) &= disable_val; #ifdef SPI_TRANSACTION_MISMATCH_LED inTransactionFlag = 0; #endif diff --git a/libraries/SPI/src/SPI.h b/libraries/SPI/src/SPI.h old mode 100644 new mode 100755 index 8a96b930..c331624f --- a/libraries/SPI/src/SPI.h +++ b/libraries/SPI/src/SPI.h @@ -46,6 +46,11 @@ #define MSBFIRST 1 #endif +#define SPI0_CS 21 +#define SPI1_CS SS + +#define SPIDEV_0 0 +#define SPIDEV_1 1 /* For Arduino Uno compatibility, divider values are doubled to provide equivalent clock rates * e.g. SPI_CLOCK_DIV4 will produce a 4MHz clock * The Intel Curie has a 32MHz base clock and a min divider of 2, so max SPI clock is 16MHz @@ -63,6 +68,7 @@ #define SPI_MODE2 0x02 #define SPI_MODE3 0x03 +#define NUM_SPIDEVS 2 class SPISettings { public: SPISettings(uint32_t clock, uint8_t bitOrder, uint8_t dataMode) { @@ -86,7 +92,12 @@ class SPISettings { class SPIClass { public: - SPIClass(void) { initialized = 0; } + SPIClass(int dev) { + spi_addr = spidevs[dev][0]; + enable_val = spidevs[dev][1]; + disable_val = spidevs[dev][2]; + ss_gpio = spidevs[dev][3]; + } // Initialize the SPI library void begin(); @@ -131,14 +142,14 @@ class SPIClass { #endif /* disable controller */ - SPI1_M_REG_VAL(SPIEN) &= SPI_DISABLE; + SPI_M_REG_VAL(spi_addr, SPIEN) &= SPI_DISABLE; /* Configure clock divider, frame size and data mode */ - SPI1_M_REG_VAL(BAUDR) = settings.baudr; - SPI1_M_REG_VAL(CTRL0) = settings.ctrl0; + SPI_M_REG_VAL(spi_addr, BAUDR) = settings.baudr; + SPI_M_REG_VAL(spi_addr, CTRL0) = settings.ctrl0; frameSize = SPI_8_BIT; lsbFirst = settings.lsbFirst; /* Enable controller */ - SPI1_M_REG_VAL(SPIEN) |= SPI_ENABLE; + SPI_M_REG_VAL(spi_addr, SPIEN) |= SPI_ENABLE; } // Write to the SPI bus (MOSI pin) and also receive (MISO pin) @@ -186,15 +197,15 @@ class SPIClass { uint32_t transferSize = SPI_FIFO_DEPTH > remaining ? remaining : SPI_FIFO_DEPTH; /* Fill the TX FIFO */ for (uint32_t i = 0; i < transferSize; i++) - SPI1_M_REG_VAL(DR) = *(p + i); + SPI_M_REG_VAL(spi_addr, DR) = *(p + i); remaining -= transferSize; /* Wait for transfer to complete */ - while (SPI1_M_REG_VAL(SR) & SPI_STATUS_BUSY) ; + while (SPI_M_REG_VAL(spi_addr, SR) & SPI_STATUS_BUSY) ; do { - uint32_t rxLevel = SPI1_M_REG_VAL(RXFL); + uint32_t rxLevel = SPI_M_REG_VAL(spi_addr, RXFL); /* Drain the RX FIFO */ for (uint32_t i = 0; i < rxLevel; i++) - *(p + i) = SPI1_M_REG_VAL(DR); + *(p + i) = SPI_M_REG_VAL(spi_addr, DR); p += rxLevel; transferSize -= rxLevel; } while (transferSize); @@ -248,6 +259,10 @@ class SPIClass { void setClockDivider(uint8_t clockDiv); private: + int ss_gpio; + uint32_t spi_addr; + uint32_t enable_val; + uint32_t disable_val; uint32_t initialized; uint32_t interruptMode; // 0=none, 1-7=mask, 8=global uint32_t interruptMask[3]; // which interrupts to mask @@ -260,26 +275,38 @@ class SPIClass { inline void setFrameSize(uint32_t size) { if (frameSize != size) { /* disable controller */ - SPI1_M_REG_VAL(SPIEN) &= SPI_DISABLE; + SPI_M_REG_VAL(spi_addr, SPIEN) &= SPI_DISABLE; /* Configure new frame size */ frameSize = size; - SPI1_M_REG_VAL(CTRL0) = (SPI1_M_REG_VAL(CTRL0) & ~(SPI_FSIZE_MASK)) | ((frameSize << SPI_FSIZE_SHIFT) & SPI_FSIZE_MASK); + SPI_M_REG_VAL(spi_addr, CTRL0) = (SPI_M_REG_VAL(spi_addr, CTRL0) + & ~(SPI_FSIZE_MASK)) | ((frameSize << SPI_FSIZE_SHIFT) + & SPI_FSIZE_MASK); /* Enable controller */ - SPI1_M_REG_VAL(SPIEN) |= SPI_ENABLE; + SPI_M_REG_VAL(spi_addr, SPIEN) |= SPI_ENABLE; } } inline uint32_t singleTransfer(uint32_t data) { /* Write to TX FIFO */ - SPI1_M_REG_VAL(DR) = data; + SPI_M_REG_VAL(spi_addr, DR) = data; /* Wait for transfer to complete */ - while (SPI1_M_REG_VAL(SR) & SPI_STATUS_BUSY) ; - while (SPI1_M_REG_VAL(RXFL) == 0) ; + while (SPI_M_REG_VAL(spi_addr, SR) & SPI_STATUS_BUSY) ; + while (SPI_M_REG_VAL(spi_addr, RXFL) == 0) ; /* Read from RX FIFO */ - return SPI1_M_REG_VAL(DR); + return SPI_M_REG_VAL(spi_addr, DR); } + + void init(); + void set_dev(int dev); + int spidevs[NUM_SPIDEVS][4] = + { + /* base addr. Clk. enable value Clk. disable value SS GPIO */ + {(int)SOC_MST_SPI0_REGISTER_BASE, ENABLE_SPI_MASTER_0, DISABLE_SPI_MASTER_0, SPI0_CS}, + {(int)SOC_MST_SPI1_REGISTER_BASE, ENABLE_SPI_MASTER_1, DISABLE_SPI_MASTER_1, SPI1_CS} + }; }; extern SPIClass SPI; +extern SPIClass SPI1; #endif diff --git a/libraries/SPI/src/SPI_registers.h b/libraries/SPI/src/SPI_registers.h old mode 100644 new mode 100755 index 657de631..3b3823a4 --- a/libraries/SPI/src/SPI_registers.h +++ b/libraries/SPI/src/SPI_registers.h @@ -21,9 +21,8 @@ #include "portable.h" -/* Macro to access SPI1 Master controller register offset */ -#define SPI1_M_REG_VAL(reg) \ - MMIO_REG_VAL_FROM_BASE(SOC_MST_SPI1_REGISTER_BASE, (reg)) +/* Macro to access SPI Master controller register offset */ +#define SPI_M_REG_VAL(base, reg) MMIO_REG_VAL_FROM_BASE(base, (reg)) /* SoC SPI device register offsets */ #define CTRL0 (0x00) /* SoC SPI Control Register 1 */ @@ -55,8 +54,10 @@ #define SPI_FIFO_DEPTH (8UL) -#define ENABLE_SPI_MASTER_1 (0x1 << 15) -#define DISABLE_SPI_MASTER_1 (~ENABLE_SPI_MASTER_1) +#define ENABLE_SPI_MASTER_0 (0x1 << 14) +#define DISABLE_SPI_MASTER_0 (~ENABLE_SPI_MASTER_0) +#define ENABLE_SPI_MASTER_1 (0x1 << 15) +#define DISABLE_SPI_MASTER_1 (~ENABLE_SPI_MASTER_1) #define SPI_BASE_CLOCK (CLOCK_SPEED*1000*1000) /* CLOCK_SPEED in MHz */ diff --git a/variants/arduino_101/pins_arduino.h b/variants/arduino_101/pins_arduino.h index 8e7551a3..631c35cc 100644 --- a/variants/arduino_101/pins_arduino.h +++ b/variants/arduino_101/pins_arduino.h @@ -25,7 +25,7 @@ #ifndef Pins_Arduino_h #define Pins_Arduino_h -#define NUM_DIGITAL_PINS 21 +#define NUM_DIGITAL_PINS 22 #define NUM_ANALOG_INPUTS 6 #define NUM_PWM 4 #define NUM_UARTS 1 diff --git a/variants/arduino_101/variant.cpp b/variants/arduino_101/variant.cpp index 974eb798..0fe85c2d 100644 --- a/variants/arduino_101/variant.cpp +++ b/variants/arduino_101/variant.cpp @@ -83,6 +83,7 @@ PinDescription g_APinDescription[]= { 6, SS_GPIO_8B0, SS_GPIO, SS_GPIO_8B0_BASE_ADDR, 14, GPIO_MUX_MODE, INVALID, INVALID, 14, INPUT_MODE }, // Arduino IO18 { 1, SS_GPIO_8B0, SS_GPIO, SS_GPIO_8B0_BASE_ADDR, 9, GPIO_MUX_MODE, INVALID, INVALID, 9, INPUT_MODE }, // Arduino IO19 { 0, SS_GPIO_8B0, SS_GPIO, SS_GPIO_8B0_BASE_ADDR, 8, GPIO_MUX_MODE, INVALID, INVALID, INVALID, INPUT_MODE }, // Arduino IO20 + { 24, SOC_GPIO_32, SOC_GPIO, SOC_GPIO_BASE_ADDR, 58, GPIO_MUX_MODE, INVALID, INVALID, INVALID, INPUT_MODE }, // Arduino IO21 } ; From 331b2f0152bb90f1c96ee1726e8017db56e51789 Mon Sep 17 00:00:00 2001 From: "erik.nyquist" Date: Thu, 12 May 2016 11:18:35 -0700 Subject: [PATCH 2/3] Clean up the SPI files Be consistent about commenting style, and stay below 80 chars where appropriate. --- libraries/SPI/src/SPI.cpp | 30 ++++---- libraries/SPI/src/SPI.h | 109 ++++++++++++++++-------------- libraries/SPI/src/SPI_registers.h | 57 ++++++++-------- 3 files changed, 106 insertions(+), 90 deletions(-) diff --git a/libraries/SPI/src/SPI.cpp b/libraries/SPI/src/SPI.cpp index e4ca4841..57644358 100755 --- a/libraries/SPI/src/SPI.cpp +++ b/libraries/SPI/src/SPI.cpp @@ -13,7 +13,7 @@ * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #include "SPI.h" @@ -48,7 +48,8 @@ void SPIClass::setDataMode(uint8_t dataMode) void SPIClass::begin() { - uint32_t flags = interrupt_lock(); // Protect from a scheduler and prevent transactionBegin + /* Protect from a scheduler and prevent transactionBegin*/ + uint32_t flags = interrupt_lock(); if (!initialized) { interruptMode = 0; interruptMask[0] = 0; @@ -60,13 +61,14 @@ void SPIClass::begin() lsbFirst = false; frameSize = SPI_8_BIT; - // Set SS to high so a connected chip will be "deselected" by default - // TODO - confirm that data register is updated even if pin is set as input + /* Set SS to high so a connected chip will be "deselected" by default. + * TODO - confirm that data register is updated even if pin is set as + * input. */ digitalWrite(ss_gpio, HIGH); - // When the SS pin is set as OUTPUT, it can be used as - // a general purpose output port (it doesn't influence - // SPI operations). + /* When the SS pin is set as OUTPUT, it can be used as + * a general purpose output port (it doesn't influence + * SPI operations). */ pinMode(ss_gpio, OUTPUT); /* disable controller */ @@ -81,8 +83,9 @@ void SPIClass::begin() (frameSize << SPI_FSIZE_SHIFT) | (SPI_MODE0 << SPI_MODE_SHIFT); /* Disable interrupts */ - /* Enable at least one slave device (mandatory, though SS signals are unused) */ SPI_M_REG_VAL(spi_addr, IMR) = SPI_DISABLE_INT; + /* Enable at least one slave device (mandatory, though + * SS signals are unused) */ SPI_M_REG_VAL(spi_addr, SER) = 0x1; /* Enable controller */ SPI_M_REG_VAL(spi_addr, SPIEN) |= SPI_ENABLE; @@ -96,16 +99,17 @@ void SPIClass::begin() g_APinDescription[SCK].ulPinMode = SPI_MUX_MODE; } - initialized++; // reference count + initialized++; /* reference count */ interrupt_unlock(flags); } void SPIClass::end() { - uint32_t flags = interrupt_lock(); // Protect from a scheduler and prevent transactionBegin - // Decrease the reference counter + /* Protect from a scheduler and prevent transactionBegin */ + uint32_t flags = interrupt_lock(); + /* Decrease the reference counter */ if (initialized) initialized--; - // If there are no more references disable SPI + /* If there are no more references disable SPI */ if (!initialized) { SPI_M_REG_VAL(spi_addr, SPIEN) &= SPI_DISABLE; MMIO_REG_VAL(PERIPH_CLK_GATE_CTRL) &= disable_val; @@ -142,7 +146,7 @@ void SPIClass::usingInterrupt(uint8_t interruptNumber) { } void SPIClass::notUsingInterrupt(uint8_t interruptNumber) { - // Once in mode 8 we can't go back to 0 without a proper reference count + /* Once in mode 8 we can't go back to 0 without a proper reference count */ if (interruptMode == 8) return; diff --git a/libraries/SPI/src/SPI.h b/libraries/SPI/src/SPI.h index c331624f..40892da8 100755 --- a/libraries/SPI/src/SPI.h +++ b/libraries/SPI/src/SPI.h @@ -19,24 +19,25 @@ #include "SPI_registers.h" -// SPI_HAS_TRANSACTION means SPI has beginTransaction(), endTransaction(), -// usingInterrupt(), and SPISetting(clock, bitOrder, dataMode) +/* SPI_HAS_TRANSACTION means SPI has beginTransaction(), endTransaction(), + * usingInterrupt(), and SPISetting(clock, bitOrder, dataMode) */ #define SPI_HAS_TRANSACTION 1 -// SPI_HAS_NOTUSINGINTERRUPT means that SPI has notUsingInterrupt() method +/* SPI_HAS_NOTUSINGINTERRUPT means that SPI has notUsingInterrupt() method */ #define SPI_HAS_NOTUSINGINTERRUPT 1 -// SPI_ATOMIC_VERSION means that SPI has atomicity fixes and what version. -// This way when there is a bug fix you can check this define to alert users -// of your code if it uses better version of this library. -// This also implies everything that SPI_HAS_TRANSACTION as documented above is -// available too. +/* SPI_ATOMIC_VERSION means that SPI has atomicity fixes and what version. + * This way when there is a bug fix you can check this define to alert users + * of your code if it uses better version of this library. + * This also implies everything that SPI_HAS_TRANSACTION as documented above is + * available too. */ #define SPI_ATOMIC_VERSION 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 an LED to this pin. The LED will turn -// on if any mismatch is ever detected. +/* 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 an LED to this pin. The LED will turn + * on if any mismatch is ever detected. */ + //#define SPI_TRANSACTION_MISMATCH_LED 5 #ifndef LSBFIRST @@ -51,10 +52,11 @@ #define SPIDEV_0 0 #define SPIDEV_1 1 -/* For Arduino Uno compatibility, divider values are doubled to provide equivalent clock rates - * e.g. SPI_CLOCK_DIV4 will produce a 4MHz clock - * The Intel Curie has a 32MHz base clock and a min divider of 2, so max SPI clock is 16MHz - */ + +/* For Arduino Uno compatibility, divider values are doubled to provide + * equivalent clock rates e.g. SPI_CLOCK_DIV4 will produce a 4MHz clock + * The Intel Curie has a 32MHz base clock and a min divider of 2, so max + * SPI clock is 16MHz */ #define SPI_CLOCK_DIV4 8 #define SPI_CLOCK_DIV16 32 #define SPI_CLOCK_DIV64 128 @@ -69,14 +71,17 @@ #define SPI_MODE3 0x03 #define NUM_SPIDEVS 2 + class SPISettings { public: SPISettings(uint32_t clock, uint8_t bitOrder, uint8_t dataMode) { /* Set frame size, bus mode and transfer mode */ - ctrl0 = (SPI_8_BIT << SPI_FSIZE_SHIFT) | ((dataMode << SPI_MODE_SHIFT) & SPI_MODE_MASK); + ctrl0 = (SPI_8_BIT << SPI_FSIZE_SHIFT) + | ((dataMode << SPI_MODE_SHIFT) & SPI_MODE_MASK); /* Set SPI Clock Divider */ baudr = (SPI_BASE_CLOCK / clock) & SPI_CLOCK_MASK; - /* Only MSBFIRST supported in hardware, need to swizzle the bits if LSBFIRST selected */ + /* Only MSBFIRST supported in hardware, need to swizzle the bits if + * LSBFIRST selected */ lsbFirst = (bitOrder == LSBFIRST) ? true : false; } SPISettings() { @@ -99,26 +104,26 @@ class SPIClass { ss_gpio = spidevs[dev][3]; } - // Initialize the SPI library + /* Initialize the SPI library */ void begin(); - // If SPI is 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. + /* If SPI is 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. */ void usingInterrupt(uint8_t interruptNumber); - // And this does the opposite. + /* And this does the opposite. */ void notUsingInterrupt(uint8_t interruptNumber); - // Note: the usingInterrupt and notUsingInterrupt functions should - // not to be called from ISR context or inside a transaction. - // For details see: - // https://github.com/arduino/Arduino/pull/2381 - // https://github.com/arduino/Arduino/pull/2449 - - // 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. + /* Note: the usingInterrupt and notUsingInterrupt functions should + * not to be called from ISR context or inside a transaction. + * For details see: + * https://github.com/arduino/Arduino/pull/2381 + * https://github.com/arduino/Arduino/pull/2449 */ + + /* 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 void beginTransaction(SPISettings settings) { if (interruptMode > 0) { if (interruptMode < 8) { @@ -152,7 +157,7 @@ class SPIClass { SPI_M_REG_VAL(spi_addr, SPIEN) |= SPI_ENABLE; } - // Write to the SPI bus (MOSI pin) and also receive (MISO pin) + /* Write to the SPI bus (MOSI pin) and also receive (MISO pin) */ inline uint8_t transfer(uint8_t data) { setFrameSize(SPI_8_BIT); if (lsbFirst) @@ -217,8 +222,8 @@ class SPIClass { } } - // After performing a group of transfers and releasing the chip select - // signal, this function allows others to access the SPI bus + /* After performing a group of transfers and releasing the chip select + * signal, this function allows others to access the SPI bus */ inline void endTransaction(void) { #ifdef SPI_TRANSACTION_MISMATCH_LED if (!inTransactionFlag) { @@ -231,31 +236,35 @@ class SPIClass { if (interruptMode > 0) { if (interruptMode < 8) { if (interruptMode & 1) - CLEAR_ARC_MASK(SS_GPIO_8B0_BASE_ADDR + SS_GPIO_INTMASK, interruptMask[0]); + CLEAR_ARC_MASK(SS_GPIO_8B0_BASE_ADDR + SS_GPIO_INTMASK, + interruptMask[0]); if (interruptMode & 2) - CLEAR_ARC_MASK(SS_GPIO_8B1_BASE_ADDR + SS_GPIO_INTMASK, interruptMask[1]); + CLEAR_ARC_MASK(SS_GPIO_8B1_BASE_ADDR + SS_GPIO_INTMASK, + interruptMask[1]); if (interruptMode & 4) - CLEAR_MMIO_MASK(SOC_GPIO_BASE_ADDR + SOC_GPIO_INTMASK, interruptMask[2]); + CLEAR_MMIO_MASK(SOC_GPIO_BASE_ADDR + SOC_GPIO_INTMASK, + interruptMask[2]); } else { interrupts(); } } } - // Disable the SPI bus + /* Disable the SPI bus */ void end(); - // This function is deprecated. New applications should use - // beginTransaction() to configure SPI settings. + /* This function is deprecated. New applications should use + * beginTransaction() to configure SPI settings. */ inline void setBitOrder(uint8_t bitOrder) { - /* Only MSBFIRST supported in hardware, need to swizzle the bits if LSBFIRST selected */ + /* Only MSBFIRST supported in hardware, need to swizzle the bits if + * LSBFIRST selected */ lsbFirst = (bitOrder == LSBFIRST) ? true : false; } - // This function is deprecated. New applications should use - // beginTransaction() to configure SPI settings. + /* This function is deprecated. New applications should use + * beginTransaction() to configure SPI settings. */ void setDataMode(uint8_t dataMode); - // This function is deprecated. New applications should use - // beginTransaction() to configure SPI settings. + /* This function is deprecated. New applications should use + * beginTransaction() to configure SPI settings. */ void setClockDivider(uint8_t clockDiv); private: @@ -264,8 +273,8 @@ class SPIClass { uint32_t enable_val; uint32_t disable_val; uint32_t initialized; - uint32_t interruptMode; // 0=none, 1-7=mask, 8=global - uint32_t interruptMask[3]; // which interrupts to mask + uint32_t interruptMode; /* 0=none, 1-7=mask, 8=global */ + uint32_t interruptMask[3]; /* which interrupts to mask */ #ifdef SPI_TRANSACTION_MISMATCH_LED uint32_t inTransactionFlag; #endif diff --git a/libraries/SPI/src/SPI_registers.h b/libraries/SPI/src/SPI_registers.h index 3b3823a4..9b8f017c 100755 --- a/libraries/SPI/src/SPI_registers.h +++ b/libraries/SPI/src/SPI_registers.h @@ -13,7 +13,7 @@ * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifndef _SPI_REGISTERS_H_ @@ -25,44 +25,47 @@ #define SPI_M_REG_VAL(base, reg) MMIO_REG_VAL_FROM_BASE(base, (reg)) /* SoC SPI device register offsets */ -#define CTRL0 (0x00) /* SoC SPI Control Register 1 */ -#define SPIEN (0x08) /* SoC SPI Enable Register */ -#define SER (0x10) /* SoC SPI Slave Enable Register */ -#define BAUDR (0x14) /* SoC SPI Baud Rate Select */ -#define TXFL (0x20) /* SoC SPI Transmit FIFO Level Register */ -#define RXFL (0x24) /* SoC SPI Receive FIFO Level Register */ -#define SR (0x28) /* SoC SPI Status Register */ -#define IMR (0x2C) /* SoC SPI Interrupt Mask Register */ -#define DR (0x60) /* SoC SPI Data Register */ +#define CTRL0 (0x00) /* SoC SPI Control */ +#define SPIEN (0x08) /* SoC SPI Enable */ +#define SER (0x10) /* SoC SPI Slave Enable */ +#define BAUDR (0x14) /* SoC SPI Baud Rate Select */ +#define TXFL (0x20) /* SoC SPI Transmit FIFO Level */ +#define RXFL (0x24) /* SoC SPI Receive FIFO Level */ +#define SR (0x28) /* SoC SPI Status Register */ +#define IMR (0x2C) /* SoC SPI Interrupt Mask */ +#define DR (0x60) /* SoC SPI Data */ /* SPI specific macros */ -#define SPI_DISABLE_INT (0x0) /* Disable SoC SPI Interrupts */ -#define SPI_ENABLE (0x1) /* Enable SoC SPI Device */ -#define SPI_DISABLE (0x0) /* Disable SoC SPI Device */ -#define SPI_STATUS_BUSY (0x1) /* Busy status */ +#define SPI_DISABLE_INT (0x0) /* Disable SoC SPI Interrupts */ +#define SPI_ENABLE (0x1) /* Enable SoC SPI Device */ +#define SPI_DISABLE (0x0) /* Disable SoC SPI Device */ +#define SPI_STATUS_BUSY (0x1) /* Busy status */ -#define SPI_8_BIT (7) /* 8-bit frame size */ -#define SPI_16_BIT (15) /* 16-bit frame size */ -#define SPI_24_BIT (23) /* 24-bit frame size */ -#define SPI_32_BIT (31) /* 32-bit frame size */ +#define SPI_8_BIT (7) /* 8-bit frame size */ +#define SPI_16_BIT (15) /* 16-bit frame size */ +#define SPI_24_BIT (23) /* 24-bit frame size */ +#define SPI_32_BIT (31) /* 32-bit frame size */ -#define SPI_MODE_MASK (0xC0) /* CPOL = bit 7, CPHA = bit 6 on CTRL0 */ -#define SPI_MODE_SHIFT (6) -#define SPI_FSIZE_MASK (0x1F0000) /* Valid frame sizes: 1- 32 bits */ -#define SPI_FSIZE_SHIFT (16) -#define SPI_CLOCK_MASK (0xFFFE) /* Clock divider: any even value in the ragnge 2-65534 */ +#define SPI_MODE_MASK (0xC0) /* CPOL=bit 7, CPHA=bit 6 on CTRL0 */ +#define SPI_MODE_SHIFT (6) +#define SPI_FSIZE_MASK (0x1F0000) /* Valid frame sizes: 1-32 bits */ +#define SPI_FSIZE_SHIFT (16) +#define SPI_CLOCK_MASK (0xFFFE) /* Clock divider: any even value + * in the ragnge 2-65534 */ -#define SPI_FIFO_DEPTH (8UL) +#define SPI_FIFO_DEPTH (8UL) #define ENABLE_SPI_MASTER_0 (0x1 << 14) #define DISABLE_SPI_MASTER_0 (~ENABLE_SPI_MASTER_0) #define ENABLE_SPI_MASTER_1 (0x1 << 15) #define DISABLE_SPI_MASTER_1 (~ENABLE_SPI_MASTER_1) -#define SPI_BASE_CLOCK (CLOCK_SPEED*1000*1000) /* CLOCK_SPEED in MHz */ + /* CLOCK_SPEED in MHz */ +#define SPI_BASE_CLOCK (CLOCK_SPEED*1000*1000) /* Utility function to reverse the bit order of a 32-bit word */ -static inline uint32_t arc32_bit_reverse(register uint32_t src, register uint32_t count) +static inline uint32_t arc32_bit_reverse(register uint32_t src, + register uint32_t count) { register uint32_t dst = 0; /* Copy the specified number of least-significant bits from src to dst, @@ -85,4 +88,4 @@ static inline uint32_t arc32_bit_reverse(register uint32_t src, register uint32_ #define SPI_REVERSE_24(b) arc32_bit_reverse((b), 24) #define SPI_REVERSE_32(b) arc32_bit_reverse((b), 32) -#endif // _SPI_REGISTERS_H_ +#endif /* _SPI_REGISTERS_H_ */ From 8dea7b4a1430dce33870a97fcf0330e0cda4fef3 Mon Sep 17 00:00:00 2001 From: "erik.nyquist" Date: Mon, 16 May 2016 10:41:02 -0700 Subject: [PATCH 3/3] Fix SPI clock divider calculation If a clock value greater than the maximum supported is passed (i.e. > 16MHz), the resulting value written to the BAUDR register will be 0 which will disable the serial output clock. Check for this and ensure the value calculated for BAUDR register is never < 2. --- libraries/SPI/src/SPI.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/libraries/SPI/src/SPI.h b/libraries/SPI/src/SPI.h index 40892da8..cd37622b 100755 --- a/libraries/SPI/src/SPI.h +++ b/libraries/SPI/src/SPI.h @@ -80,6 +80,12 @@ class SPISettings { | ((dataMode << SPI_MODE_SHIFT) & SPI_MODE_MASK); /* Set SPI Clock Divider */ baudr = (SPI_BASE_CLOCK / clock) & SPI_CLOCK_MASK; + + /* clock value passed is > than max supported; + * set baudr to 2 for max. speed */ + if (baudr == 0) + baudr = 2; + /* Only MSBFIRST supported in hardware, need to swizzle the bits if * LSBFIRST selected */ lsbFirst = (bitOrder == LSBFIRST) ? true : false;