瀏覽代碼

Restructure into separate AVR & ARM sections

main
PaulStoffregen 10 年之前
父節點
當前提交
cf1ba732d9
共有 2 個檔案被更改,包括 325 行新增104 行删除
  1. +94
    -16
      SPI.cpp
  2. +231
    -88
      SPI.h

+ 94
- 16
SPI.cpp 查看文件

@@ -13,13 +13,19 @@

SPIClass SPI;


/**********************************************************/
/* 8 bit AVR-based boards */
/**********************************************************/

#if defined(__AVR__)

uint8_t SPIClass::interruptMode = 0;
uint8_t SPIClass::interruptMask = 0;
uint8_t SPIClass::interruptSave = 0;

void SPIClass::begin()
{
#if defined(__AVR__)
// Set SS to high so a connected chip will be "deselected" by default
digitalWrite(SS, HIGH);

@@ -42,23 +48,10 @@ void SPIClass::begin()
// http://code.google.com/p/arduino/issues/detail?id=888
pinMode(SCK, OUTPUT);
pinMode(MOSI, OUTPUT);
#elif defined(__arm__) && defined(TEENSYDUINO)
SIM_SCGC6 |= SIM_SCGC6_SPI0;
SPI0_MCR = SPI_MCR_MDIS | SPI_MCR_HALT | SPI_MCR_PCSIS(0x1F);
SPI0_CTAR0 = SPI_CTAR_FMSZ(7) | SPI_CTAR_PBR(0) | SPI_CTAR_BR(1) | SPI_CTAR_CSSCK(1);
SPI0_CTAR1 = SPI_CTAR_FMSZ(15) | SPI_CTAR_PBR(0) | SPI_CTAR_BR(1) | SPI_CTAR_CSSCK(1);
SPI0_MCR = SPI_MCR_MSTR | SPI_MCR_PCSIS(0x1F);
SPCR.enable_pins(); // pins managed by SPCRemulation in avr_emulation.h
#endif
}

void SPIClass::end() {
#if defined(__AVR__)
SPCR &= ~_BV(SPE);
#elif defined(__arm__) && defined(TEENSYDUINO)
SPCR.disable_pins();
SPI0_MCR = SPI_MCR_MDIS | SPI_MCR_HALT | SPI_MCR_PCSIS(0x1F);
#endif
}

void SPIClass::usingInterrupt(uint8_t interruptNumber)
@@ -104,7 +97,43 @@ void SPIClass::usingInterrupt(uint8_t interruptNumber)
}


#if defined(__arm__) && defined(TEENSYDUINO)
/**********************************************************/
/* 32 bit Teensy 3.0 and 3.1 */
/**********************************************************/

#elif defined(__arm__) && defined(TEENSYDUINO)

uint8_t SPIClass::interruptMode = 0;
uint8_t SPIClass::interruptMask = 0;
uint8_t SPIClass::interruptSave = 0;

void SPIClass::begin()
{
SIM_SCGC6 |= SIM_SCGC6_SPI0;
SPI0_MCR = SPI_MCR_MDIS | SPI_MCR_HALT | SPI_MCR_PCSIS(0x1F);
SPI0_CTAR0 = SPI_CTAR_FMSZ(7) | SPI_CTAR_PBR(0) | SPI_CTAR_BR(1) | SPI_CTAR_CSSCK(1);
SPI0_CTAR1 = SPI_CTAR_FMSZ(15) | SPI_CTAR_PBR(0) | SPI_CTAR_BR(1) | SPI_CTAR_CSSCK(1);
SPI0_MCR = SPI_MCR_MSTR | SPI_MCR_PCSIS(0x1F);
SPCR.enable_pins(); // pins managed by SPCRemulation in avr_emulation.h
}

void SPIClass::end() {
SPCR.disable_pins();
SPI0_MCR = SPI_MCR_MDIS | SPI_MCR_HALT | SPI_MCR_PCSIS(0x1F);
}

void SPIClass::usingInterrupt(uint8_t interruptNumber)
{
// TODO: implement this...
}

void SPIClass::usingInterrupt(IRQ_NUMBER_t interruptName)
{
// TODO: implement this...
}



