Browse Source

Use unified SPIClass for SPI1 & SPI2 on Teensy 3.5 & 3.6

main
PaulStoffregen 7 years ago
parent
commit
cad7201411
3 changed files with 8 additions and 822 deletions
  1. +5
    -440
      SPI.cpp
  2. +2
    -382
      SPI.h
  3. +1
    -0
      keywords.txt

+ 5
- 440
SPI.cpp View File

@@ -220,10 +220,9 @@ const SPIClass::SPI_Hardware_t SPIClass::spi2_hardware = {
2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0,
0x1, 0x2, 0x1, 0, 0, 0, 0, 0, 0, 0, 0
};
//SPIClass SPI((uintptr_t)&KINETISK_SPI0, SPIClass::spi0_hardware);
SPIClass SPI((uintptr_t)&KINETISK_SPI0, (uintptr_t)&SPIClass::spi0_hardware);
//SPIClass SPI1((uintptr_t)&KINETISK_SPI1, SPIClass::spi1_hardware);
//SPIClass SPI2((uintptr_t)&KINETISK_SPI2, SPIClass::spi2_hardware);
SPIClass SPI1((uintptr_t)&KINETISK_SPI1, (uintptr_t)&SPIClass::spi1_hardware);
SPIClass SPI2((uintptr_t)&KINETISK_SPI2, (uintptr_t)&SPIClass::spi2_hardware);
#endif


@@ -248,7 +247,6 @@ void SPIClass::end()
{
volatile uint32_t *reg;

//SPCR.disable_pins();
reg = portConfigRegister(hardware().mosi_pin[mosi_pin_index]);
*reg = 0;
reg = portConfigRegister(hardware().miso_pin[miso_pin_index]);
@@ -369,24 +367,6 @@ uint8_t SPIClass::pinIsChipSelect(uint8_t pin)
if (pin == hardware().cs_pin[i]) return hardware().cs_mask[i];
}
return 0;
/*
switch (pin) {
case 10: return 0x01; // PTC4
case 2: return 0x01; // PTD0
case 9: return 0x02; // PTC3
case 6: return 0x02; // PTD4
case 20: return 0x04; // PTD5
case 23: return 0x04; // PTC2
case 21: return 0x08; // PTD6
case 22: return 0x08; // PTC1
case 15: return 0x10; // PTC0
#if defined(__MK64FX512__) || defined(__MK66FX1M0__)
case 26: return 0x01;
case 45: return 0x20; // CS5
#endif
}
return 0;
*/
}

bool SPIClass::pinIsChipSelect(uint8_t pin1, uint8_t pin2)
@@ -410,24 +390,6 @@ uint8_t SPIClass::setCS(uint8_t pin)
}
}
return 0;
/*
switch (pin) {
case 10: CORE_PIN10_CONFIG = PORT_PCR_MUX(2); return 0x01; // PTC4
case 2: CORE_PIN2_CONFIG = PORT_PCR_MUX(2); return 0x01; // PTD0
case 9: CORE_PIN9_CONFIG = PORT_PCR_MUX(2); return 0x02; // PTC3
case 6: CORE_PIN6_CONFIG = PORT_PCR_MUX(2); return 0x02; // PTD4
case 20: CORE_PIN20_CONFIG = PORT_PCR_MUX(2); return 0x04; // PTD5
case 23: CORE_PIN23_CONFIG = PORT_PCR_MUX(2); return 0x04; // PTC2
case 21: CORE_PIN21_CONFIG = PORT_PCR_MUX(2); return 0x08; // PTD6
case 22: CORE_PIN22_CONFIG = PORT_PCR_MUX(2); return 0x08; // PTC1
case 15: CORE_PIN15_CONFIG = PORT_PCR_MUX(2); return 0x10; // PTC0
#if defined(__MK64FX512__) || defined(__MK66FX1M0__)
case 26: CORE_PIN26_CONFIG = PORT_PCR_MUX(2);return 0x01;
case 45: CORE_PIN45_CONFIG = PORT_PCR_MUX(3);return 0x20;
#endif
}
return 0;
*/
}

void SPIClass::setMOSI(uint8_t pin)
@@ -473,12 +435,11 @@ void SPIClass::transfer(void *buf, size_t count)
uint8_t *p_read = p_write;
size_t count_read = count;
bool lsbfirst = (port().CTAR0 & SPI_CTAR_LSBFE) ? true : false;
uint32_t sr, full_mask;

