Browse Source

Add SPISettings (Matthijs Kooijman)

main
PaulStoffregen 10 years ago
parent
commit
e07c056bf8
2 changed files with 88 additions and 5 deletions
  1. +87
    -5
      SPI.h
  2. +1
    -0
      keywords.txt

+ 87
- 5
SPI.h View File

@@ -1,6 +1,7 @@
/*
* Copyright (c) 2010 by Cristian Maglie <c.maglie@bug.st>
* Copyright (c) 2014 by Paul Stoffregen <paul@pjrc.com> (Transaction API)
* Copyright (c) 2014 by Matthijs Kooijman <matthijs@stdin.nl> (SPISettings)
* SPI Master library for arduino.
*
* This file is free software; you can redistribute it and/or modify
@@ -38,6 +39,89 @@
#define SPI_CLOCK_MASK 0x03 // SPR1 = bit 1, SPR0 = bit 0 on SPCR
#define SPI_2XCLOCK_MASK 0x01 // SPI2X = bit 0 on SPSR


class SPISettings {
public:
SPISettings(uint32_t clock, uint8_t bitOrder, uint8_t dataMode) {
if (__builtin_constant_p(clock)) {
init_AlwaysInline(clock, bitOrder, dataMode);
} else {
init_MightInline(clock, bitOrder, dataMode);
}
}
private:
void init_MightInline(uint32_t clock, uint8_t bitOrder, uint8_t dataMode) {
init_AlwaysInline(clock, bitOrder, dataMode);
}
void init_AlwaysInline(uint32_t clock, uint8_t bitOrder, uint8_t dataMode)
__attribute__((__always_inline__)) {
// Clock settings are defined as follows. Note that this shows SPI2X
// inverted, so the bits form increasing numbers. Also note that
// fosc/64 appears twice
// SPR1 SPR0 ~SPI2X Freq
// 0 0 0 fosc/2
// 0 0 1 fosc/4
// 0 1 0 fosc/8
// 0 1 1 fosc/16
// 1 0 0 fosc/32
// 1 0 1 fosc/64
// 1 1 0 fosc/64
// 1 1 1 fosc/128

// We find the fastest clock that is less than or equal to the
// given clock rate. The clock divider that results in clock_setting
// is 2 ^^ (clock_div + 1). If nothing is slow enough, we'll use the
// slowest (128 == 2 ^^ 7, so clock_div = 6).
uint8_t clockDiv;

// When the clock is known at compiletime, use this if-then-else
// cascade, which the compiler knows how to completely optimize
// away. When clock is not know, use a loop instead, which generates
// shorter code.
if (__builtin_constant_p(clock)) {
if (clock >= F_CPU / 2) {
clockDiv = 0;
} else if (clock >= F_CPU / 4) {
clockDiv = 1;
} else if (clock >= F_CPU / 8) {
clockDiv = 2;
} else if (clock >= F_CPU / 16) {
clockDiv = 3;
} else if (clock >= F_CPU / 32) {
clockDiv = 4;
} else if (clock >= F_CPU / 64) {
clockDiv = 5;
} else {
clockDiv = 6;
}
} else {
uint32_t clockSetting = F_CPU / 2;
clockDiv = 0;
while (clockDiv < 6 && clock < clockSetting) {
clockSetting /= 2;
clockDiv++;
}
}

// Compensate for the duplicate fosc/64
if (clockDiv == 6)
clockDiv = 7;

// Invert the SPI2X bit
clockDiv ^= 0x1;

// Pack into the SPISettings class
spcr = _BV(SPE) | _BV(MSTR) | ((bitOrder == LSBFIRST) ? _BV(DORD) : 0) |
(dataMode & SPI_MODE_MASK) | ((clockDiv >> 1) & SPI_CLOCK_MASK);
spsr = clockDiv & SPI_2XCLOCK_MASK;
}
uint8_t spcr;
uint8_t spsr;
friend class SPIClass;
};



class SPIClass {
public:
// Initialize the SPI library
@@ -56,7 +140,7 @@ public:
// 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 static void beginTransaction(uint8_t clockDiv, uint8_t bitOrder, uint8_t dataMode) {
inline static void beginTransaction(SPISettings settings) {
if (interruptMode > 0) {
#ifdef SPI_AVR_EIMSK
if (interruptMode == 1) {
@@ -69,10 +153,8 @@ public:
cli();
}
}
// these long expressions each compile to only 2 instructions
SPCR = _BV(SPE) | _BV(MSTR) | ((bitOrder == LSBFIRST) ? _BV(DORD) : 0) |
(dataMode & SPI_MODE_MASK) | (clockDiv & SPI_CLOCK_MASK);
SPSR = (clockDiv >> 2) & SPI_2XCLOCK_MASK;
SPCR = settings.spcr;
SPSR = settings.spsr;
}

// Write to the SPI bus (MOSI pin) and also receive (MISO pin)

+ 1
- 0
keywords.txt View File

@@ -23,6 +23,7 @@ setSCK KEYWORD2
usingInterrupt KEYWORD2
beginTransaction KEYWORD2
endTransaction KEYWORD2
SPISettings KEYWORD2

#######################################
# Constants (LITERAL1)

Loading…
Cancel
Save