const uint16_t SPISettings::ctar_div_table[23] = {
2, 3, 4, 5, 6, 8, 10, 12, 16, 20, 24, 32, 40,
56, 64, 96, 128, 192, 256, 384, 512, 640, 768
@@ -134,8 +163,57 @@ const uint32_t SPISettings::ctar_clock_table[23] = {
SPI_CTAR_PBR(2) | SPI_CTAR_BR(7) | SPI_CTAR_CSSCK(6),
SPI_CTAR_PBR(1) | SPI_CTAR_BR(8) | SPI_CTAR_CSSCK(7)
};
#endif

static void updateCTAR(uint32_t ctar)
{
if (SPI0_CTAR0 != ctar) {
uint32_t mcr = SPI0_MCR;
if (mcr & SPI_MCR_MDIS) {
SPI0_CTAR0 = ctar;
SPI0_CTAR1 = ctar | SPI_CTAR_FMSZ(8);
} else {
SPI0_MCR = SPI_MCR_MDIS | SPI_MCR_HALT | SPI_MCR_PCSIS(0x1F);
SPI0_CTAR0 = ctar;
SPI0_CTAR1 = ctar | SPI_CTAR_FMSZ(8);
SPI0_MCR = mcr;
}
}
}

void SPIClass::setBitOrder(uint8_t bitOrder)
{
SIM_SCGC6 |= SIM_SCGC6_SPI0;
uint32_t ctar = SPI0_CTAR0;
if (bitOrder == LSBFIRST) {
ctar |= SPI_CTAR_LSBFE;
} else {
ctar &= ~SPI_CTAR_LSBFE;
}
updateCTAR(ctar);
}

void SPIClass::setDataMode(uint8_t dataMode)
{
SIM_SCGC6 |= SIM_SCGC6_SPI0;

// TODO: implement with native code

SPCR = (SPCR & ~SPI_MODE_MASK) | dataMode;
}

void SPIClass::setClockDivider_noInline(uint32_t clk)
{
SIM_SCGC6 |= SIM_SCGC6_SPI0;
uint32_t ctar = SPI0_CTAR0;
ctar &= (SPI_CTAR_CPOL | SPI_CTAR_CPHA | SPI_CTAR_LSBFE);
if (ctar & SPI_CTAR_CPHA) {
clk = (clk & 0xFFFF0FFF) | ((clk & 0xF000) >> 4);
}
ctar |= clk;
updateCTAR(ctar);
}


#endif



+ 231
- 88
SPI.h 查看文件

@@ -16,20 +16,9 @@
#include <Arduino.h>

// SPI_HAS_TRANSACTION means SPI has beginTransaction(), endTransaction(),
// usingInterrupt(), and the actual clock speed names
// usingInterrupt(), and SPISetting(clock, bitOrder, dataMode)
#define SPI_HAS_TRANSACTION 1

// define SPI_AVR_EIMSK for AVR boards with external interrupt pins
#if defined(__AVR__)
#if defined(EIMSK)
#define SPI_AVR_EIMSK EIMSK
#elif defined(GICR)
#define SPI_AVR_EIMSK GICR
#elif defined(GIMSK)
#define SPI_AVR_EIMSK GIMSK
#endif
#endif

#ifndef LSBFIRST
#define LSBFIRST 0
#endif
@@ -42,11 +31,34 @@
#define SPI_MODE2 0x08
#define SPI_MODE3 0x0C

#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_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


/**********************************************************/
/* 8 bit AVR-based boards */
/**********************************************************/

#if defined(__AVR__)

// define SPI_AVR_EIMSK for AVR boards with external interrupt pins
#if defined(EIMSK)
#define SPI_AVR_EIMSK EIMSK
#elif defined(GICR)
#define SPI_AVR_EIMSK GICR
#elif defined(GIMSK)
#define SPI_AVR_EIMSK GIMSK
#endif

class SPISettings {
public:
SPISettings(uint32_t clock, uint8_t bitOrder, uint8_t dataMode) {
@@ -63,7 +75,6 @@ private:
void init_MightInline(uint32_t clock, uint8_t bitOrder, uint8_t dataMode) {
init_AlwaysInline(clock, bitOrder, dataMode);
}
#if defined(__AVR__)
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
@@ -128,20 +139,188 @@ private:
}
uint8_t spcr;
uint8_t spsr;
friend class SPIClass;
};



class SPIClass {
public:
// Initialize the SPI library
static void begin();

// If SPI is to used from within an interrupt, this function registers
// that interrupt with the SPI library, so beginTransaction() can
// prevent conflicts. The input interruptNumber is the number used
// with attachInterrupt. If SPI is used from a different interrupt
// (eg, a timer), interruptNumber should be 255.
static void usingInterrupt(uint8_t interruptNumber);

// 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(SPISettings settings) {
if (interruptMode > 0) {
#ifdef SPI_AVR_EIMSK
if (interruptMode == 1) {
interruptSave = SPI_AVR_EIMSK;
SPI_AVR_EIMSK &= ~interruptMask;
} else
#endif
{
interruptSave = SREG;
cli();
}
}
SPCR = settings.spcr;
SPSR = settings.spsr;
}

// Write to the SPI bus (MOSI pin) and also receive (MISO pin)
inline static uint8_t transfer(uint8_t data) {
SPDR = data;
asm volatile("nop");
while (!(SPSR & _BV(SPIF))) ; // wait
return SPDR;
}
inline static void transfer(void *buf, size_t count) {
if (count == 0) return;
uint8_t *p = (uint8_t *)buf;
SPDR = *p;
while (--count > 0) {
uint8_t out = *(p + 1);
while (!(SPSR & _BV(SPIF))) ;
uint8_t in = SPDR;
SPDR = out;
*p++ = in;
}
while (!(SPSR & _BV(SPIF))) ;
*p = SPDR;
}

// After performing a group of transfers and releasing the chip select
// signal, this function allows others to access the SPI bus
inline static void endTransaction(void) {
if (interruptMode > 0) {
#ifdef SPI_AVR_EIMSK
if (interruptMode == 1) {
SPI_AVR_EIMSK = interruptSave;
} else
#endif
{
SREG = interruptSave;
}
}
}

// Disable the SPI bus
static void end();

// This function is deprecated. New applications should use
// beginTransaction() to configure SPI settings.
inline static void setBitOrder(uint8_t bitOrder) {
if (bitOrder == LSBFIRST) SPCR |= _BV(DORD);
else SPCR &= ~(_BV(DORD));
}
// This function is deprecated. New applications should use
// beginTransaction() to configure SPI settings.
inline static void setDataMode(uint8_t dataMode) {
SPCR = (SPCR & ~SPI_MODE_MASK) | dataMode;
}
// This function is deprecated. New applications should use
// beginTransaction() to configure SPI settings.
inline static void setClockDivider(uint8_t clockDiv) {
SPCR = (SPCR & ~SPI_CLOCK_MASK) | (clockDiv & SPI_CLOCK_MASK);
SPSR = (SPSR & ~SPI_2XCLOCK_MASK) | ((clockDiv >> 2) & SPI_2XCLOCK_MASK);
}
// These undocumented functions should not be used. SPI.transfer()
// polls the hardware flag which is automatically cleared as the
// AVR responds to SPI's interrupt
inline static void attachInterrupt() { SPCR |= _BV(SPIE); }
inline static void detachInterrupt() { SPCR &= ~_BV(SPIE); }

private:
static uint8_t interruptMode; // 0=none, 1=mask, 2=global
static uint8_t interruptMask; // which interrupts to mask
static uint8_t interruptSave; // temp storage, to restore state
};