// Lets clear the reader queue
port().MCR = SPI_MCR_MSTR | SPI_MCR_CLR_RXF | SPI_MCR_PCSIS(0x1F);

uint32_t sr;

// Now lets loop while we still have data to output
if (count & 1) {
if (count > 1)
@@ -488,6 +449,7 @@ void SPIClass::transfer(void *buf, size_t count)
count--;
}

full_mask = (hardware().queue_size-1) << 12;
while (count > 0) {
// Push out the next byte;
uint16_t w = (*p_write++) << 8;
@@ -513,7 +475,7 @@ void SPIClass::transfer(void *buf, size_t count)
count_read -= 2;
}
}
} while ((sr & (15 << 12)) > (3 << 12));
} while ((sr & (15 << 12)) > full_mask);
}

// now lets wait for all of the read bytes to be returned...
@@ -535,403 +497,6 @@ void SPIClass::transfer(void *buf, size_t count)
}



/**********************************************************/
/* 32 bit Teensy-3.5/3.6 */
/**********************************************************/
#if defined(__MK64FX512__) || defined(__MK66FX1M0__)
SPI1Class SPI1;

uint8_t SPI1Class::interruptMasksUsed = 0;
uint32_t SPI1Class::interruptMask[(NVIC_NUM_INTERRUPTS+31)/32];
uint32_t SPI1Class::interruptSave[(NVIC_NUM_INTERRUPTS+31)/32];
#ifdef SPI_TRANSACTION_MISMATCH_LED
uint8_t SPI1Class::inTransactionFlag = 0;
#endif

void SPI1Class::begin()
{
SIM_SCGC6 |= SIM_SCGC6_SPI1;
SPI1_MCR = SPI_MCR_MDIS | SPI_MCR_HALT | SPI_MCR_PCSIS(0x1F);
SPI1_CTAR0 = SPI_CTAR_FMSZ(7) | SPI_CTAR_PBR(0) | SPI_CTAR_BR(1) | SPI_CTAR_CSSCK(1);
SPI1_CTAR1 = SPI_CTAR_FMSZ(15) | SPI_CTAR_PBR(0) | SPI_CTAR_BR(1) | SPI_CTAR_CSSCK(1);
SPI1_MCR = SPI_MCR_MSTR | SPI_MCR_PCSIS(0x1F);
SPCR1.enable_pins(); // pins managed by SPCRemulation in avr_emulation.h
}

void SPI1Class::end() {
SPCR1.disable_pins();
SPI1_MCR = SPI_MCR_MDIS | SPI_MCR_HALT | SPI_MCR_PCSIS(0x1F);
}

void SPI1Class::usingInterrupt(IRQ_NUMBER_t interruptName)
{
uint32_t n = (uint32_t)interruptName;

if (n >= NVIC_NUM_INTERRUPTS) return;

//Serial.print("usingInterrupt ");
//Serial.println(n);
interruptMasksUsed |= (1 << (n >> 5));
interruptMask[n >> 5] |= (1 << (n & 0x1F));
//Serial.printf("interruptMasksUsed = %d\n", interruptMasksUsed);
//Serial.printf("interruptMask[0] = %08X\n", interruptMask[0]);
//Serial.printf("interruptMask[1] = %08X\n", interruptMask[1]);
//Serial.printf("interruptMask[2] = %08X\n", interruptMask[2]);
}

void SPI1Class::notUsingInterrupt(IRQ_NUMBER_t interruptName)
{
uint32_t n = (uint32_t)interruptName;
if (n >= NVIC_NUM_INTERRUPTS) return;
interruptMask[n >> 5] &= ~(1 << (n & 0x1F));
if (interruptMask[n >> 5] == 0) {
interruptMasksUsed &= ~(1 << (n >> 5));
}
}


static void updateCTAR1(uint32_t ctar)
{
if (SPI1_CTAR0 != ctar) {
uint32_t mcr = SPI1_MCR;
if (mcr & SPI_MCR_MDIS) {
SPI1_CTAR0 = ctar;
SPI1_CTAR1 = ctar | SPI_CTAR_FMSZ(8);
} else {
SPI1_MCR = SPI_MCR_MDIS | SPI_MCR_HALT | SPI_MCR_PCSIS(0x1F);
SPI1_CTAR0 = ctar;
SPI1_CTAR1 = ctar | SPI_CTAR_FMSZ(8);
SPI1_MCR = mcr;
}
}
}

