|
- /*
- * Copyright (c) 2010 by Cristian Maglie <c.maglie@bug.st>
- * SPI Master library for arduino.
- *
- * This file is free software; you can redistribute it and/or modify
- * it under the terms of either the GNU General Public License version 2
- * or the GNU Lesser General Public License version 2.1, both as
- * published by the Free Software Foundation.
- */
-
- #include "SPI.h"
- #include "pins_arduino.h"
-
- SPIClass SPI;
-
-
- /**********************************************************/
- /* 8 bit AVR-based boards */
- /**********************************************************/
-
- #if defined(__AVR__)
-
- uint8_t SPIClass::interruptMode = 0;
- uint8_t SPIClass::interruptMask = 0;
- uint8_t SPIClass::interruptSave = 0;
-
- void SPIClass::begin()
- {
- // Set SS to high so a connected chip will be "deselected" by default
- digitalWrite(SS, HIGH);
-
- // When the SS pin is set as OUTPUT, it can be used as
- // a general purpose output port (it doesn't influence
- // SPI operations).
- pinMode(SS, OUTPUT);
-
- // Warning: if the SS pin ever becomes a LOW INPUT then SPI
- // automatically switches to Slave, so the data direction of
- // the SS pin MUST be kept as OUTPUT.
- SPCR |= _BV(MSTR);
- SPCR |= _BV(SPE);
-
- // Set direction register for SCK and MOSI pin.
- // MISO pin automatically overrides to INPUT.
- // By doing this AFTER enabling SPI, we avoid accidentally
- // clocking in a single bit since the lines go directly
- // from "input" to SPI control.
- // http://code.google.com/p/arduino/issues/detail?id=888
- pinMode(SCK, OUTPUT);
- pinMode(MOSI, OUTPUT);
- }
-
- void SPIClass::end() {
- SPCR &= ~_BV(SPE);
- }
-
- void SPIClass::usingInterrupt(uint8_t interruptNumber)
- {
- uint8_t mask;
-
- if (interruptMode > 1) return;
-
- noInterrupts();
- switch (interruptNumber) {
- #ifdef SPI_INT0_MASK
- case 0: mask = SPI_INT0_MASK; break;
- #endif
- #ifdef SPI_INT1_MASK
- case 1: mask = SPI_INT1_MASK; break;
- #endif
- #ifdef SPI_INT2_MASK
- case 2: mask = SPI_INT2_MASK; break;
- #endif
- #ifdef SPI_INT3_MASK
- case 3: mask = SPI_INT3_MASK; break;
- #endif
- #ifdef SPI_INT4_MASK
- case 4: mask = SPI_INT4_MASK; break;
- #endif
- #ifdef SPI_INT5_MASK
- case 5: mask = SPI_INT5_MASK; break;
- #endif
- #ifdef SPI_INT6_MASK
- case 6: mask = SPI_INT6_MASK; break;
- #endif
- #ifdef SPI_INT7_MASK
- case 7: mask = SPI_INT7_MASK; break;
- #endif
- default:
- interruptMode = 2;
- interrupts();
- return;
- }
- interruptMode = 1;
- interruptMask |= mask;
- interrupts();
- }
-
-
- /**********************************************************/
- /* 32 bit Teensy 3.0 and 3.1 */
- /**********************************************************/
-
- #elif defined(__arm__) && defined(TEENSYDUINO)
-
- uint8_t SPIClass::interruptMode = 0;
- uint8_t SPIClass::interruptMask = 0;
- uint8_t SPIClass::interruptSave = 0;
-
- void SPIClass::begin()
- {
- SIM_SCGC6 |= SIM_SCGC6_SPI0;
- SPI0_MCR = SPI_MCR_MDIS | SPI_MCR_HALT | SPI_MCR_PCSIS(0x1F);
- SPI0_CTAR0 = SPI_CTAR_FMSZ(7) | SPI_CTAR_PBR(0) | SPI_CTAR_BR(1) | SPI_CTAR_CSSCK(1);
- SPI0_CTAR1 = SPI_CTAR_FMSZ(15) | SPI_CTAR_PBR(0) | SPI_CTAR_BR(1) | SPI_CTAR_CSSCK(1);
- SPI0_MCR = SPI_MCR_MSTR | SPI_MCR_PCSIS(0x1F);
- SPCR.enable_pins(); // pins managed by SPCRemulation in avr_emulation.h
- }
-
- void SPIClass::end() {
- SPCR.disable_pins();
- SPI0_MCR = SPI_MCR_MDIS | SPI_MCR_HALT | SPI_MCR_PCSIS(0x1F);
- }
-
- void SPIClass::usingInterrupt(uint8_t interruptNumber)
- {
- // TODO: implement this...
- }
-
- void SPIClass::usingInterrupt(IRQ_NUMBER_t interruptName)
- {
- // TODO: implement this...
- }
-
-
-
- const uint16_t SPISettings::ctar_div_table[23] = {
- 2, 3, 4, 5, 6, 8, 10, 12, 16, 20, 24, 32, 40,
- 56, 64, 96, 128, 192, 256, 384, 512, 640, 768
- };
- const uint32_t SPISettings::ctar_clock_table[23] = {
- SPI_CTAR_PBR(0) | SPI_CTAR_BR(0) | SPI_CTAR_DBR | SPI_CTAR_CSSCK(0),
- SPI_CTAR_PBR(1) | SPI_CTAR_BR(0) | SPI_CTAR_DBR | SPI_CTAR_CSSCK(0),
- SPI_CTAR_PBR(0) | SPI_CTAR_BR(0) | SPI_CTAR_CSSCK(0),
- SPI_CTAR_PBR(2) | SPI_CTAR_BR(0) | SPI_CTAR_DBR | SPI_CTAR_CSSCK(0),
- SPI_CTAR_PBR(1) | SPI_CTAR_BR(0) | SPI_CTAR_CSSCK(0),
- SPI_CTAR_PBR(0) | SPI_CTAR_BR(1) | SPI_CTAR_CSSCK(1),
- SPI_CTAR_PBR(2) | SPI_CTAR_BR(0) | SPI_CTAR_CSSCK(0),
- SPI_CTAR_PBR(1) | SPI_CTAR_BR(1) | SPI_CTAR_CSSCK(1),
- SPI_CTAR_PBR(0) | SPI_CTAR_BR(3) | SPI_CTAR_CSSCK(2),
- SPI_CTAR_PBR(2) | SPI_CTAR_BR(1) | SPI_CTAR_CSSCK(0),
- SPI_CTAR_PBR(1) | SPI_CTAR_BR(3) | SPI_CTAR_CSSCK(2),
- SPI_CTAR_PBR(0) | SPI_CTAR_BR(4) | SPI_CTAR_CSSCK(3),
- SPI_CTAR_PBR(2) | SPI_CTAR_BR(3) | SPI_CTAR_CSSCK(2),
- SPI_CTAR_PBR(3) | SPI_CTAR_BR(3) | SPI_CTAR_CSSCK(2),
- SPI_CTAR_PBR(0) | SPI_CTAR_BR(5) | SPI_CTAR_CSSCK(4),
- SPI_CTAR_PBR(1) | SPI_CTAR_BR(5) | SPI_CTAR_CSSCK(4),
- SPI_CTAR_PBR(0) | SPI_CTAR_BR(6) | SPI_CTAR_CSSCK(5),
- SPI_CTAR_PBR(1) | SPI_CTAR_BR(6) | SPI_CTAR_CSSCK(5),
- SPI_CTAR_PBR(0) | SPI_CTAR_BR(7) | SPI_CTAR_CSSCK(6),
- SPI_CTAR_PBR(1) | SPI_CTAR_BR(7) | SPI_CTAR_CSSCK(6),
- SPI_CTAR_PBR(0) | SPI_CTAR_BR(8) | SPI_CTAR_CSSCK(7),
- SPI_CTAR_PBR(2) | SPI_CTAR_BR(7) | SPI_CTAR_CSSCK(6),
- SPI_CTAR_PBR(1) | SPI_CTAR_BR(8) | SPI_CTAR_CSSCK(7)
- };
-
- static void updateCTAR(uint32_t ctar)
- {
- if (SPI0_CTAR0 != ctar) {
- uint32_t mcr = SPI0_MCR;
- if (mcr & SPI_MCR_MDIS) {
- SPI0_CTAR0 = ctar;
- SPI0_CTAR1 = ctar | SPI_CTAR_FMSZ(8);
- } else {
- SPI0_MCR = SPI_MCR_MDIS | SPI_MCR_HALT | SPI_MCR_PCSIS(0x1F);
- SPI0_CTAR0 = ctar;
- SPI0_CTAR1 = ctar | SPI_CTAR_FMSZ(8);
- SPI0_MCR = mcr;
- }
- }
- }
-
- void SPIClass::setBitOrder(uint8_t bitOrder)
- {
- SIM_SCGC6 |= SIM_SCGC6_SPI0;
- uint32_t ctar = SPI0_CTAR0;
- if (bitOrder == LSBFIRST) {
- ctar |= SPI_CTAR_LSBFE;
- } else {
- ctar &= ~SPI_CTAR_LSBFE;
- }
- updateCTAR(ctar);
- }
-
- void SPIClass::setDataMode(uint8_t dataMode)
- {
- SIM_SCGC6 |= SIM_SCGC6_SPI0;
-
- // TODO: implement with native code
-
- SPCR = (SPCR & ~SPI_MODE_MASK) | dataMode;
- }
-
- void SPIClass::setClockDivider_noInline(uint32_t clk)
- {
- SIM_SCGC6 |= SIM_SCGC6_SPI0;
- uint32_t ctar = SPI0_CTAR0;
- ctar &= (SPI_CTAR_CPOL | SPI_CTAR_CPHA | SPI_CTAR_LSBFE);
- if (ctar & SPI_CTAR_CPHA) {
- clk = (clk & 0xFFFF0FFF) | ((clk & 0xF000) >> 4);
- }
- ctar |= clk;
- updateCTAR(ctar);
- }
-
- bool SPIClass::pinIsChipSelect(uint8_t pin)
- {
- if (pin == 10 || pin == 9 || pin == 6 || pin == 2 || pin == 15) return true;
- if (pin >= 20 && pin <= 23) return true;
- return false;
- }
-
- bool SPIClass::pinIsChipSelect(uint8_t pin1, uint8_t pin2)
- {
- if (!pinIsChipSelect(pin1) || !pinIsChipSelect(pin2)) return false;
- if ((pin1 == 2 && pin2 == 10) || (pin1 == 10 && pin2 == 2)) return false;
- if ((pin1 == 6 && pin2 == 9) || (pin1 == 9 && pin2 == 6)) return false;
- if ((pin1 == 20 && pin2 == 23) || (pin1 == 23 && pin2 == 20)) return false;
- if ((pin1 == 21 && pin2 == 22) || (pin1 == 22 && pin2 == 21)) return false;
- return true;
- }
-
- uint8_t SPIClass::setCS(uint8_t pin)
- {
- 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
- }
- return 0;
- }
-
-
- #endif
-
|