@@ -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 */ | |||
/**********************************************************/ |
@@ -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 |
@@ -16,6 +16,7 @@ SPI2 KEYWORD1 | |||
begin KEYWORD2 | |||
end KEYWORD2 | |||
transfer KEYWORD2 | |||
transfer16 KEYWORD2 | |||
setBitOrder KEYWORD2 | |||
setDataMode KEYWORD2 | |||
setClockDivider KEYWORD2 |