void SPI1Class::setBitOrder(uint8_t bitOrder)
{
SIM_SCGC6 |= SIM_SCGC6_SPI1;
uint32_t ctar = SPI1_CTAR0;
if (bitOrder == LSBFIRST) {
ctar |= SPI_CTAR_LSBFE;
} else {
ctar &= ~SPI_CTAR_LSBFE;
}
updateCTAR1(ctar);
}

void SPI1Class::setDataMode(uint8_t dataMode)
{
SIM_SCGC6 |= SIM_SCGC6_SPI1;

// TODO: implement with native code
SPCR1 = (SPCR1 & ~SPI_MODE_MASK) | dataMode;
}

void SPI1Class::setClockDivider_noInline(uint32_t clk)
{
SIM_SCGC6 |= SIM_SCGC6_SPI1;
uint32_t ctar = SPI1_CTAR0;
ctar &= (SPI_CTAR_CPOL | SPI_CTAR_CPHA | SPI_CTAR_LSBFE);
if (ctar & SPI_CTAR_CPHA) {
clk = (clk & 0xFFFF0FFF) | ((clk & 0xF000) >> 4);
}
ctar |= clk;
updateCTAR1(ctar);
}

uint8_t SPI1Class::pinIsChipSelect(uint8_t pin)
{
switch (pin) {
case 6: return 0x01; // CS0
case 31: return 0x01; // CS0
case 58: return 0x02; //CS1
case 62: return 0x01; //CS0
case 63: return 0x04; //CS2
}
return 0;
}

bool SPI1Class::pinIsChipSelect(uint8_t pin1, uint8_t pin2)
{
uint8_t pin1_mask, pin2_mask;
if ((pin1_mask = (uint8_t)pinIsChipSelect(pin1)) == 0) return false;
if ((pin2_mask = (uint8_t)pinIsChipSelect(pin2)) == 0) return false;
//Serial.printf("pinIsChipSelect %d %d %x %x\n\r", pin1, pin2, pin1_mask, pin2_mask);
if ((pin1_mask & pin2_mask) != 0) return false;
return true;
}

// setCS() is not intended for use from normal Arduino programs/sketches.
uint8_t SPI1Class::setCS(uint8_t pin)
{
switch (pin) {
case 6: CORE_PIN6_CONFIG = PORT_PCR_MUX(7); return 0x01; // PTD4
case 31: CORE_PIN31_CONFIG = PORT_PCR_MUX(2); return 0x01; // PTD5
case 58: CORE_PIN58_CONFIG = PORT_PCR_MUX(2); return 0x02; //CS1
case 62: CORE_PIN62_CONFIG = PORT_PCR_MUX(2); return 0x01; //CS0
case 63: CORE_PIN63_CONFIG = PORT_PCR_MUX(2); return 0x04; //CS2
}
return 0;
}

void SPI1Class::transfer(void *buf, size_t count)
{
if (count == 0) return;
uint8_t *p_write = (uint8_t *)buf;
uint8_t *p_read = p_write;
size_t count_read = count;
bool lsbfirst = (SPI1_CTAR0 & SPI_CTAR_LSBFE) ? true : false;

// Lets clear the reader queue
SPI1_MCR = SPI_MCR_MSTR | SPI_MCR_CLR_RXF | SPI_MCR_PCSIS(0x1F);

uint32_t sr;

// Now lets loop while we still have data to output
if (count & 1) {
KINETISK_SPI1.PUSHR = *p_write++ | SPI_PUSHR_CTAS(0);
count--;
}

while (count > 0) {
// Push out the next byte;
uint16_t w = (*p_write++) << 8;
w |= *p_write++;
if (lsbfirst) w = __builtin_bswap16(w);
KINETISK_SPI1.PUSHR = w | SPI_PUSHR_CTAS(1);
count -= 2; // how many bytes to output.
// Make sure queue is not full before pushing next byte out
do {
sr = KINETISK_SPI1.SR;
if (sr & 0xF0) {
uint16_t w = KINETISK_SPI1.POPR; // Read any pending RX bytes in
if (count_read & 1) {
*p_read++ = w; // Read any pending RX bytes in
count_read--;
} else {
if (lsbfirst) w = __builtin_bswap16(w);
*p_read++ = w >> 8;
*p_read++ = (w & 0xff);
count_read -= 2;
}
}
} while ((sr & (15 << 12)) > (0 << 12)); // SPI1 and 2 only have 1 item queue
}

// now lets wait for all of the read bytes to be returned...
while (count_read) {
sr = KINETISK_SPI1.SR;
if (sr & 0xF0) {
uint16_t w = KINETISK_SPI1.POPR; // Read any pending RX bytes in
if (count_read & 1) {
*p_read++ = w; // Read any pending RX bytes in
count_read--;
} else {
if (lsbfirst) w = __builtin_bswap16(w);
*p_read++ = w >> 8;
*p_read++ = (w & 0xff);
count_read -= 2;
}
}
}
}