// mapping of interrupt numbers to bits within SPI_AVR_EIMSK
#if defined(__AVR_ATmega32U4__)
#define SPI_INT0_MASK (1<<INT0)
#define SPI_INT1_MASK (1<<INT1)
#define SPI_INT2_MASK (1<<INT2)
#define SPI_INT3_MASK (1<<INT3)
#define SPI_INT4_MASK (1<<INT6)
#elif defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB1286__)
#define SPI_INT0_MASK (1<<INT0)
#define SPI_INT1_MASK (1<<INT1)
#define SPI_INT2_MASK (1<<INT2)
#define SPI_INT3_MASK (1<<INT3)
#define SPI_INT4_MASK (1<<INT4)
#define SPI_INT5_MASK (1<<INT5)
#define SPI_INT6_MASK (1<<INT6)
#define SPI_INT7_MASK (1<<INT7)
#elif defined(EICRA) && defined(EICRB) && defined(EIMSK)
#define SPI_INT0_MASK (1<<INT4)
#define SPI_INT1_MASK (1<<INT5)
#define SPI_INT2_MASK (1<<INT0)
#define SPI_INT3_MASK (1<<INT1)
#define SPI_INT4_MASK (1<<INT2)
#define SPI_INT5_MASK (1<<INT3)
#define SPI_INT6_MASK (1<<INT6)
#define SPI_INT7_MASK (1<<INT7)
#else
#ifdef INT0
#define SPI_INT0_MASK (1<<INT0)
#endif
#ifdef INT1
#define SPI_INT1_MASK (1<<INT1)
#endif
#ifdef INT2
#define SPI_INT2_MASK (1<<INT2)
#endif
#endif


