Browse Source

Add Arduino Due code

main
PaulStoffregen 10 years ago
parent
commit
68a0138a8a
2 changed files with 337 additions and 39 deletions
  1. +236
    -27
      SPI.cpp
  2. +101
    -12
      SPI.h

+ 236
- 27
SPI.cpp View File

#include "SPI.h" #include "SPI.h"
#include "pins_arduino.h" #include "pins_arduino.h"


SPIClass SPI;




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


#if defined(__AVR__) #if defined(__AVR__)


SPIClass SPI;

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


// mapping of interrupt numbers to bits within SPI_AVR_EIMSK // mapping of interrupt numbers to bits within SPI_AVR_EIMSK
#if defined(__AVR_ATmega32U4__) #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)
#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__) #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)
#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) #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)
#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 #else
#ifdef INT0 #ifdef INT0
#define SPI_INT0_MASK (1<<INT0)
#define SPI_INT0_MASK (1<<INT0)
#endif #endif
#ifdef INT1 #ifdef INT1
#define SPI_INT1_MASK (1<<INT1)
#define SPI_INT1_MASK (1<<INT1)
#endif #endif
#ifdef INT2 #ifdef INT2
#define SPI_INT2_MASK (1<<INT2)
#define SPI_INT2_MASK (1<<INT2)
#endif #endif
#endif #endif






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


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


SPIClass SPI;

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




/**********************************************************/
/* 32 bit Arduino Due */
/**********************************************************/

#elif defined(__arm__) && defined(__SAM3X8E__)

#include "SPI.h"

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

SPIClass::SPIClass(Spi *_spi, uint32_t _id, void(*_initCb)(void)) :
spi(_spi), id(_id), initCb(_initCb), initialized(false)
{
// Empty
}

void SPIClass::begin() {
init();

// NPCS control is left to the user

// Default speed set to 4Mhz
setClockDivider(BOARD_SPI_DEFAULT_SS, 21);
setDataMode(BOARD_SPI_DEFAULT_SS, SPI_MODE0);
setBitOrder(BOARD_SPI_DEFAULT_SS, MSBFIRST);
}

void SPIClass::begin(uint8_t _pin) {
init();

uint32_t spiPin = BOARD_PIN_TO_SPI_PIN(_pin);
PIO_Configure(
g_APinDescription[spiPin].pPort,
g_APinDescription[spiPin].ulPinType,
g_APinDescription[spiPin].ulPin,
g_APinDescription[spiPin].ulPinConfiguration);

// Default speed set to 4Mhz
setClockDivider(_pin, 21);
setDataMode(_pin, SPI_MODE0);
setBitOrder(_pin, MSBFIRST);
}

void SPIClass::init() {
if (initialized)
return;
initCb();
SPI_Configure(spi, id, SPI_MR_MSTR | SPI_MR_PS | SPI_MR_MODFDIS);
SPI_Enable(spi);
initialized = true;
}

void SPIClass::usingInterrupt(uint8_t interruptNumber)
{
uint8_t irestore;

irestore = interruptsStatus();
noInterrupts();
if (interruptMode < 2) {
if (interruptNumber > NUM_DIGITAL_PINS) {
interruptMode = 2;
} else {
uint8_t imask = interruptMask;
Pio *pio = g_APinDescription[interruptNumber].pPort;
if (pio == PIOA) {
imask |= 1;
} else if (pio == PIOB) {
imask |= 2;
} else if (pio == PIOC) {
imask |= 4;
} else if (pio == PIOD) {
imask |= 8;
}
interruptMask = imask;
interruptMode = 1;
}
}
if (irestore) interrupts();
}

void SPIClass::beginTransaction(uint8_t clockDiv, BitOrder bitOrder, uint8_t dataMode)
{
if (interruptMode > 0) {
if (interruptMode == 1) {
uint8_t imask = interruptMask;
if (imask & 1) NVIC_DisableIRQ(PIOA_IRQn);
if (imask & 2) NVIC_DisableIRQ(PIOB_IRQn);
if (imask & 4) NVIC_DisableIRQ(PIOC_IRQn);
if (imask & 8) NVIC_DisableIRQ(PIOD_IRQn);
} else {
interruptSave = interruptsStatus();
noInterrupts();
}
}
setClockDivider(BOARD_SPI_DEFAULT_SS, clockDiv);
setDataMode(BOARD_SPI_DEFAULT_SS, dataMode);
setBitOrder(BOARD_SPI_DEFAULT_SS, bitOrder);
}

void SPIClass::endTransaction(void)
{
if (interruptMode > 0) {
if (interruptMode == 1) {
uint8_t imask = interruptMask;
if (imask & 1) NVIC_EnableIRQ(PIOA_IRQn);
if (imask & 2) NVIC_EnableIRQ(PIOB_IRQn);
if (imask & 4) NVIC_EnableIRQ(PIOC_IRQn);
if (imask & 8) NVIC_EnableIRQ(PIOD_IRQn);
} else {
if (interruptSave) interrupts();
}
}
}