// SPI2 Class
SPI2Class SPI2;

uint8_t SPI2Class::interruptMasksUsed = 0;
uint32_t SPI2Class::interruptMask[(NVIC_NUM_INTERRUPTS+31)/32];
uint32_t SPI2Class::interruptSave[(NVIC_NUM_INTERRUPTS+31)/32];
#ifdef SPI_TRANSACTION_MISMATCH_LED
uint8_t SPI2Class::inTransactionFlag = 0;
#endif

void SPI2Class::begin()
{
SIM_SCGC3 |= SIM_SCGC3_SPI2;
SPI2_MCR = SPI_MCR_MDIS | SPI_MCR_HALT | SPI_MCR_PCSIS(0x1F);
SPI2_CTAR0 = SPI_CTAR_FMSZ(7) | SPI_CTAR_PBR(0) | SPI_CTAR_BR(1) | SPI_CTAR_CSSCK(1);
SPI2_CTAR1 = SPI_CTAR_FMSZ(15) | SPI_CTAR_PBR(0) | SPI_CTAR_BR(1) | SPI_CTAR_CSSCK(1);
SPI2_MCR = SPI_MCR_MSTR | SPI_MCR_PCSIS(0x1F);
SPCR2.enable_pins(); // pins managed by SPCRemulation in avr_emulation.h
}

void SPI2Class::end() {
SPCR2.disable_pins();
SPI2_MCR = SPI_MCR_MDIS | SPI_MCR_HALT | SPI_MCR_PCSIS(0x1F);
}

void SPI2Class::usingInterrupt(IRQ_NUMBER_t interruptName)
{
uint32_t n = (uint32_t)interruptName;

if (n >= NVIC_NUM_INTERRUPTS) return;

//Serial.print("usingInterrupt ");
//Serial.println(n);
interruptMasksUsed |= (1 << (n >> 5));
interruptMask[n >> 5] |= (1 << (n & 0x1F));
//Serial.printf("interruptMasksUsed = %d\n", interruptMasksUsed);
//Serial.printf("interruptMask[0] = %08X\n", interruptMask[0]);
//Serial.printf("interruptMask[1] = %08X\n", interruptMask[1]);
//Serial.printf("interruptMask[2] = %08X\n", interruptMask[2]);
}

void SPI2Class::notUsingInterrupt(IRQ_NUMBER_t interruptName)
{
uint32_t n = (uint32_t)interruptName;
if (n >= NVIC_NUM_INTERRUPTS) return;
interruptMask[n >> 5] &= ~(1 << (n & 0x1F));
if (interruptMask[n >> 5] == 0) {
interruptMasksUsed &= ~(1 << (n >> 5));
}
}


static void updateCTAR2(uint32_t ctar)
{
if (SPI2_CTAR0 != ctar) {
uint32_t mcr = SPI2_MCR;
if (mcr & SPI_MCR_MDIS) {
SPI2_CTAR0 = ctar;
SPI2_CTAR1 = ctar | SPI_CTAR_FMSZ(8);
} else {
SPI2_MCR = SPI_MCR_MDIS | SPI_MCR_HALT | SPI_MCR_PCSIS(0x1F);
SPI2_CTAR0 = ctar;
SPI2_CTAR1 = ctar | SPI_CTAR_FMSZ(8);
SPI2_MCR = mcr;
}
}
}

void SPI2Class::setBitOrder(uint8_t bitOrder)
{
SIM_SCGC3 |= SIM_SCGC3_SPI2;
uint32_t ctar = SPI2_CTAR0;
if (bitOrder == LSBFIRST) {
ctar |= SPI_CTAR_LSBFE;
} else {
ctar &= ~SPI_CTAR_LSBFE;
}
updateCTAR2(ctar);
}

