#SPI Library for Teensy# | |||||
http://www.pjrc.com/teensy/teensyduino.html |
/* | |||||
* Copyright (c) 2010 by Cristian Maglie <c.maglie@bug.st> | |||||
* SPI Master library for arduino. | |||||
* | |||||
* This file is free software; you can redistribute it and/or modify | |||||
* it under the terms of either the GNU General Public License version 2 | |||||
* or the GNU Lesser General Public License version 2.1, both as | |||||
* published by the Free Software Foundation. | |||||
*/ | |||||
#include "pins_arduino.h" | |||||
#include "SPI.h" | |||||
SPIClass SPI; | |||||
void SPIClass::begin() { | |||||
// Set SS to high so a connected chip will be "deselected" by default | |||||
digitalWrite(SS, 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); | |||||
// Warning: if the SS pin ever becomes a LOW INPUT then SPI | |||||
// automatically switches to Slave, so the data direction of | |||||
// the SS pin MUST be kept as OUTPUT. | |||||
SPCR |= _BV(MSTR); | |||||
SPCR |= _BV(SPE); | |||||
// Set direction register for SCK and MOSI pin. | |||||
// MISO pin automatically overrides to INPUT. | |||||
// By doing this AFTER enabling SPI, we avoid accidentally | |||||
// clocking in a single bit since the lines go directly | |||||
// from "input" to SPI control. | |||||
// http://code.google.com/p/arduino/issues/detail?id=888 | |||||
#ifdef __AVR__ | |||||
pinMode(SCK, OUTPUT); | |||||
pinMode(MOSI, OUTPUT); | |||||
#endif | |||||
} | |||||
void SPIClass::end() { | |||||
SPCR &= ~_BV(SPE); | |||||
} | |||||
void SPIClass::setBitOrder(uint8_t bitOrder) | |||||
{ | |||||
if(bitOrder == LSBFIRST) { | |||||
SPCR |= _BV(DORD); | |||||
} else { | |||||
SPCR &= ~(_BV(DORD)); | |||||
} | |||||
} | |||||
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); | |||||
} | |||||
/* | |||||
* Copyright (c) 2010 by Cristian Maglie <c.maglie@bug.st> | |||||
* SPI Master library for arduino. | |||||
* | |||||
* This file is free software; you can redistribute it and/or modify | |||||
* it under the terms of either the GNU General Public License version 2 | |||||
* or the GNU Lesser General Public License version 2.1, both as | |||||
* published by the Free Software Foundation. | |||||
*/ | |||||
#ifndef _SPI_H_INCLUDED | |||||
#define _SPI_H_INCLUDED | |||||
#include <stdio.h> | |||||
#include <Arduino.h> | |||||
#include <avr/pgmspace.h> | |||||
#define SPI_CLOCK_DIV4 0x00 | |||||
#define SPI_CLOCK_DIV16 0x01 | |||||
#define SPI_CLOCK_DIV64 0x02 | |||||
#define SPI_CLOCK_DIV128 0x03 | |||||
#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 | |||||
#define SPI_MODE2 0x08 | |||||
#define SPI_MODE3 0x0C | |||||
#define SPI_MODE_MASK 0x0C // CPOL = bit 3, CPHA = bit 2 on SPCR | |||||
#define SPI_CLOCK_MASK 0x03 // SPR1 = bit 1, SPR0 = bit 0 on SPCR | |||||
#define SPI_2XCLOCK_MASK 0x01 // SPI2X = bit 0 on SPSR | |||||
class SPIClass { | |||||
public: | |||||
inline static byte transfer(byte _data); | |||||
// SPI Configuration methods | |||||
inline static void attachInterrupt(); | |||||
inline static void detachInterrupt(); // Default | |||||
static void begin(); // Default | |||||
static void end(); | |||||
static void setBitOrder(uint8_t); | |||||
static void setDataMode(uint8_t); | |||||
static void setClockDivider(uint8_t); | |||||
#if defined(__arm__) && defined(CORE_TEENSY) | |||||
inline void setMOSI(uint8_t pin) __attribute__((always_inline)) { SPCR.setMOSI(pin); } | |||||
inline void setMISO(uint8_t pin) __attribute__((always_inline)) { SPCR.setMISO(pin); } | |||||
inline void setSCK(uint8_t pin) __attribute__((always_inline)) { SPCR.setSCK(pin); } | |||||
#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 |
/* | |||||
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); | |||||
} | |||||
/* | |||||
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 | |||||
cont byte READ = 0b00000000; // 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 | |||||
// 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 | |||||
dataToSend = thisRegister & READ; | |||||
// 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: | |||||
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); | |||||
} | |||||
/* | |||||
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); | |||||
} |
####################################### | |||||
# Syntax Coloring Map SPI | |||||
####################################### | |||||
####################################### | |||||
# Datatypes (KEYWORD1) | |||||
####################################### | |||||
SPI KEYWORD1 | |||||
####################################### | |||||
# Methods and Functions (KEYWORD2) | |||||
####################################### | |||||
begin KEYWORD2 | |||||
end KEYWORD2 | |||||
transfer KEYWORD2 | |||||
setBitOrder KEYWORD2 | |||||
setDataMode KEYWORD2 | |||||
setClockDivider KEYWORD2 | |||||
setMOSI KEYWORD2 | |||||
setMISO KEYWORD2 | |||||
setSCK KEYWORD2 | |||||
####################################### | |||||
# Constants (LITERAL1) | |||||
####################################### | |||||
SPI_CLOCK_DIV4 LITERAL1 | |||||
SPI_CLOCK_DIV16 LITERAL1 | |||||
SPI_CLOCK_DIV64 LITERAL1 | |||||
SPI_CLOCK_DIV128 LITERAL1 | |||||
SPI_CLOCK_DIV2 LITERAL1 | |||||
SPI_CLOCK_DIV8 LITERAL1 | |||||
SPI_CLOCK_DIV32 LITERAL1 | |||||
SPI_CLOCK_DIV64 LITERAL1 | |||||
SPI_MODE0 LITERAL1 | |||||
SPI_MODE1 LITERAL1 | |||||
SPI_MODE2 LITERAL1 | |||||
SPI_MODE3 LITERAL1 |