void SPIClass::end(uint8_t _pin) {
uint32_t spiPin = BOARD_PIN_TO_SPI_PIN(_pin);
// Setting the pin as INPUT will disconnect it from SPI peripheral
pinMode(spiPin, INPUT);
}

void SPIClass::end() {
SPI_Disable(spi);
initialized = false;
}

void SPIClass::setBitOrder(uint8_t _pin, BitOrder _bitOrder) {
uint32_t ch = BOARD_PIN_TO_SPI_CHANNEL(_pin);
bitOrder[ch] = _bitOrder;
}

void SPIClass::setDataMode(uint8_t _pin, uint8_t _mode) {
uint32_t ch = BOARD_PIN_TO_SPI_CHANNEL(_pin);
mode[ch] = _mode | SPI_CSR_CSAAT;
// SPI_CSR_DLYBCT(1) keeps CS enabled for 32 MCLK after a completed
// transfer. Some device needs that for working properly.
SPI_ConfigureNPCS(spi, ch, mode[ch] | SPI_CSR_SCBR(divider[ch]) | SPI_CSR_DLYBCT(1));
}

void SPIClass::setClockDivider(uint8_t _pin, uint8_t _divider) {
uint32_t ch = BOARD_PIN_TO_SPI_CHANNEL(_pin);
divider[ch] = _divider;
// SPI_CSR_DLYBCT(1) keeps CS enabled for 32 MCLK after a completed
// transfer. Some device needs that for working properly.
SPI_ConfigureNPCS(spi, ch, mode[ch] | SPI_CSR_SCBR(divider[ch]) | SPI_CSR_DLYBCT(1));
}

byte SPIClass::transfer(byte _pin, uint8_t _data, SPITransferMode _mode) {
uint32_t ch = BOARD_PIN_TO_SPI_CHANNEL(_pin);
// Reverse bit order
if (bitOrder[ch] == LSBFIRST)
_data = __REV(__RBIT(_data));
uint32_t d = _data | SPI_PCS(ch);
if (_mode == SPI_LAST)
d |= SPI_TDR_LASTXFER;

// SPI_Write(spi, _channel, _data);
while ((spi->SPI_SR & SPI_SR_TDRE) == 0)
;
spi->SPI_TDR = d;

// return SPI_Read(spi);
while ((spi->SPI_SR & SPI_SR_RDRF) == 0)
;
d = spi->SPI_RDR;
// Reverse bit order
if (bitOrder[ch] == LSBFIRST)
d = __REV(__RBIT(d));
return d & 0xFF;
}

void SPIClass::attachInterrupt(void) {
// Should be enableInterrupt()
}

void SPIClass::detachInterrupt(void) {
// Should be disableInterrupt()
}

#if SPI_INTERFACES_COUNT > 0
static void SPI_0_Init(void) {
PIO_Configure(
g_APinDescription[PIN_SPI_MOSI].pPort,
g_APinDescription[PIN_SPI_MOSI].ulPinType,
g_APinDescription[PIN_SPI_MOSI].ulPin,
g_APinDescription[PIN_SPI_MOSI].ulPinConfiguration);
PIO_Configure(
g_APinDescription[PIN_SPI_MISO].pPort,
g_APinDescription[PIN_SPI_MISO].ulPinType,
g_APinDescription[PIN_SPI_MISO].ulPin,
g_APinDescription[PIN_SPI_MISO].ulPinConfiguration);
PIO_Configure(
g_APinDescription[PIN_SPI_SCK].pPort,
g_APinDescription[PIN_SPI_SCK].ulPinType,
g_APinDescription[PIN_SPI_SCK].ulPin,
g_APinDescription[PIN_SPI_SCK].ulPinConfiguration);
}

SPIClass SPI(SPI_INTERFACE, SPI_INTERFACE_ID, SPI_0_Init);
#endif





#endif #endif





+ 101
- 12
SPI.h View File





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


#if defined(__AVR__) #if defined(__AVR__)
// inverted, so the bits form increasing numbers. Also note that // inverted, so the bits form increasing numbers. Also note that
// fosc/64 appears twice // fosc/64 appears twice
// SPR1 SPR0 ~SPI2X Freq // 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
// 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 // We find the fastest clock that is less than or equal to the
// given clock rate. The clock divider that results in clock_setting // given clock rate. The clock divider that results in clock_setting




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