void SPI2Class::setDataMode(uint8_t dataMode)
{
SIM_SCGC3 |= SIM_SCGC3_SPI2;

// TODO: implement with native code
SPCR2 = (SPCR2 & ~SPI_MODE_MASK) | dataMode;
}

void SPI2Class::setClockDivider_noInline(uint32_t clk)
{
SIM_SCGC3 |= SIM_SCGC3_SPI2;
uint32_t ctar = SPI2_CTAR0;
ctar &= (SPI_CTAR_CPOL | SPI_CTAR_CPHA | SPI_CTAR_LSBFE);
if (ctar & SPI_CTAR_CPHA) {
clk = (clk & 0xFFFF0FFF) | ((clk & 0xF000) >> 4);
}
ctar |= clk;
updateCTAR2(ctar);
}

uint8_t SPI2Class::pinIsChipSelect(uint8_t pin)
{
switch (pin) {
case 43: return 0x01; // CS0
case 54: return 0x02; // CS1
case 55: return 0x01; // CS0
}
return 0;
}

bool SPI2Class::pinIsChipSelect(uint8_t pin1, uint8_t pin2)
{
uint8_t pin1_mask, pin2_mask;
if ((pin1_mask = (uint8_t)pinIsChipSelect(pin1)) == 0) return false;
if ((pin2_mask = (uint8_t)pinIsChipSelect(pin2)) == 0) return false;
//Serial.printf("pinIsChipSelect %d %d %x %x\n\r", pin1, pin2, pin1_mask, pin2_mask);
if ((pin1_mask & pin2_mask) != 0) return false;
return true;
}

// setCS() is not intended for use from normal Arduino programs/sketches.
uint8_t SPI2Class::setCS(uint8_t pin)
{
switch (pin) {
case 43: CORE_PIN43_CONFIG = PORT_PCR_MUX(2); return 0x01; // CS0
case 54: CORE_PIN54_CONFIG = PORT_PCR_MUX(2); return 0x02; // CS1
case 55: CORE_PIN55_CONFIG = PORT_PCR_MUX(2); return 0x01; // CS0
}
return 0;
}

void SPI2Class::transfer(void *buf, size_t count)
{
if (count == 0) return;
uint8_t *p_write = (uint8_t *)buf;
uint8_t *p_read = p_write;
size_t count_read = count;
bool lsbfirst = (SPI2_CTAR0 & SPI_CTAR_LSBFE) ? true : false;

// Lets clear the reader queue
SPI2_MCR = SPI_MCR_MSTR | SPI_MCR_CLR_RXF | SPI_MCR_PCSIS(0x1F);

uint32_t sr;

// Now lets loop while we still have data to output
if (count & 1) {
KINETISK_SPI2.PUSHR = *p_write++ | SPI_PUSHR_CTAS(0);
count--;
}

while (count > 0) {
// Push out the next byte;
uint16_t w = (*p_write++) << 8;
w |= *p_write++;
if (lsbfirst) w = __builtin_bswap16(w);
KINETISK_SPI2.PUSHR = w | SPI_PUSHR_CTAS(1);
count -= 2; // how many bytes to output.
// Make sure queue is not full before pushing next byte out
do {
sr = KINETISK_SPI2.SR;
if (sr & 0xF0) {
uint16_t w = KINETISK_SPI2.POPR; // Read any pending RX bytes in
if (count_read & 1) {
*p_read++ = w; // Read any pending RX bytes in
count_read--;
} else {
if (lsbfirst) w = __builtin_bswap16(w);
*p_read++ = w >> 8;
*p_read++ = (w & 0xff);
count_read -= 2;
}
}
} while ((sr & (15 << 12)) > (0 << 12)); // SPI2 and 2 only have 1 item queue
}

// now lets wait for all of the read bytes to be returned...
while (count_read) {
sr = KINETISK_SPI2.SR;
if (sr & 0xF0) {
uint16_t w = KINETISK_SPI2.POPR; // Read any pending RX bytes in
if (count_read & 1) {
*p_read++ = w; // Read any pending RX bytes in
count_read--;
} else {
if (lsbfirst) w = __builtin_bswap16(w);
*p_read++ = w >> 8;
*p_read++ = (w & 0xff);
count_read -= 2;
}
}
}
}


#endif

/**********************************************************/
/* 32 bit Teensy-LC */
/**********************************************************/

+ 2
- 382
SPI.h View File

@@ -629,386 +629,6 @@ private:
};