/**********************************************************/
/* 32 bit Teensy 3.0 and 3.1 */
/**********************************************************/

#elif defined(__arm__) && defined(TEENSYDUINO)

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);
}
}
SPISettings() {
init_AlwaysInline(4000000, MSBFIRST, SPI_MODE0);
}
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__)) {
uint32_t t, c = SPI_CTAR_FMSZ(7);
if (bitOrder == LSBFIRST) c |= SPI_CTAR_LSBFE;
if (__builtin_constant_p(clock)) {
if (clock >= F_BUS / 2) {
t = SPI_CTAR_PBR(0) | SPI_CTAR_BR(0) | SPI_CTAR_DBR | SPI_CTAR_CSSCK(0);
t = SPI_CTAR_PBR(0) | SPI_CTAR_BR(0) | SPI_CTAR_DBR
| SPI_CTAR_CSSCK(0);
} else if (clock >= F_BUS / 3) {
t = SPI_CTAR_PBR(1) | SPI_CTAR_BR(0) | SPI_CTAR_DBR | SPI_CTAR_CSSCK(0);
t = SPI_CTAR_PBR(1) | SPI_CTAR_BR(0) | SPI_CTAR_DBR
| SPI_CTAR_CSSCK(0);
} else if (clock >= F_BUS / 4) {
t = SPI_CTAR_PBR(0) | SPI_CTAR_BR(0) | SPI_CTAR_CSSCK(0);
} else if (clock >= F_BUS / 5) {
t = SPI_CTAR_PBR(2) | SPI_CTAR_BR(0) | SPI_CTAR_DBR | SPI_CTAR_CSSCK(0);
t = SPI_CTAR_PBR(2) | SPI_CTAR_BR(0) | SPI_CTAR_DBR
| SPI_CTAR_CSSCK(0);
} else if (clock >= F_BUS / 6) {
t = SPI_CTAR_PBR(1) | SPI_CTAR_BR(0) | SPI_CTAR_CSSCK(0);
} else if (clock >= F_BUS / 8) {
@@ -199,7 +378,6 @@ private:
static const uint16_t ctar_div_table[23];
static const uint32_t ctar_clock_table[23];
uint32_t ctar;
#endif
friend class SPIClass;
};

@@ -216,9 +394,7 @@ public:
// with attachInterrupt. If SPI is used from a different interrupt
// (eg, a timer), interruptNumber should be 255.
static void usingInterrupt(uint8_t interruptNumber);
#if defined(__arm__) && defined(TEENSYDUINO)
static void usingInterrupt(IRQ_NUMBER_t interruptName);
#endif

// Before using SPI.transfer() or asserting chip select pins,
// this function is used to gain exclusive access to the SPI bus
@@ -236,17 +412,12 @@ public:
cli();
}
}
#if defined(__AVR__)
SPCR = settings.spcr;
SPSR = settings.spsr;
#elif defined(__arm__) && defined(TEENSYDUINO)
if (SPI0_CTAR0 != settings.ctar) {
SPI0_MCR = SPI_MCR_MDIS | SPI_MCR_HALT | SPI_MCR_PCSIS(0x1F);
SPI0_CTAR0 = settings.ctar;
SPI0_CTAR1 = settings.ctar | SPI_CTAR_FMSZ(7);
SPI0_CTAR1 = settings.ctar| SPI_CTAR_FMSZ(8);
SPI0_MCR = SPI_MCR_MSTR | SPI_MCR_PCSIS(0x1F);
}
#endif
}

// Write to the SPI bus (MOSI pin) and also receive (MISO pin)
@@ -291,32 +462,49 @@ public:

// This function is deprecated. New applications should use
// beginTransaction() to configure SPI settings.
inline static void setBitOrder(uint8_t bitOrder) {
if (bitOrder == LSBFIRST) SPCR |= _BV(DORD);
else SPCR &= ~(_BV(DORD));
}
static void setBitOrder(uint8_t bitOrder);

// This function is deprecated. New applications should use
// beginTransaction() to configure SPI settings.
inline static void setDataMode(uint8_t dataMode) {
SPCR = (SPCR & ~SPI_MODE_MASK) | dataMode;
}
static void setDataMode(uint8_t dataMode);