#elif defined(__arm__) && defined(TEENSYDUINO) #elif defined(__arm__) && defined(TEENSYDUINO)
uint32_t t, c = SPI_CTAR_FMSZ(7); uint32_t t, c = SPI_CTAR_FMSZ(7);
if (bitOrder == LSBFIRST) c |= SPI_CTAR_LSBFE; if (bitOrder == LSBFIRST) c |= SPI_CTAR_LSBFE;
if (__builtin_constant_p(clock)) { if (__builtin_constant_p(clock)) {
if (clock >= F_BUS / 2) {
if (clock >= F_BUS / 2) {
t = SPI_CTAR_PBR(0) | SPI_CTAR_BR(0) | SPI_CTAR_DBR t = SPI_CTAR_PBR(0) | SPI_CTAR_BR(0) | SPI_CTAR_DBR
| SPI_CTAR_CSSCK(0); | SPI_CTAR_CSSCK(0);
} else if (clock >= F_BUS / 3) { } else if (clock >= F_BUS / 3) {
t = SPI_CTAR_PBR(0) | SPI_CTAR_BR(8) | SPI_CTAR_CSSCK(7); t = SPI_CTAR_PBR(0) | SPI_CTAR_BR(8) | SPI_CTAR_CSSCK(7);
} else if (clock >= F_BUS / 640) { } else if (clock >= F_BUS / 640) {
t = SPI_CTAR_PBR(2) | SPI_CTAR_BR(7) | SPI_CTAR_CSSCK(6); t = SPI_CTAR_PBR(2) | SPI_CTAR_BR(7) | SPI_CTAR_CSSCK(6);
} else { /* F_BUS / 768 */
} else { /* F_BUS / 768 */
t = SPI_CTAR_PBR(1) | SPI_CTAR_BR(8) | SPI_CTAR_CSSCK(7); t = SPI_CTAR_PBR(1) | SPI_CTAR_BR(8) | SPI_CTAR_CSSCK(7);
} }
} else { } else {
static uint8_t interruptSave; // temp storage, to restore state static uint8_t interruptSave; // temp storage, to restore state
}; };



/**********************************************************/
/* 32 bit Arduino Due */
/**********************************************************/

#elif defined(__arm__) && defined(__SAM3X8E__)

#undef SPI_MODE0
#undef SPI_MODE1
#undef SPI_MODE2
#undef SPI_MODE3
#define SPI_MODE0 0x02
#define SPI_MODE1 0x00
#define SPI_MODE2 0x03
#define SPI_MODE3 0x01

#undef SPI_CLOCK_DIV2
#undef SPI_CLOCK_DIV4
#undef SPI_CLOCK_DIV8
#undef SPI_CLOCK_DIV16
#undef SPI_CLOCK_DIV32
#undef SPI_CLOCK_DIV64
#undef SPI_CLOCK_DIV128
#define SPI_CLOCK_DIV2 11
#define SPI_CLOCK_DIV4 21
#define SPI_CLOCK_DIV8 42
#define SPI_CLOCK_DIV16 84
#define SPI_CLOCK_DIV32 168
#define SPI_CLOCK_DIV64 255
#define SPI_CLOCK_DIV128 255

enum SPITransferMode {
SPI_CONTINUE,
SPI_LAST
};

class SPIClass {
public:
SPIClass(Spi *_spi, uint32_t _id, void(*_initCb)(void));

byte transfer(uint8_t _data, SPITransferMode _mode = SPI_LAST) { return transfer(BOARD_SPI_DEFAULT_SS, _data, _mode); }
byte transfer(byte _channel, uint8_t _data, SPITransferMode _mode = SPI_LAST);

// Transaction Functions
void usingInterrupt(uint8_t interruptNumber);
void beginTransaction(uint8_t clockDiv, BitOrder bitOrder, uint8_t dataMode);
void endTransaction(void);

// SPI Configuration methods
void attachInterrupt(void);
void detachInterrupt(void);

void begin(void);
void end(void);

// Attach/Detach pin to/from SPI controller
void begin(uint8_t _pin);
void end(uint8_t _pin);

// These methods sets a parameter on a single pin
void setBitOrder(uint8_t _pin, BitOrder);
void setDataMode(uint8_t _pin, uint8_t);
void setClockDivider(uint8_t _pin, uint8_t);

// These methods sets the same parameters but on default pin BOARD_SPI_DEFAULT_SS
void setBitOrder(BitOrder _order) { setBitOrder(BOARD_SPI_DEFAULT_SS, _order); };
void setDataMode(uint8_t _mode) { setDataMode(BOARD_SPI_DEFAULT_SS, _mode); };
void setClockDivider(uint8_t _div) { setClockDivider(BOARD_SPI_DEFAULT_SS, _div); };

private:
void init();

Spi *spi;
uint32_t id;
BitOrder bitOrder[SPI_CHANNELS_NUM];
uint32_t divider[SPI_CHANNELS_NUM];
uint32_t mode[SPI_CHANNELS_NUM];
void (*initCb)(void);
bool initialized;
static uint8_t interruptMode; // 0=none, 1=mask, 2=global
static uint8_t interruptMask; // bits 0:3=pin change
static uint8_t interruptSave; // temp storage, to restore state
};






#endif #endif





Loading…
Cancel
Save