/**********************************************************/
/* Teensy 3.5 and 3.6 have SPI1 as well */
/**********************************************************/
#if defined(__MK64FX512__) || defined(__MK66FX1M0__)
class SPI1Class {
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 n) {
if (n == 3 || n == 4 || n == 24 || n == 33) {
usingInterrupt(IRQ_PORTA);
} else if (n == 0 || n == 1 || (n >= 16 && n <= 19) || n == 25 || n == 32) {
usingInterrupt(IRQ_PORTB);
} else if ((n >= 9 && n <= 13) || n == 15 || n == 22 || n == 23
|| (n >= 27 && n <= 30)) {
usingInterrupt(IRQ_PORTC);
} else if (n == 2 || (n >= 5 && n <= 8) || n == 14 || n == 20 || n == 21) {
usingInterrupt(IRQ_PORTD);
} else if (n == 26 || n == 31) {
usingInterrupt(IRQ_PORTE);
}
}
static void usingInterrupt(IRQ_NUMBER_t interruptName);
static void notUsingInterrupt(IRQ_NUMBER_t interruptName);

// 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 (interruptMasksUsed) {
__disable_irq();
if (interruptMasksUsed & 0x01) {
interruptSave[0] = NVIC_ICER0 & interruptMask[0];
NVIC_ICER0 = interruptSave[0];
}
#if NVIC_NUM_INTERRUPTS > 32
if (interruptMasksUsed & 0x02) {
interruptSave[1] = NVIC_ICER1 & interruptMask[1];
NVIC_ICER1 = interruptSave[1];
}
#endif
#if NVIC_NUM_INTERRUPTS > 64 && defined(NVIC_ISER2)
if (interruptMasksUsed & 0x04) {
interruptSave[2] = NVIC_ICER2 & interruptMask[2];
NVIC_ICER2 = interruptSave[2];
}
#endif
#if NVIC_NUM_INTERRUPTS > 96 && defined(NVIC_ISER3)
if (interruptMasksUsed & 0x08) {
interruptSave[3] = NVIC_ICER3 & interruptMask[3];
NVIC_ICER3 = interruptSave[3];
}
#endif
__enable_irq();
}
#ifdef SPI_TRANSACTION_MISMATCH_LED
if (inTransactionFlag) {
pinMode(SPI_TRANSACTION_MISMATCH_LED, OUTPUT);
digitalWrite(SPI_TRANSACTION_MISMATCH_LED, HIGH);
}
inTransactionFlag = 1;
#endif
if (SPI1_CTAR0 != settings.ctar) {
SPI1_MCR = SPI_MCR_MDIS | SPI_MCR_HALT | SPI_MCR_PCSIS(0x1F);
SPI1_CTAR0 = settings.ctar;
SPI1_CTAR1 = settings.ctar| SPI_CTAR_FMSZ(8);
SPI1_MCR = SPI_MCR_MSTR | SPI_MCR_PCSIS(0x1F);
}
}

// Write to the SPI bus (MOSI pin) and also receive (MISO pin)
inline static uint8_t transfer(uint8_t data) {
SPI1_SR = SPI_SR_TCF;
SPI1_PUSHR = data;
while (!(SPI1_SR & SPI_SR_TCF)) ; // wait
return SPI1_POPR;
}
inline static uint16_t transfer16(uint16_t data) {
SPI1_SR = SPI_SR_TCF;
SPI1_PUSHR = data | SPI_PUSHR_CTAS(1);
while (!(SPI1_SR & SPI_SR_TCF)) ; // wait
return SPI1_POPR;
}
static void transfer(void *buf, size_t count);
// 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) {
#ifdef SPI_TRANSACTION_MISMATCH_LED
if (!inTransactionFlag) {
pinMode(SPI_TRANSACTION_MISMATCH_LED, OUTPUT);
digitalWrite(SPI_TRANSACTION_MISMATCH_LED, HIGH);
}
inTransactionFlag = 0;
#endif
if (interruptMasksUsed) {
if (interruptMasksUsed & 0x01) {
NVIC_ISER0 = interruptSave[0];
}
#if NVIC_NUM_INTERRUPTS > 32
if (interruptMasksUsed & 0x02) {
NVIC_ISER1 = interruptSave[1];
}
#endif
#if NVIC_NUM_INTERRUPTS > 64 && defined(NVIC_ISER2)
if (interruptMasksUsed & 0x04) {
NVIC_ISER2 = interruptSave[2];
}
#endif
#if NVIC_NUM_INTERRUPTS > 96 && defined(NVIC_ISER3)
if (interruptMasksUsed & 0x08) {
NVIC_ISER3 = interruptSave[3];
}
#endif
}
}

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