// This function is deprecated. New applications should use
// beginTransaction() to configure SPI settings.
inline static void setClockDivider(uint8_t clockDiv) {
SPCR = (SPCR & ~SPI_CLOCK_MASK) | (clockDiv & SPI_CLOCK_MASK);
SPSR = (SPSR & ~SPI_2XCLOCK_MASK) | ((clockDiv >> 2) & SPI_2XCLOCK_MASK);
if (clockDiv == SPI_CLOCK_DIV2) {
setClockDivider_noInline(SPISettings(8000000, MSBFIRST, SPI_MODE0).ctar);
} else if (clockDiv == SPI_CLOCK_DIV4) {
setClockDivider_noInline(SPISettings(4000000, MSBFIRST, SPI_MODE0).ctar);
} else if (clockDiv == SPI_CLOCK_DIV8) {
setClockDivider_noInline(SPISettings(2000000, MSBFIRST, SPI_MODE0).ctar);
} else if (clockDiv == SPI_CLOCK_DIV16) {
setClockDivider_noInline(SPISettings(1000000, MSBFIRST, SPI_MODE0).ctar);
} else if (clockDiv == SPI_CLOCK_DIV32) {
setClockDivider_noInline(SPISettings(500000, MSBFIRST, SPI_MODE0).ctar);
} else if (clockDiv == SPI_CLOCK_DIV64) {
setClockDivider_noInline(SPISettings(250000, MSBFIRST, SPI_MODE0).ctar);
} else { /* clockDiv == SPI_CLOCK_DIV128 */
setClockDivider_noInline(SPISettings(125000, MSBFIRST, SPI_MODE0).ctar);
}
}
static void setClockDivider_noInline(uint32_t clk);

// These undocumented functions should not be used. SPI.transfer()
// polls the hardware flag which is automatically cleared as the
// AVR responds to SPI's interrupt
inline static void attachInterrupt() { SPCR |= _BV(SPIE); }
inline static void detachInterrupt() { SPCR &= ~_BV(SPIE); }
inline static void attachInterrupt() { }
inline static void detachInterrupt() { }

#if defined(__arm__) && defined(TEENSYDUINO)
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
// Teensy 3.x can use alternate pins for these 3 SPI signals.
inline static void setMOSI(uint8_t pin) __attribute__((always_inline)) {
SPCR.setMOSI(pin);
}
inline static void setMISO(uint8_t pin) __attribute__((always_inline)) {
SPCR.setMISO(pin);
}
inline static void setSCK(uint8_t pin) __attribute__((always_inline)) {
SPCR.setSCK(pin);
}

private:
static uint8_t interruptMode; // 0=none, 1=mask, 2=global
@@ -324,55 +512,10 @@ private:
static uint8_t interruptSave; // temp storage, to restore state
};

extern SPIClass SPI;
#endif


#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

// mapping of interrupt numbers to bits within SPI_AVR_EIMSK
#ifdef SPI_AVR_EIMSK
#if defined(__AVR_ATmega32U4__)
#define SPI_INT0_MASK (1<<INT0)
#define SPI_INT1_MASK (1<<INT1)
#define SPI_INT2_MASK (1<<INT2)
#define SPI_INT3_MASK (1<<INT3)
#define SPI_INT4_MASK (1<<INT6)
#elif defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB1286__)
#define SPI_INT0_MASK (1<<INT0)
#define SPI_INT1_MASK (1<<INT1)
#define SPI_INT2_MASK (1<<INT2)
#define SPI_INT3_MASK (1<<INT3)
#define SPI_INT4_MASK (1<<INT4)
#define SPI_INT5_MASK (1<<INT5)
#define SPI_INT6_MASK (1<<INT6)
#define SPI_INT7_MASK (1<<INT7)
#elif defined(EICRA) && defined(EICRB) && defined(EIMSK)
#define SPI_INT0_MASK (1<<INT4)
#define SPI_INT1_MASK (1<<INT5)
#define SPI_INT2_MASK (1<<INT0)
#define SPI_INT3_MASK (1<<INT1)
#define SPI_INT4_MASK (1<<INT2)
#define SPI_INT5_MASK (1<<INT3)
#define SPI_INT6_MASK (1<<INT6)
#define SPI_INT7_MASK (1<<INT7)
#else
#ifdef INT0
#define SPI_INT0_MASK (1<<INT0)
#endif
#ifdef INT1
#define SPI_INT1_MASK (1<<INT1)
#endif
#ifdef INT2
#define SPI_INT2_MASK (1<<INT2)
#endif
#endif
#endif //SPI_AVR_EIMSK

extern SPIClass SPI;

#endif

Loading…
取消
儲存