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

/* /*
* Copyright (c) 2010 by Cristian Maglie <c.maglie@bug.st> * 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 Paul Stoffregen <paul@pjrc.com> (Transaction API)
* Copyright (c) 2014 by Matthijs Kooijman <matthijs@stdin.nl> (SPISettings)
* SPI Master library for arduino. * SPI Master library for arduino.
* *
* This file is free software; you can redistribute it and/or modify * This file is free software; you can redistribute it and/or modify
#define SPI_CLOCK_MASK 0x03 // SPR1 = bit 1, SPR0 = bit 0 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 #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 { class SPIClass {
public: public:
// Initialize the SPI library // Initialize the SPI library
// Before using SPI.transfer() or asserting chip select pins, // Before using SPI.transfer() or asserting chip select pins,
// this function is used to gain exclusive access to the SPI bus // this function is used to gain exclusive access to the SPI bus
// and configure the correct settings. // 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) { if (interruptMode > 0) {
#ifdef SPI_AVR_EIMSK #ifdef SPI_AVR_EIMSK
if (interruptMode == 1) { if (interruptMode == 1) {
cli(); 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) // Write to the SPI bus (MOSI pin) and also receive (MISO pin)

+ 1
- 0
keywords.txt View File

usingInterrupt KEYWORD2 usingInterrupt KEYWORD2
beginTransaction KEYWORD2 beginTransaction KEYWORD2
endTransaction KEYWORD2 endTransaction KEYWORD2
SPISettings KEYWORD2


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

Loading…
Cancel
Save