// RHHardwareSPI.h // Author: Mike McCauley (mikem@airspayce.com) // Copyright (C) 2011 Mike McCauley // Contributed by Joanna Rutkowska // $Id: RHHardwareSPI.cpp,v 1.16 2016/07/07 00:02:53 mikem Exp mikem $ #include // Declare a single default instance of the hardware SPI interface class RHHardwareSPI hardware_spi; #ifdef RH_HAVE_HARDWARE_SPI #if (RH_PLATFORM == RH_PLATFORM_STM32) // Maple etc // Declare an SPI interface to use HardwareSPI SPI(1); #elif (RH_PLATFORM == RH_PLATFORM_STM32STD) // STM32F4 Discovery // Declare an SPI interface to use HardwareSPI SPI(1); #endif // Arduino Due has default SPI pins on central SPI headers, and not on 10, 11, 12, 13 // as per other Arduinos // http://21stdigitalhome.blogspot.com.au/2013/02/arduino-due-hardware-spi.html #if defined (__arm__) && !defined(CORE_TEENSY) && !defined(SPI_CLOCK_DIV16) // Arduino Due in 1.5.5 has no definitions for SPI dividers // SPI clock divider is based on MCK of 84MHz #define SPI_CLOCK_DIV16 (VARIANT_MCK/84000000) // 1MHz #define SPI_CLOCK_DIV8 (VARIANT_MCK/42000000) // 2MHz #define SPI_CLOCK_DIV4 (VARIANT_MCK/21000000) // 4MHz #define SPI_CLOCK_DIV2 (VARIANT_MCK/10500000) // 8MHz #define SPI_CLOCK_DIV1 (VARIANT_MCK/5250000) // 16MHz #endif RHHardwareSPI::RHHardwareSPI(Frequency frequency, BitOrder bitOrder, DataMode dataMode) : RHGenericSPI(frequency, bitOrder, dataMode) { } uint8_t RHHardwareSPI::transfer(uint8_t data) { return SPI.transfer(data); } void RHHardwareSPI::attachInterrupt() { #if (RH_PLATFORM == RH_PLATFORM_ARDUINO) SPI.attachInterrupt(); #endif } void RHHardwareSPI::detachInterrupt() { #if (RH_PLATFORM == RH_PLATFORM_ARDUINO) SPI.detachInterrupt(); #endif } void RHHardwareSPI::begin() { // Sigh: there are no common symbols for some of these SPI options across all platforms #if (RH_PLATFORM == RH_PLATFORM_ARDUINO) || (RH_PLATFORM == RH_PLATFORM_UNO32) || (RH_PLATFORM == RH_PLATFORM_CHIPKIT_CORE) uint8_t dataMode; if (_dataMode == DataMode0) dataMode = SPI_MODE0; else if (_dataMode == DataMode1) dataMode = SPI_MODE1; else if (_dataMode == DataMode2) dataMode = SPI_MODE2; else if (_dataMode == DataMode3) dataMode = SPI_MODE3; else dataMode = SPI_MODE0; #if (RH_PLATFORM == RH_PLATFORM_ARDUINO) && defined(__arm__) && defined(CORE_TEENSY) // Temporary work-around due to problem where avr_emulation.h does not work properly for the setDataMode() cal SPCR &= ~SPI_MODE_MASK; #else #if (RH_PLATFORM == RH_PLATFORM_ARDUINO) && defined (__arm__) && defined(ARDUINO_ARCH_SAMD) // Zero requires begin() before anything else :-) SPI.begin(); #endif SPI.setDataMode(dataMode); #endif #if (RH_PLATFORM == RH_PLATFORM_ARDUINO) && defined(SPI_HAS_TRANSACTION) uint32_t frequency32; if (_frequency == Frequency16MHz) { frequency32 = 16000000; } else if (_frequency == Frequency8MHz) { frequency32 = 8000000; } else if (_frequency == Frequency4MHz) { frequency32 = 4000000; } else if (_frequency == Frequency2MHz) { frequency32 = 2000000; } else { frequency32 = 1000000; } _settings = SPISettings(frequency32, (_bitOrder == BitOrderLSBFirst) ? LSBFIRST : MSBFIRST, dataMode); //Serial.print("SPISettings: "); Serial.println(frequency32, DEC); #endif #if (RH_PLATFORM == RH_PLATFORM_ARDUINO) && defined (__arm__) && (defined(ARDUINO_SAM_DUE) || defined(ARDUINO_ARCH_SAMD)) // Arduino Due in 1.5.5 has its own BitOrder :-( // So too does Arduino Zero ::BitOrder bitOrder; #else uint8_t bitOrder; #endif if (_bitOrder == BitOrderLSBFirst) bitOrder = LSBFIRST; else bitOrder = MSBFIRST; SPI.setBitOrder(bitOrder); uint8_t divider; switch (_frequency) { case Frequency1MHz: default: #if F_CPU == 8000000 divider = SPI_CLOCK_DIV8; #else divider = SPI_CLOCK_DIV16; #endif break; case Frequency2MHz: #if F_CPU == 8000000 divider = SPI_CLOCK_DIV4; #else divider = SPI_CLOCK_DIV8; #endif break; case Frequency4MHz: #if F_CPU == 8000000 divider = SPI_CLOCK_DIV2; #else divider = SPI_CLOCK_DIV4; #endif break; case Frequency8MHz: divider = SPI_CLOCK_DIV2; // 4MHz on an 8MHz Arduino break; case Frequency16MHz: divider = SPI_CLOCK_DIV2; // Not really 16MHz, only 8MHz. 4MHz on an 8MHz Arduino break; } SPI.setClockDivider(divider); SPI.begin(); // Teensy requires it to be set _after_ begin() SPI.setClockDivider(divider); #elif (RH_PLATFORM == RH_PLATFORM_STM32) // Maple etc spi_mode dataMode; // Hmmm, if we do this as a switch, GCC on maple gets v confused! if (_dataMode == DataMode0) dataMode = SPI_MODE_0; else if (_dataMode == DataMode1) dataMode = SPI_MODE_1; else if (_dataMode == DataMode2) dataMode = SPI_MODE_2; else if (_dataMode == DataMode3) dataMode = SPI_MODE_3; else dataMode = SPI_MODE_0; uint32 bitOrder; if (_bitOrder == BitOrderLSBFirst) bitOrder = LSBFIRST; else bitOrder = MSBFIRST; SPIFrequency frequency; // Yes, I know these are not exact equivalents. switch (_frequency) { case Frequency1MHz: default: frequency = SPI_1_125MHZ; break; case Frequency2MHz: frequency = SPI_2_25MHZ; break; case Frequency4MHz: frequency = SPI_4_5MHZ; break; case Frequency8MHz: frequency = SPI_9MHZ; break; case Frequency16MHz: frequency = SPI_18MHZ; break; } SPI.begin(frequency, bitOrder, dataMode); #elif (RH_PLATFORM == RH_PLATFORM_STM32STD) // STM32F4 discovery uint8_t dataMode; if (_dataMode == DataMode0) dataMode = SPI_MODE0; else if (_dataMode == DataMode1) dataMode = SPI_MODE1; else if (_dataMode == DataMode2) dataMode = SPI_MODE2; else if (_dataMode == DataMode3) dataMode = SPI_MODE3; else dataMode = SPI_MODE0; uint32_t bitOrder; if (_bitOrder == BitOrderLSBFirst) bitOrder = LSBFIRST; else bitOrder = MSBFIRST; SPIFrequency frequency; // Yes, I know these are not exact equivalents. switch (_frequency) { case Frequency1MHz: default: frequency = SPI_1_3125MHZ; break; case Frequency2MHz: frequency = SPI_2_625MHZ; break; case Frequency4MHz: frequency = SPI_5_25MHZ; break; case Frequency8MHz: frequency = SPI_10_5MHZ; break; case Frequency16MHz: frequency = SPI_21_0MHZ; break; } SPI.begin(frequency, bitOrder, dataMode); #elif (RH_PLATFORM == RH_PLATFORM_STM32F2) // Photon Serial.println("HERE"); uint8_t dataMode; if (_dataMode == DataMode0) dataMode = SPI_MODE0; else if (_dataMode == DataMode1) dataMode = SPI_MODE1; else if (_dataMode == DataMode2) dataMode = SPI_MODE2; else if (_dataMode == DataMode3) dataMode = SPI_MODE3; else dataMode = SPI_MODE0; SPI.setDataMode(dataMode); if (_bitOrder == BitOrderLSBFirst) SPI.setBitOrder(LSBFIRST); else SPI.setBitOrder(MSBFIRST); switch (_frequency) { case Frequency1MHz: default: SPI.setClockSpeed(1, MHZ); break; case Frequency2MHz: SPI.setClockSpeed(2, MHZ); break; case Frequency4MHz: SPI.setClockSpeed(4, MHZ); break; case Frequency8MHz: SPI.setClockSpeed(8, MHZ); break; case Frequency16MHz: SPI.setClockSpeed(16, MHZ); break; } // SPI.setClockDivider(SPI_CLOCK_DIV4); // 72MHz / 4MHz = 18MHz // SPI.setClockSpeed(1, MHZ); SPI.begin(); #elif (RH_PLATFORM == RH_PLATFORM_ESP8266) // Requires SPI driver for ESP8266 from https://github.com/esp8266/Arduino/tree/master/libraries/SPI // Which ppears to be in Arduino Board Manager ESP8266 Community version 2.1.0 // Contributed by David Skinner // begin comes first SPI.begin(); // datamode switch ( _dataMode ) { case DataMode1: SPI.setDataMode ( SPI_MODE1 ); break; case DataMode2: SPI.setDataMode ( SPI_MODE2 ); break; case DataMode3: SPI.setDataMode ( SPI_MODE3 ); break; case DataMode0: default: SPI.setDataMode ( SPI_MODE0 ); break; } // bitorder SPI.setBitOrder(_bitOrder == BitOrderLSBFirst ? LSBFIRST : MSBFIRST); // frequency (this sets the divider) switch (_frequency) { case Frequency1MHz: default: SPI.setFrequency(1000000); break; case Frequency2MHz: SPI.setFrequency(2000000); break; case Frequency4MHz: SPI.setFrequency(4000000); break; case Frequency8MHz: SPI.setFrequency(8000000); break; case Frequency16MHz: SPI.setFrequency(16000000); break; } #elif (RH_PLATFORM == RH_PLATFORM_RASPI) // Raspberry PI uint8_t dataMode; if (_dataMode == DataMode0) dataMode = BCM2835_SPI_MODE0; else if (_dataMode == DataMode1) dataMode = BCM2835_SPI_MODE1; else if (_dataMode == DataMode2) dataMode = BCM2835_SPI_MODE2; else if (_dataMode == DataMode3) dataMode = BCM2835_SPI_MODE3; uint8_t bitOrder; if (_bitOrder == BitOrderLSBFirst) bitOrder = BCM2835_SPI_BIT_ORDER_LSBFIRST; else bitOrder = BCM2835_SPI_BIT_ORDER_MSBFIRST; uint32_t divider; switch (_frequency) { case Frequency1MHz: default: divider = BCM2835_SPI_CLOCK_DIVIDER_256; break; case Frequency2MHz: divider = BCM2835_SPI_CLOCK_DIVIDER_128; break; case Frequency4MHz: divider = BCM2835_SPI_CLOCK_DIVIDER_64; break; case Frequency8MHz: divider = BCM2835_SPI_CLOCK_DIVIDER_32; break; case Frequency16MHz: divider = BCM2835_SPI_CLOCK_DIVIDER_16; break; } SPI.begin(divider, bitOrder, dataMode); #else #warning RHHardwareSPI does not support this platform yet. Consider adding it and contributing a patch. #endif } void RHHardwareSPI::end() { return SPI.end(); } // If our platform is arduino and we support transactions then lets use the begin/end transaction #if (RH_PLATFORM == RH_PLATFORM_ARDUINO) && defined(SPI_HAS_TRANSACTION) void RHHardwareSPI::beginTransaction() { SPI.beginTransaction(_settings); } void RHHardwareSPI::endTransaction() { SPI.endTransaction(); } #endif #endif