Commit 9a7fa4f8 authored by Sandeep Mistry's avatar Sandeep Mistry

Functional SPI

parent 941bacc7
/*
* SPI Master library for Arduino Zero.
* Copyright (c) 2015 Arduino LLC
*
* 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 = uc_pinMISO;
_uc_pinSCK = uc_pinSCK;
_uc_pinMosi = uc_pinMOSI;
_dataMode = NRF_SPI_MODE_0;
_bitOrder = NRF_SPI_BIT_ORDER_MSB_FIRST;
}
void SPIClass::begin()
{
init();
nrf_spi_pins_set(_p_spi, _uc_pinSCK, _uc_pinMosi, _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)
{
nrf_spi_disable(_p_spi);
nrf_spi_configure(_p_spi, settings.dataMode, settings.bitOrder);
nrf_spi_frequency_set(_p_spi, settings.clockFreq);
nrf_spi_enable(_p_spi);
}
void SPIClass::end()
{
nrf_spi_disable(_p_spi);
initialized = false;
}
void SPIClass::usingInterrupt(int /*interruptNumber*/)
{
}
void SPIClass::beginTransaction(SPISettings settings)
{
config(settings);
}
void SPIClass::endTransaction(void)
{
}
void SPIClass::setBitOrder(BitOrder order)
{
if (order == LSBFIRST) {
nrf_spi_configure(_p_spi, _dataMode, NRF_SPI_BIT_ORDER_LSB_FIRST);
} else {
nrf_spi_configure(_p_spi, _dataMode, NRF_SPI_BIT_ORDER_MSB_FIRST);
}
}
void SPIClass::setDataMode(uint8_t mode)
{
switch (mode)
{
case SPI_MODE0:
nrf_spi_configure(_p_spi, NRF_SPI_MODE_0, _bitOrder);
break;
case SPI_MODE1:
nrf_spi_configure(_p_spi, NRF_SPI_MODE_1, _bitOrder);
break;
case SPI_MODE2:
nrf_spi_configure(_p_spi, NRF_SPI_MODE_2, _bitOrder);
break;
case SPI_MODE3:
nrf_spi_configure(_p_spi, NRF_SPI_MODE_3, _bitOrder);
break;
default:
break;
}
}
void SPIClass::setClockDivider(uint8_t div)
{
nrf_spi_frequency_t clockFreq;
if (div >= SPI_CLOCK_DIV128) {
clockFreq = NRF_SPI_FREQ_125K;
} else if (div >= SPI_CLOCK_DIV64) {
clockFreq = NRF_SPI_FREQ_250K;
} else if (div >= SPI_CLOCK_DIV32) {
clockFreq = NRF_SPI_FREQ_500K;
} else if (div >= SPI_CLOCK_DIV16) {
clockFreq = (nrf_spi_frequency_t)SPI_FREQUENCY_FREQUENCY_M1;
} else if (div >= SPI_CLOCK_DIV8) {
clockFreq = (nrf_spi_frequency_t)SPI_FREQUENCY_FREQUENCY_M2;
} else if (div >= SPI_CLOCK_DIV4) {
clockFreq = (nrf_spi_frequency_t)SPI_FREQUENCY_FREQUENCY_M4;
} else {
clockFreq = (nrf_spi_frequency_t)SPI_FREQUENCY_FREQUENCY_M8;
}
nrf_spi_frequency_set(_p_spi, clockFreq);
}
byte SPIClass::transfer(uint8_t data)
{
nrf_spi_txd_set(_p_spi, data);
while(!nrf_spi_event_check(_p_spi, NRF_SPI_EVENT_READY));
data = nrf_spi_rxd_get(_p_spi);
nrf_spi_event_clear(_p_spi, NRF_SPI_EVENT_READY);
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 == NRF_SPI_BIT_ORDER_LSB_FIRST) {
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()
}
SPIClass SPI (NRF_SPI0, 24, 25, 23);
/*
* SPI Master library for Arduino Zero.
* Copyright (c) 2015 Arduino LLC
*
* 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 "nrf_spi.h"
#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 = NRF_SPI_FREQ_125K;
} else if (clock <= 250000) {
this->clockFreq = NRF_SPI_FREQ_250K;
} else if (clock <= 500000) {
this->clockFreq = NRF_SPI_FREQ_500K;
} else if (clock <= 1000000) {
this->clockFreq = (nrf_spi_frequency_t)SPI_FREQUENCY_FREQUENCY_M1;
} else if (clock <= 2000000) {
this->clockFreq = (nrf_spi_frequency_t)SPI_FREQUENCY_FREQUENCY_M2;
} else if (clock <= 4000000) {
this->clockFreq = (nrf_spi_frequency_t)SPI_FREQUENCY_FREQUENCY_M4;
} else {
this->clockFreq = (nrf_spi_frequency_t)SPI_FREQUENCY_FREQUENCY_M8;
}
this->bitOrder = (bitOrder == MSBFIRST ? NRF_SPI_BIT_ORDER_MSB_FIRST : NRF_SPI_BIT_ORDER_LSB_FIRST);
switch (dataMode)
{
case SPI_MODE0:
this->dataMode = NRF_SPI_MODE_0; break;
case SPI_MODE1:
this->dataMode = NRF_SPI_MODE_1; break;
case SPI_MODE2:
this->dataMode = NRF_SPI_MODE_2; break;
case SPI_MODE3:
this->dataMode = NRF_SPI_MODE_3; break;
default:
this->dataMode = NRF_SPI_MODE_0; break;
}
}
nrf_spi_frequency_t clockFreq;
nrf_spi_mode_t dataMode;
nrf_spi_bit_order_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;
nrf_spi_mode_t _dataMode;
nrf_spi_bit_order_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]);
}
extern SPIClass SPI;
extern SPIClass SPI1;
extern SPIClass SPI2;
// For compatibility with sketches designed for AVR @ 16 MHz
// New programs should use SPI.beginTransaction to set the SPI clock
#if F_CPU == 16000000
#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
#endif
#endif
\ No newline at end of file
/*
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);
}
/*
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
#######################################
# Constants (LITERAL1)
#######################################
SPI_MODE0 LITERAL1
SPI_MODE1 LITERAL1
SPI_MODE2 LITERAL1
SPI_MODE3 LITERAL1
SPI_CONTINUE LITERAL1
SPI_LAST LITERAL1
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=nRF52
\ No newline at end of file
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment