| @@ -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 | |||