// This function is deprecated. New applications should use
// beginTransaction() to configure SPI settings.
static void setBitOrder(uint8_t bitOrder);

// This function is deprecated. New applications should use
// beginTransaction() to configure SPI settings.
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) {
if (clockDiv == SPI_CLOCK_DIV2) {
setClockDivider_noInline(SPISettings(12000000, 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() { }
inline static void detachInterrupt() { }

// Teensy 3.x can use alternate pins for these 3 SPI signals.
inline static void setMOSI(uint8_t pin) __attribute__((always_inline)) {
SPCR1.setMOSI(pin);
}
inline static void setMISO(uint8_t pin) __attribute__((always_inline)) {
SPCR1.setMISO(pin);
}
inline static void setSCK(uint8_t pin) __attribute__((always_inline)) {
SPCR1.setSCK(pin);
}
// return true if "pin" has special chip select capability
static uint8_t pinIsChipSelect(uint8_t pin);
// return true if both pin1 and pin2 have independent chip select capability
static bool pinIsChipSelect(uint8_t pin1, uint8_t pin2);
// configure a pin for chip select and return its SPI_MCR_PCSIS bitmask
// setCS() is a special function, not intended for use from normal Arduino
// programs/sketches. See the ILI3941_t3 library for an example.
static uint8_t setCS(uint8_t pin);

private:
static uint8_t interruptMasksUsed;
static uint32_t interruptMask[(NVIC_NUM_INTERRUPTS+31)/32];
static uint32_t interruptSave[(NVIC_NUM_INTERRUPTS+31)/32];
#ifdef SPI_TRANSACTION_MISMATCH_LED
static uint8_t inTransactionFlag;
#endif
};
class SPI2Class {
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 n) {
if (n == 3 || n == 4 || n == 24 || n == 33) {
usingInterrupt(IRQ_PORTA);
} else if (n == 0 || n == 1 || (n >= 16 && n <= 19) || n == 25 || n == 32) {
usingInterrupt(IRQ_PORTB);
} else if ((n >= 9 && n <= 13) || n == 15 || n == 22 || n == 23
|| (n >= 27 && n <= 30)) {
usingInterrupt(IRQ_PORTC);
} else if (n == 2 || (n >= 5 && n <= 8) || n == 14 || n == 20 || n == 21) {
usingInterrupt(IRQ_PORTD);
} else if (n == 26 || n == 31) {
usingInterrupt(IRQ_PORTE);
}
}
static void usingInterrupt(IRQ_NUMBER_t interruptName);
static void notUsingInterrupt(IRQ_NUMBER_t interruptName);

// 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 (interruptMasksUsed) {
__disable_irq();
if (interruptMasksUsed & 0x01) {
interruptSave[0] = NVIC_ICER0 & interruptMask[0];
NVIC_ICER0 = interruptSave[0];
}
#if NVIC_NUM_INTERRUPTS > 32
if (interruptMasksUsed & 0x02) {
interruptSave[1] = NVIC_ICER1 & interruptMask[1];
NVIC_ICER1 = interruptSave[1];
}
#endif
#if NVIC_NUM_INTERRUPTS > 64 && defined(NVIC_ISER2)
if (interruptMasksUsed & 0x04) {
interruptSave[2] = NVIC_ICER2 & interruptMask[2];
NVIC_ICER2 = interruptSave[2];
}
#endif
#if NVIC_NUM_INTERRUPTS > 96 && defined(NVIC_ISER3)
if (interruptMasksUsed & 0x08) {
interruptSave[3] = NVIC_ICER3 & interruptMask[3];
NVIC_ICER3 = interruptSave[3];
}
#endif
__enable_irq();
}
#ifdef SPI_TRANSACTION_MISMATCH_LED
if (inTransactionFlag) {
pinMode(SPI_TRANSACTION_MISMATCH_LED, OUTPUT);
digitalWrite(SPI_TRANSACTION_MISMATCH_LED, HIGH);
}
inTransactionFlag = 1;
#endif
if (SPI2_CTAR0 != settings.ctar) {
SPI2_MCR = SPI_MCR_MDIS | SPI_MCR_HALT | SPI_MCR_PCSIS(0x1F);
SPI2_CTAR0 = settings.ctar;
SPI2_CTAR1 = settings.ctar| SPI_CTAR_FMSZ(8);
SPI2_MCR = SPI_MCR_MSTR | SPI_MCR_PCSIS(0x1F);
}
}

// Write to the SPI bus (MOSI pin) and also receive (MISO pin)
inline static uint8_t transfer(uint8_t data) {
SPI2_SR = SPI_SR_TCF;
SPI2_PUSHR = data;
while (!(SPI2_SR & SPI_SR_TCF)) ; // wait
return SPI2_POPR;
}
inline static uint16_t transfer16(uint16_t data) {
SPI2_SR = SPI_SR_TCF;
SPI2_PUSHR = data | SPI_PUSHR_CTAS(1);
while (!(SPI2_SR & SPI_SR_TCF)) ; // wait
return SPI2_POPR;
}
static void transfer(void *buf, size_t count);

// 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) {
#ifdef SPI_TRANSACTION_MISMATCH_LED
if (!inTransactionFlag) {
pinMode(SPI_TRANSACTION_MISMATCH_LED, OUTPUT);
digitalWrite(SPI_TRANSACTION_MISMATCH_LED, HIGH);
}
inTransactionFlag = 0;
#endif
if (interruptMasksUsed) {
if (interruptMasksUsed & 0x01) {
NVIC_ISER0 = interruptSave[0];
}
#if NVIC_NUM_INTERRUPTS > 32
if (interruptMasksUsed & 0x02) {
NVIC_ISER1 = interruptSave[1];
}
#endif
#if NVIC_NUM_INTERRUPTS > 64 && defined(NVIC_ISER2)
if (interruptMasksUsed & 0x04) {
NVIC_ISER2 = interruptSave[2];
}
#endif
#if NVIC_NUM_INTERRUPTS > 96 && defined(NVIC_ISER3)
if (interruptMasksUsed & 0x08) {
NVIC_ISER3 = interruptSave[3];
}
#endif
}
}

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

