diff options
Diffstat (limited to 'arduino/libraries/SPI')
-rwxr-xr-x | arduino/libraries/SPI/SPI.cpp | 254 | ||||
-rwxr-xr-x | arduino/libraries/SPI/SPI.h | 154 | ||||
-rwxr-xr-x | arduino/libraries/SPI/examples/BarometricPressureSensor/BarometricPressureSensor.ino | 143 | ||||
-rwxr-xr-x | arduino/libraries/SPI/examples/DigitalPotControl/DigitalPotControl.ino | 71 | ||||
-rwxr-xr-x | arduino/libraries/SPI/keywords.txt | 31 | ||||
-rwxr-xr-x | arduino/libraries/SPI/library.properties | 9 |
6 files changed, 662 insertions, 0 deletions
diff --git a/arduino/libraries/SPI/SPI.cpp b/arduino/libraries/SPI/SPI.cpp new file mode 100755 index 0000000..e0c4a2a --- /dev/null +++ b/arduino/libraries/SPI/SPI.cpp @@ -0,0 +1,254 @@ +/* + * SPI Master library for nRF5x. + * Copyright (c) 2015 Arduino LLC + * Copyright (c) 2016 Sandeep Mistry 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 + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * 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. + * + * 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 St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "SPI.h" +#include <Arduino.h> +#include <wiring_private.h> +#include <assert.h> + +#define SPI_IMODE_NONE 0 +#define SPI_IMODE_EXTINT 1 +#define SPI_IMODE_GLOBAL 2 + +const SPISettings DEFAULT_SPI_SETTINGS = SPISettings(); + +SPIClass::SPIClass(NRF_SPI_Type *p_spi, uint8_t uc_pinMISO, uint8_t uc_pinSCK, uint8_t uc_pinMOSI) +{ + initialized = false; + assert(p_spi != NULL); + _p_spi = p_spi; + + // pins + _uc_pinMiso = g_ADigitalPinMap[uc_pinMISO]; + _uc_pinSCK = g_ADigitalPinMap[uc_pinSCK]; + _uc_pinMosi = g_ADigitalPinMap[uc_pinMOSI]; + + _dataMode = SPI_MODE0; + _bitOrder = SPI_CONFIG_ORDER_MsbFirst; +} + +void SPIClass::begin() +{ + init(); + + _p_spi->PSELSCK = _uc_pinSCK; + _p_spi->PSELMOSI = _uc_pinMosi; + _p_spi->PSELMISO = _uc_pinMiso; + + config(DEFAULT_SPI_SETTINGS); +} + +void SPIClass::init() +{ + if (initialized) + return; + interruptMode = SPI_IMODE_NONE; + interruptSave = 0; + interruptMask = 0; + initialized = true; +} + +void SPIClass::config(SPISettings settings) +{ + _p_spi->ENABLE = (SPI_ENABLE_ENABLE_Disabled << SPI_ENABLE_ENABLE_Pos); + + uint32_t config = settings.bitOrder; + + switch (settings.dataMode) { + default: + case SPI_MODE0: + config |= (SPI_CONFIG_CPOL_ActiveHigh << SPI_CONFIG_CPOL_Pos); + config |= (SPI_CONFIG_CPHA_Leading << SPI_CONFIG_CPHA_Pos); + break; + + case SPI_MODE1: + config |= (SPI_CONFIG_CPOL_ActiveHigh << SPI_CONFIG_CPOL_Pos); + config |= (SPI_CONFIG_CPHA_Trailing << SPI_CONFIG_CPHA_Pos); + break; + + case SPI_MODE2: + config |= (SPI_CONFIG_CPOL_ActiveLow << SPI_CONFIG_CPOL_Pos); + config |= (SPI_CONFIG_CPHA_Leading << SPI_CONFIG_CPHA_Pos); + break; + + case SPI_MODE3: + config |= (SPI_CONFIG_CPOL_ActiveLow << SPI_CONFIG_CPOL_Pos); + config |= (SPI_CONFIG_CPHA_Trailing << SPI_CONFIG_CPHA_Pos); + break; + } + + _p_spi->CONFIG = config; + _p_spi->FREQUENCY = settings.clockFreq; + + _p_spi->ENABLE = (SPI_ENABLE_ENABLE_Enabled << SPI_ENABLE_ENABLE_Pos); +} + +void SPIClass::end() +{ + _p_spi->ENABLE = (SPI_ENABLE_ENABLE_Disabled << SPI_ENABLE_ENABLE_Pos); + + initialized = false; +} + +void SPIClass::usingInterrupt(int /*interruptNumber*/) +{ +} + +void SPIClass::beginTransaction(SPISettings settings) +{ + config(settings); +} + +void SPIClass::endTransaction(void) +{ + _p_spi->ENABLE = (SPI_ENABLE_ENABLE_Disabled << SPI_ENABLE_ENABLE_Pos); +} + +void SPIClass::setBitOrder(BitOrder order) +{ + this->_bitOrder = (order == MSBFIRST ? SPI_CONFIG_ORDER_MsbFirst : SPI_CONFIG_ORDER_LsbFirst); + + uint32_t config = this->_bitOrder; + + switch (this->_dataMode) { + default: + case SPI_MODE0: + config |= (SPI_CONFIG_CPOL_ActiveHigh << SPI_CONFIG_CPOL_Pos); + config |= (SPI_CONFIG_CPHA_Leading << SPI_CONFIG_CPHA_Pos); + break; + + case SPI_MODE1: + config |= (SPI_CONFIG_CPOL_ActiveHigh << SPI_CONFIG_CPOL_Pos); + config |= (SPI_CONFIG_CPHA_Trailing << SPI_CONFIG_CPHA_Pos); + break; + + case SPI_MODE2: + config |= (SPI_CONFIG_CPOL_ActiveLow << SPI_CONFIG_CPOL_Pos); + config |= (SPI_CONFIG_CPHA_Leading << SPI_CONFIG_CPHA_Pos); + break; + + case SPI_MODE3: + config |= (SPI_CONFIG_CPOL_ActiveLow << SPI_CONFIG_CPOL_Pos); + config |= (SPI_CONFIG_CPHA_Trailing << SPI_CONFIG_CPHA_Pos); + break; + } + + _p_spi->CONFIG = config; +} + +void SPIClass::setDataMode(uint8_t mode) +{ + this->_dataMode = mode; + + uint32_t config = this->_bitOrder; + + switch (this->_dataMode) { + default: + case SPI_MODE0: + config |= (SPI_CONFIG_CPOL_ActiveHigh << SPI_CONFIG_CPOL_Pos); + config |= (SPI_CONFIG_CPHA_Leading << SPI_CONFIG_CPHA_Pos); + break; + + case SPI_MODE1: + config |= (SPI_CONFIG_CPOL_ActiveHigh << SPI_CONFIG_CPOL_Pos); + config |= (SPI_CONFIG_CPHA_Trailing << SPI_CONFIG_CPHA_Pos); + break; + + case SPI_MODE2: + config |= (SPI_CONFIG_CPOL_ActiveLow << SPI_CONFIG_CPOL_Pos); + config |= (SPI_CONFIG_CPHA_Leading << SPI_CONFIG_CPHA_Pos); + break; + + case SPI_MODE3: + config |= (SPI_CONFIG_CPOL_ActiveLow << SPI_CONFIG_CPOL_Pos); + config |= (SPI_CONFIG_CPHA_Trailing << SPI_CONFIG_CPHA_Pos); + break; + } + + _p_spi->CONFIG = config; +} + +void SPIClass::setClockDivider(uint8_t div) +{ + uint32_t clockFreq; + + // Adafruit Note: nrf52 run at 64MHz + if (div >= SPI_CLOCK_DIV512) { + clockFreq = SPI_FREQUENCY_FREQUENCY_K125; + } else if (div >= SPI_CLOCK_DIV256) { + clockFreq = SPI_FREQUENCY_FREQUENCY_K250; + } else if (div >= SPI_CLOCK_DIV128) { + clockFreq = SPI_FREQUENCY_FREQUENCY_K500; + } else if (div >= SPI_CLOCK_DIV64) { + clockFreq = SPI_FREQUENCY_FREQUENCY_M1; + } else if (div >= SPI_CLOCK_DIV32) { + clockFreq = SPI_FREQUENCY_FREQUENCY_M2; + } else if (div >= SPI_CLOCK_DIV16) { + clockFreq = SPI_FREQUENCY_FREQUENCY_M4; + } else { + clockFreq = SPI_FREQUENCY_FREQUENCY_M8; + } + + _p_spi->FREQUENCY = clockFreq; +} + +byte SPIClass::transfer(uint8_t data) +{ + _p_spi->TXD = data; + + while(!_p_spi->EVENTS_READY); + + data = _p_spi->RXD; + + _p_spi->EVENTS_READY = 0x0UL; + + return data; +} + +uint16_t SPIClass::transfer16(uint16_t data) { + union { uint16_t val; struct { uint8_t lsb; uint8_t msb; }; } t; + + t.val = data; + + if (_bitOrder == SPI_CONFIG_ORDER_LsbFirst) { + t.lsb = transfer(t.lsb); + t.msb = transfer(t.msb); + } else { + t.msb = transfer(t.msb); + t.lsb = transfer(t.lsb); + } + + return t.val; +} + +void SPIClass::attachInterrupt() { + // Should be enableInterrupt() +} + +void SPIClass::detachInterrupt() { + // Should be disableInterrupt() +} + +#if SPI_INTERFACES_COUNT > 0 +SPIClass SPI (NRF_SPI0, PIN_SPI_MISO, PIN_SPI_SCK, PIN_SPI_MOSI); +#endif +#if SPI_INTERFACES_COUNT > 1 +SPIClass SPI1(NRF_SPI1, PIN_SPI1_MISO, PIN_SPI1_SCK, PIN_SPI1_MOSI); +#endif diff --git a/arduino/libraries/SPI/SPI.h b/arduino/libraries/SPI/SPI.h new file mode 100755 index 0000000..778575b --- /dev/null +++ b/arduino/libraries/SPI/SPI.h @@ -0,0 +1,154 @@ +/* + * SPI Master library for nRF5x. + * Copyright (c) 2015 Arduino LLC + * Copyright (c) 2016 Sandeep Mistry 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 + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * 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. + * + * 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 St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef _SPI_H_INCLUDED +#define _SPI_H_INCLUDED + +#include <Arduino.h> + +// SPI_HAS_TRANSACTION means SPI has +// - beginTransaction() +// - endTransaction() +// - usingInterrupt() +// - SPISetting(clock, bitOrder, dataMode) +#define SPI_HAS_TRANSACTION 1 + +#define SPI_MODE0 0x02 +#define SPI_MODE1 0x00 +#define SPI_MODE2 0x03 +#define SPI_MODE3 0x01 + + +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); + } + } + + // Default speed set to 4MHz, SPI mode set to MODE 0 and Bit order set to MSB first. + 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__)) { + if (clock <= 125000) { + this->clockFreq = SPI_FREQUENCY_FREQUENCY_K125; + } else if (clock <= 250000) { + this->clockFreq = SPI_FREQUENCY_FREQUENCY_K250; + } else if (clock <= 500000) { + this->clockFreq = SPI_FREQUENCY_FREQUENCY_K500; + } else if (clock <= 1000000) { + this->clockFreq = SPI_FREQUENCY_FREQUENCY_M1; + } else if (clock <= 2000000) { + this->clockFreq = SPI_FREQUENCY_FREQUENCY_M2; + } else if (clock <= 4000000) { + this->clockFreq = SPI_FREQUENCY_FREQUENCY_M4; + } else { + this->clockFreq = SPI_FREQUENCY_FREQUENCY_M8; + } + + this->bitOrder = (bitOrder == MSBFIRST ? SPI_CONFIG_ORDER_MsbFirst : SPI_CONFIG_ORDER_LsbFirst); + this->dataMode = dataMode; + } + + uint32_t clockFreq; + uint8_t dataMode; + uint32_t bitOrder; + + friend class SPIClass; +}; + +class SPIClass { + public: + SPIClass(NRF_SPI_Type *p_spi, uint8_t uc_pinMISO, uint8_t uc_pinSCK, uint8_t uc_pinMOSI); + + + byte transfer(uint8_t data); + uint16_t transfer16(uint16_t data); + inline void transfer(void *buf, size_t count); + + // Transaction Functions + void usingInterrupt(int interruptNumber); + void beginTransaction(SPISettings settings); + void endTransaction(void); + + // SPI Configuration methods + void attachInterrupt(); + void detachInterrupt(); + + void begin(); + void end(); + + void setBitOrder(BitOrder order); + void setDataMode(uint8_t uc_mode); + void setClockDivider(uint8_t uc_div); + + private: + void init(); + void config(SPISettings settings); + + NRF_SPI_Type *_p_spi; + uint8_t _uc_pinMiso; + uint8_t _uc_pinMosi; + uint8_t _uc_pinSCK; + + uint8_t _dataMode; + uint32_t _bitOrder; + + bool initialized; + uint8_t interruptMode; + char interruptSave; + uint32_t interruptMask; +}; + +void SPIClass::transfer(void *buf, size_t count) +{ + // TODO: Optimize for faster block-transfer + uint8_t *buffer = reinterpret_cast<uint8_t *>(buf); + for (size_t i=0; i<count; i++) + buffer[i] = transfer(buffer[i]); +} + +#if SPI_INTERFACES_COUNT > 0 +extern SPIClass SPI; +#endif + +// For compatibility with sketches designed for AVR @ 64 MHz +// New programs should use SPI.beginTransaction to set the SPI clock +#if F_CPU == 64000000 // feather52 run @ 64Mhz + #define SPI_CLOCK_DIV2 2 + #define SPI_CLOCK_DIV4 4 + #define SPI_CLOCK_DIV8 8 + #define SPI_CLOCK_DIV16 16 + #define SPI_CLOCK_DIV32 32 + #define SPI_CLOCK_DIV64 64 + #define SPI_CLOCK_DIV128 128 + #define SPI_CLOCK_DIV256 256 + #define SPI_CLOCK_DIV512 512 +#endif + +#endif diff --git a/arduino/libraries/SPI/examples/BarometricPressureSensor/BarometricPressureSensor.ino b/arduino/libraries/SPI/examples/BarometricPressureSensor/BarometricPressureSensor.ino new file mode 100755 index 0000000..8104fcb --- /dev/null +++ b/arduino/libraries/SPI/examples/BarometricPressureSensor/BarometricPressureSensor.ino @@ -0,0 +1,143 @@ +/* + SCP1000 Barometric Pressure Sensor Display + + Shows the output of a Barometric Pressure Sensor on a + Uses the SPI library. For details on the sensor, see: + http://www.sparkfun.com/commerce/product_info.php?products_id=8161 + http://www.vti.fi/en/support/obsolete_products/pressure_sensors/ + + This sketch adapted from Nathan Seidle's SCP1000 example for PIC: + http://www.sparkfun.com/datasheets/Sensors/SCP1000-Testing.zip + + Circuit: + SCP1000 sensor attached to pins 6, 7, 10 - 13: + DRDY: pin 6 + CSB: pin 7 + MOSI: pin 11 + MISO: pin 12 + SCK: pin 13 + + created 31 July 2010 + modified 14 August 2010 + by Tom Igoe + */ + +// the sensor communicates using SPI, so include the library: +#include <SPI.h> + +//Sensor's memory register addresses: +const int PRESSURE = 0x1F; //3 most significant bits of pressure +const int PRESSURE_LSB = 0x20; //16 least significant bits of pressure +const int TEMPERATURE = 0x21; //16 bit temperature reading +const byte READ = 0b11111100; // SCP1000's read command +const byte WRITE = 0b00000010; // SCP1000's write command + +// pins used for the connection with the sensor +// the other you need are controlled by the SPI library): +const int dataReadyPin = 6; +const int chipSelectPin = 7; + +void setup() { + Serial.begin(9600); + + // start the SPI library: + SPI.begin(); + + // initalize the data ready and chip select pins: + pinMode(dataReadyPin, INPUT); + pinMode(chipSelectPin, OUTPUT); + + //Configure SCP1000 for low noise configuration: + writeRegister(0x02, 0x2D); + writeRegister(0x01, 0x03); + writeRegister(0x03, 0x02); + // give the sensor time to set up: + delay(100); +} + +void loop() { + //Select High Resolution Mode + writeRegister(0x03, 0x0A); + + // don't do anything until the data ready pin is high: + if (digitalRead(dataReadyPin) == HIGH) { + //Read the temperature data + int tempData = readRegister(0x21, 2); + + // convert the temperature to celsius and display it: + float realTemp = (float)tempData / 20.0; + Serial.print("Temp[C]="); + Serial.print(realTemp); + + + //Read the pressure data highest 3 bits: + byte pressure_data_high = readRegister(0x1F, 1); + pressure_data_high &= 0b00000111; //you only needs bits 2 to 0 + + //Read the pressure data lower 16 bits: + unsigned int pressure_data_low = readRegister(0x20, 2); + //combine the two parts into one 19-bit number: + long pressure = ((pressure_data_high << 16) | pressure_data_low) / 4; + + // display the temperature: + Serial.println("\tPressure [Pa]=" + String(pressure)); + } +} + +//Read from or write to register from the SCP1000: +unsigned int readRegister(byte thisRegister, int bytesToRead ) { + byte inByte = 0; // incoming byte from the SPI + unsigned int result = 0; // result to return + Serial.print(thisRegister, BIN); + Serial.print("\t"); + // SCP1000 expects the register name in the upper 6 bits + // of the byte. So shift the bits left by two bits: + thisRegister = thisRegister << 2; + // now combine the address and the command into one byte + byte dataToSend = thisRegister & READ; + Serial.println(thisRegister, BIN); + // take the chip select low to select the device: + digitalWrite(chipSelectPin, LOW); + // send the device the register you want to read: + SPI.transfer(dataToSend); + // send a value of 0 to read the first byte returned: + result = SPI.transfer(0x00); + // decrement the number of bytes left to read: + bytesToRead--; + // if you still have another byte to read: + if (bytesToRead > 0) { + // shift the first byte left, then get the second byte: + result = result << 8; + inByte = SPI.transfer(0x00); + // combine the byte you just got with the previous one: + result = result | inByte; + // decrement the number of bytes left to read: + bytesToRead--; + } + // take the chip select high to de-select: + digitalWrite(chipSelectPin, HIGH); + // return the result: + return(result); +} + + +//Sends a write command to SCP1000 + +void writeRegister(byte thisRegister, byte thisValue) { + + // SCP1000 expects the register address in the upper 6 bits + // of the byte. So shift the bits left by two bits: + thisRegister = thisRegister << 2; + // now combine the register address and the command into one byte: + byte dataToSend = thisRegister | WRITE; + + // take the chip select low to select the device: + digitalWrite(chipSelectPin, LOW); + + SPI.transfer(dataToSend); //Send register location + SPI.transfer(thisValue); //Send value to record into register + + // take the chip select high to de-select: + digitalWrite(chipSelectPin, HIGH); +} + diff --git a/arduino/libraries/SPI/examples/DigitalPotControl/DigitalPotControl.ino b/arduino/libraries/SPI/examples/DigitalPotControl/DigitalPotControl.ino new file mode 100755 index 0000000..b135a74 --- /dev/null +++ b/arduino/libraries/SPI/examples/DigitalPotControl/DigitalPotControl.ino @@ -0,0 +1,71 @@ +/* + Digital Pot Control + + This example controls an Analog Devices AD5206 digital potentiometer. + The AD5206 has 6 potentiometer channels. Each channel's pins are labeled + A - connect this to voltage + W - this is the pot's wiper, which changes when you set it + B - connect this to ground. + + The AD5206 is SPI-compatible,and to command it, you send two bytes, + one with the channel number (0 - 5) and one with the resistance value for the + channel (0 - 255). + + The circuit: + * All A pins of AD5206 connected to +5V + * All B pins of AD5206 connected to ground + * An LED and a 220-ohm resisor in series connected from each W pin to ground + * CS - to digital pin 10 (SS pin) + * SDI - to digital pin 11 (MOSI pin) + * CLK - to digital pin 13 (SCK pin) + + created 10 Aug 2010 + by Tom Igoe + + Thanks to Heather Dewey-Hagborg for the original tutorial, 2005 + +*/ + + +// inslude the SPI library: +#include <SPI.h> + + +// set pin 10 as the slave select for the digital pot: +const int slaveSelectPin = 10; + +void setup() { + // set the slaveSelectPin as an output: + pinMode (slaveSelectPin, OUTPUT); + // initialize SPI: + SPI.begin(); +} + +void loop() { + // go through the six channels of the digital pot: + for (int channel = 0; channel < 6; channel++) { + // change the resistance on this channel from min to max: + for (int level = 0; level < 255; level++) { + digitalPotWrite(channel, level); + delay(10); + } + // wait a second at the top: + delay(100); + // change the resistance on this channel from max to min: + for (int level = 0; level < 255; level++) { + digitalPotWrite(channel, 255 - level); + delay(10); + } + } + +} + +void digitalPotWrite(int address, int value) { + // take the SS pin low to select the chip: + digitalWrite(slaveSelectPin, LOW); + // send in the address and value via SPI: + SPI.transfer(address); + SPI.transfer(value); + // take the SS pin high to de-select the chip: + digitalWrite(slaveSelectPin, HIGH); +} diff --git a/arduino/libraries/SPI/keywords.txt b/arduino/libraries/SPI/keywords.txt new file mode 100755 index 0000000..47738f9 --- /dev/null +++ b/arduino/libraries/SPI/keywords.txt @@ -0,0 +1,31 @@ +####################################### +# Syntax Coloring Map SPI +####################################### + +####################################### +# Datatypes (KEYWORD1) +####################################### + +SPI KEYWORD1 + +####################################### +# Methods and Functions (KEYWORD2) +####################################### +begin KEYWORD2 +end KEYWORD2 +transfer KEYWORD2 +#setBitOrder KEYWORD2 +setDataMode KEYWORD2 +setClockDivider KEYWORD2 + + +####################################### +# Constants (LITERAL1) +####################################### +SPI_MODE0 LITERAL1 +SPI_MODE1 LITERAL1 +SPI_MODE2 LITERAL1 +SPI_MODE3 LITERAL1 + +SPI_CONTINUE LITERAL1 +SPI_LAST LITERAL1 diff --git a/arduino/libraries/SPI/library.properties b/arduino/libraries/SPI/library.properties new file mode 100755 index 0000000..bebf450 --- /dev/null +++ b/arduino/libraries/SPI/library.properties @@ -0,0 +1,9 @@ +name=SPI +version=1.0 +author= +maintainer= +sentence=Enables the communication with devices that use the Serial Peripheral Interface (SPI) Bus. Specific implementation for nRF52. +paragraph= +category=Communication +url=http://www.arduino.cc/en/Reference/SPI +architectures=* |