// This function is deprecated. New applications should use
// beginTransaction() to configure SPI settings.
static void setBitOrder(uint8_t bitOrder);

// This function is deprecated. New applications should use
// beginTransaction() to configure SPI settings.
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) {
if (clockDiv == SPI_CLOCK_DIV2) {
setClockDivider_noInline(SPISettings(12000000, 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() { }
inline static void detachInterrupt() { }

// Teensy 3.x can use alternate pins for these 3 SPI signals.
inline static void setMOSI(uint8_t pin) __attribute__((always_inline)) {
SPCR2.setMOSI(pin);
}
inline static void setMISO(uint8_t pin) __attribute__((always_inline)) {
SPCR2.setMISO(pin);
}
inline static void setSCK(uint8_t pin) __attribute__((always_inline)) {
SPCR2.setSCK(pin);
}
// return true if "pin" has special chip select capability
static uint8_t pinIsChipSelect(uint8_t pin);
// return true if both pin1 and pin2 have independent chip select capability
static bool pinIsChipSelect(uint8_t pin1, uint8_t pin2);
// configure a pin for chip select and return its SPI_MCR_PCSIS bitmask
// setCS() is a special function, not intended for use from normal Arduino
// programs/sketches. See the ILI3941_t3 library for an example.
static uint8_t setCS(uint8_t pin);

private:
static uint8_t interruptMasksUsed;
static uint32_t interruptMask[(NVIC_NUM_INTERRUPTS+31)/32];
static uint32_t interruptSave[(NVIC_NUM_INTERRUPTS+31)/32];
#ifdef SPI_TRANSACTION_MISMATCH_LED
static uint8_t inTransactionFlag;
#endif
};
#endif









/**********************************************************/
/* 32 bit Teensy-LC */
@@ -1500,7 +1120,7 @@ extern SPIClass SPI;
extern SPI1Class SPI1;
#endif
#if defined(__MK64FX512__) || defined(__MK66FX1M0__)
extern SPI1Class SPI1;
extern SPI2Class SPI2;
extern SPIClass SPI1;
extern SPIClass SPI2;
#endif
#endif

+ 1
- 0
keywords.txt View File

@@ -16,6 +16,7 @@ SPI2 KEYWORD1
begin KEYWORD2
end KEYWORD2
transfer KEYWORD2
transfer16 KEYWORD2
setBitOrder KEYWORD2
setDataMode KEYWORD2
setClockDivider KEYWORD2

Loading…
Cancel
Save