| @@ -19,772 +19,10 @@ | |||
| Modified 2012 by Todd Krein (todd@krein.org) to implement repeated starts | |||
| */ | |||
| #include "Wire.h" | |||
| #if defined(__arm__) && defined(CORE_TEENSY) | |||
| #if defined(__AVR__) | |||
| #include "kinetis.h" | |||
| #include <string.h> // for memcpy | |||
| #include "core_pins.h" | |||
| //#include "HardwareSerial.h" | |||
| #include "Wire.h" | |||
| uint8_t TwoWire::rxBuffer[BUFFER_LENGTH]; | |||
| uint8_t TwoWire::rxBufferIndex = 0; | |||
| uint8_t TwoWire::rxBufferLength = 0; | |||
| uint8_t TwoWire::txBuffer[BUFFER_LENGTH+1]; | |||
| uint8_t TwoWire::txBufferIndex = 0; | |||
| uint8_t TwoWire::txBufferLength = 0; | |||
| uint8_t TwoWire::transmitting = 0; | |||
| uint8_t TwoWire::sda_pin_num = 18; | |||
| uint8_t TwoWire::scl_pin_num = 19; | |||
| void (*TwoWire::user_onRequest)(void) = NULL; | |||
| void (*TwoWire::user_onReceive)(int) = NULL; | |||
| TwoWire::TwoWire() | |||
| { | |||
| } | |||
| static uint8_t slave_mode = 0; | |||
| static uint8_t irqcount=0; | |||
| void TwoWire::begin(void) | |||
| { | |||
| //serial_begin(BAUD2DIV(115200)); | |||
| //serial_print("\nWire Begin\n"); | |||
| slave_mode = 0; | |||
| SIM_SCGC4 |= SIM_SCGC4_I2C0; // TODO: use bitband | |||
| I2C0_C1 = 0; | |||
| // On Teensy 3.0 external pullup resistors *MUST* be used | |||
| // the PORT_PCR_PE bit is ignored when in I2C mode | |||
| // I2C will not work at all without pullup resistors | |||
| // It might seem like setting PORT_PCR_PE & PORT_PCR_PS | |||
| // would enable pullup resistors. However, there seems | |||
| // to be a bug in chip while I2C is enabled, where setting | |||
| // those causes the port to be driven strongly high. | |||
| if (sda_pin_num == 18) { | |||
| CORE_PIN18_CONFIG = PORT_PCR_MUX(2)|PORT_PCR_ODE|PORT_PCR_SRE|PORT_PCR_DSE; | |||
| } else if (sda_pin_num == 17) { | |||
| CORE_PIN17_CONFIG = PORT_PCR_MUX(2)|PORT_PCR_ODE|PORT_PCR_SRE|PORT_PCR_DSE; | |||
| #if defined(__MK64FX512__) || defined(__MK66FX1M0__) | |||
| } else if (sda_pin_num == 34) { | |||
| CORE_PIN34_CONFIG = PORT_PCR_MUX(5)|PORT_PCR_ODE|PORT_PCR_SRE|PORT_PCR_DSE; | |||
| } else if (sda_pin_num == 8) { | |||
| CORE_PIN8_CONFIG = PORT_PCR_MUX(7)|PORT_PCR_ODE|PORT_PCR_SRE|PORT_PCR_DSE; | |||
| } else if (sda_pin_num == 48) { | |||
| CORE_PIN48_CONFIG = PORT_PCR_MUX(2)|PORT_PCR_ODE|PORT_PCR_SRE|PORT_PCR_DSE; | |||
| #endif | |||
| } | |||
| if (scl_pin_num == 19) { | |||
| CORE_PIN19_CONFIG = PORT_PCR_MUX(2)|PORT_PCR_ODE|PORT_PCR_SRE|PORT_PCR_DSE; | |||
| } else if (scl_pin_num == 16) { | |||
| CORE_PIN16_CONFIG = PORT_PCR_MUX(2)|PORT_PCR_ODE|PORT_PCR_SRE|PORT_PCR_DSE; | |||
| #if defined(__MK64FX512__) || defined(__MK66FX1M0__) | |||
| } else if (scl_pin_num == 33) { | |||
| CORE_PIN33_CONFIG = PORT_PCR_MUX(5)|PORT_PCR_ODE|PORT_PCR_SRE|PORT_PCR_DSE; | |||
| } else if (scl_pin_num == 7) { | |||
| CORE_PIN7_CONFIG = PORT_PCR_MUX(7)|PORT_PCR_ODE|PORT_PCR_SRE|PORT_PCR_DSE; | |||
| } else if (scl_pin_num == 47) { | |||
| CORE_PIN47_CONFIG = PORT_PCR_MUX(2)|PORT_PCR_ODE|PORT_PCR_SRE|PORT_PCR_DSE; | |||
| #endif | |||
| } | |||
| setClock(100000); | |||
| I2C0_C2 = I2C_C2_HDRS; | |||
| I2C0_C1 = I2C_C1_IICEN; | |||
| //pinMode(3, OUTPUT); | |||
| //pinMode(4, OUTPUT); | |||
| } | |||
| void TwoWire::setClock(uint32_t frequency) | |||
| { | |||
| if (!(SIM_SCGC4 & SIM_SCGC4_I2C0)) return; | |||
| #if F_BUS == 120000000 | |||
| if (frequency < 400000) { | |||
| I2C0_F = I2C_F_DIV1152; // 104 kHz | |||
| } else if (frequency < 1000000) { | |||
| I2C0_F = I2C_F_DIV288; // 416 kHz | |||
| } else { | |||
| I2C0_F = I2C_F_DIV128; // 0.94 MHz | |||
| } | |||
| I2C0_FLT = 4; | |||
| #elif F_BUS == 108000000 | |||
| if (frequency < 400000) { | |||
| I2C0_F = I2C_F_DIV1024; // 105 kHz | |||
| } else if (frequency < 1000000) { | |||
| I2C0_F = I2C_F_DIV256; // 422 kHz | |||
| } else { | |||
| I2C0_F = I2C_F_DIV112; // 0.96 MHz | |||
| } | |||
| I2C0_FLT = 4; | |||
| #elif F_BUS == 96000000 | |||
| if (frequency < 400000) { | |||
| I2C0_F = I2C_F_DIV960; // 100 kHz | |||
| } else if (frequency < 1000000) { | |||
| I2C0_F = I2C_F_DIV240; // 400 kHz | |||
| } else { | |||
| I2C0_F = I2C_F_DIV96; // 1.0 MHz | |||
| } | |||
| I2C0_FLT = 4; | |||
| #elif F_BUS == 90000000 | |||
| if (frequency < 400000) { | |||
| I2C0_F = I2C_F_DIV896; // 100 kHz | |||
| } else if (frequency < 1000000) { | |||
| I2C0_F = I2C_F_DIV224; // 402 kHz | |||
| } else { | |||
| I2C0_F = I2C_F_DIV88; // 1.02 MHz | |||
| } | |||
| I2C0_FLT = 4; | |||
| #elif F_BUS == 80000000 | |||
| if (frequency < 400000) { | |||
| I2C0_F = I2C_F_DIV768; // 104 kHz | |||
| } else if (frequency < 1000000) { | |||
| I2C0_F = I2C_F_DIV192; // 416 kHz | |||
| } else { | |||
| I2C0_F = I2C_F_DIV80; // 1.0 MHz | |||
| } | |||
| I2C0_FLT = 4; | |||
| #elif F_BUS == 72000000 | |||
| if (frequency < 400000) { | |||
| I2C0_F = I2C_F_DIV640; // 112 kHz | |||
| } else if (frequency < 1000000) { | |||
| I2C0_F = I2C_F_DIV192; // 375 kHz | |||
| } else { | |||
| I2C0_F = I2C_F_DIV72; // 1.0 MHz | |||
| } | |||
| I2C0_FLT = 4; | |||
| #elif F_BUS == 64000000 | |||
| if (frequency < 400000) { | |||
| I2C0_F = I2C_F_DIV640; // 100 kHz | |||
| } else if (frequency < 1000000) { | |||
| I2C0_F = I2C_F_DIV160; // 400 kHz | |||
| } else { | |||
| I2C0_F = I2C_F_DIV64; // 1.0 MHz | |||
| } | |||
| I2C0_FLT = 4; | |||
| #elif F_BUS == 60000000 | |||
| if (frequency < 400000) { | |||
| I2C0_F = 0x2C; // 104 kHz | |||
| } else if (frequency < 1000000) { | |||
| I2C0_F = 0x1C; // 416 kHz | |||
| } else { | |||
| I2C0_F = 0x12; // 938 kHz | |||
| } | |||
| I2C0_FLT = 4; | |||
| #elif F_BUS == 56000000 | |||
| if (frequency < 400000) { | |||
| I2C0_F = 0x2B; // 109 kHz | |||
| } else if (frequency < 1000000) { | |||
| I2C0_F = 0x1C; // 389 kHz | |||
| } else { | |||
| I2C0_F = 0x0E; // 1 MHz | |||
| } | |||
| I2C0_FLT = 4; | |||
| #elif F_BUS == 54000000 | |||
| if (frequency < 400000) { | |||
| I2C0_F = I2C_F_DIV512; // 105 kHz | |||
| } else if (frequency < 1000000) { | |||
| I2C0_F = I2C_F_DIV128; // 422 kHz | |||
| } else { | |||
| I2C0_F = I2C_F_DIV56; // 0.96 MHz | |||
| } | |||
| I2C0_FLT = 4; | |||
| #elif F_BUS == 48000000 | |||
| if (frequency < 400000) { | |||
| I2C0_F = 0x27; // 100 kHz | |||
| } else if (frequency < 1000000) { | |||
| I2C0_F = 0x1A; // 400 kHz | |||
| } else { | |||
| I2C0_F = 0x0D; // 1 MHz | |||
| } | |||
| I2C0_FLT = 4; | |||
| #elif F_BUS == 40000000 | |||
| if (frequency < 400000) { | |||
| I2C0_F = 0x29; // 104 kHz | |||
| } else if (frequency < 1000000) { | |||
| I2C0_F = 0x19; // 416 kHz | |||
| } else { | |||
| I2C0_F = 0x0B; // 1 MHz | |||
| } | |||
| I2C0_FLT = 3; | |||
| #elif F_BUS == 36000000 | |||
| if (frequency < 400000) { | |||
| I2C0_F = 0x28; // 113 kHz | |||
| } else if (frequency < 1000000) { | |||
| I2C0_F = 0x19; // 375 kHz | |||
| } else { | |||
| I2C0_F = 0x0A; // 1 MHz | |||
| } | |||
| I2C0_FLT = 3; | |||
| #elif F_BUS == 24000000 | |||
| if (frequency < 400000) { | |||
| I2C0_F = 0x1F; // 100 kHz | |||
| } else if (frequency < 1000000) { | |||
| I2C0_F = 0x12; // 375 kHz | |||
| } else { | |||
| I2C0_F = 0x02; // 1 MHz | |||
| } | |||
| I2C0_FLT = 2; | |||
| #elif F_BUS == 16000000 | |||
| if (frequency < 400000) { | |||
| I2C0_F = 0x20; // 100 kHz | |||
| } else if (frequency < 1000000) { | |||
| I2C0_F = 0x07; // 400 kHz | |||
| } else { | |||
| I2C0_F = 0x00; // 800 MHz | |||
| } | |||
| I2C0_FLT = 1; | |||
| #elif F_BUS == 8000000 | |||
| if (frequency < 400000) { | |||
| I2C0_F = 0x14; // 100 kHz | |||
| } else { | |||
| I2C0_F = 0x00; // 400 kHz | |||
| } | |||
| I2C0_FLT = 1; | |||
| #elif F_BUS == 4000000 | |||
| if (frequency < 400000) { | |||
| I2C0_F = 0x07; // 100 kHz | |||
| } else { | |||
| I2C0_F = 0x00; // 200 kHz | |||
| } | |||
| I2C0_FLT = 1; | |||
| #elif F_BUS == 2000000 | |||
| I2C0_F = 0x00; // 100 kHz | |||
| I2C0_FLT = 1; | |||
| #else | |||
| #error "F_BUS must be 120, 108, 96, 9, 80, 72, 64, 60, 56, 54, 48, 40, 36, 24, 16, 8, 4 or 2 MHz" | |||
| #endif | |||
| } | |||
| void TwoWire::setSDA(uint8_t pin) | |||
| { | |||
| if (pin == sda_pin_num) return; | |||
| if ((SIM_SCGC4 & SIM_SCGC4_I2C0)) { | |||
| if (sda_pin_num == 18) { | |||
| CORE_PIN18_CONFIG = 0; | |||
| } else if (sda_pin_num == 17) { | |||
| CORE_PIN17_CONFIG = 0; | |||
| #if defined(__MK64FX512__) || defined(__MK66FX1M0__) | |||
| } else if (sda_pin_num == 34) { | |||
| CORE_PIN34_CONFIG = 0; | |||
| } else if (sda_pin_num == 8) { | |||
| CORE_PIN8_CONFIG = 0; | |||
| } else if (sda_pin_num == 48) { | |||
| CORE_PIN48_CONFIG = 0; | |||
| #endif | |||
| } | |||
| if (pin == 18) { | |||
| CORE_PIN18_CONFIG = PORT_PCR_MUX(2)|PORT_PCR_ODE|PORT_PCR_SRE|PORT_PCR_DSE; | |||
| } else if (pin == 17) { | |||
| CORE_PIN17_CONFIG = PORT_PCR_MUX(2)|PORT_PCR_ODE|PORT_PCR_SRE|PORT_PCR_DSE; | |||
| #if defined(__MK64FX512__) || defined(__MK66FX1M0__) | |||
| } else if (pin == 34) { | |||
| CORE_PIN34_CONFIG = PORT_PCR_MUX(5)|PORT_PCR_ODE|PORT_PCR_SRE|PORT_PCR_DSE; | |||
| } else if (pin == 8) { | |||
| CORE_PIN8_CONFIG = PORT_PCR_MUX(7)|PORT_PCR_ODE|PORT_PCR_SRE|PORT_PCR_DSE; | |||
| } else if (pin == 48) { | |||
| CORE_PIN48_CONFIG = PORT_PCR_MUX(2)|PORT_PCR_ODE|PORT_PCR_SRE|PORT_PCR_DSE; | |||
| #endif | |||
| } | |||
| } | |||
| sda_pin_num = pin; | |||
| } | |||
| void TwoWire::setSCL(uint8_t pin) | |||
| { | |||
| if (pin == scl_pin_num) return; | |||
| if ((SIM_SCGC4 & SIM_SCGC4_I2C0)) { | |||
| if (scl_pin_num == 19) { | |||
| CORE_PIN19_CONFIG = 0; | |||
| } else if (scl_pin_num == 16) { | |||
| CORE_PIN16_CONFIG = 0; | |||
| #if defined(__MK64FX512__) || defined(__MK66FX1M0__) | |||
| } else if (scl_pin_num == 33) { | |||
| CORE_PIN33_CONFIG = 0; | |||
| } else if (scl_pin_num == 7) { | |||
| CORE_PIN7_CONFIG = 0; | |||
| } else if (scl_pin_num == 47) { | |||
| CORE_PIN47_CONFIG = 0; | |||
| #endif | |||
| } | |||
| if (pin == 19) { | |||
| CORE_PIN19_CONFIG = PORT_PCR_MUX(2)|PORT_PCR_ODE|PORT_PCR_SRE|PORT_PCR_DSE; | |||
| } else if (pin == 16) { | |||
| CORE_PIN16_CONFIG = PORT_PCR_MUX(2)|PORT_PCR_ODE|PORT_PCR_SRE|PORT_PCR_DSE; | |||
| #if defined(__MK64FX512__) || defined(__MK66FX1M0__) | |||
| } else if (pin == 33) { | |||
| CORE_PIN33_CONFIG = PORT_PCR_MUX(5)|PORT_PCR_ODE|PORT_PCR_SRE|PORT_PCR_DSE; | |||
| } else if (pin == 7) { | |||
| CORE_PIN7_CONFIG = PORT_PCR_MUX(7)|PORT_PCR_ODE|PORT_PCR_SRE|PORT_PCR_DSE; | |||
| } else if (pin == 47) { | |||
| CORE_PIN47_CONFIG = PORT_PCR_MUX(2)|PORT_PCR_ODE|PORT_PCR_SRE|PORT_PCR_DSE; | |||
| #endif | |||
| } | |||
| } | |||
| scl_pin_num = pin; | |||
| } | |||
| void TwoWire::begin(uint8_t address) | |||
| { | |||
| begin(); | |||
| I2C0_A1 = address << 1; | |||
| slave_mode = 1; | |||
| I2C0_C1 = I2C_C1_IICEN | I2C_C1_IICIE; | |||
| NVIC_ENABLE_IRQ(IRQ_I2C0); | |||
| } | |||
| void TwoWire::end() | |||
| { | |||
| if (!(SIM_SCGC4 & SIM_SCGC4_I2C0)) return; | |||
| NVIC_DISABLE_IRQ(IRQ_I2C0); | |||
| I2C0_C1 = 0; | |||
| if (sda_pin_num == 18) { | |||
| CORE_PIN18_CONFIG = 0; | |||
| } else if (sda_pin_num == 17) { | |||
| CORE_PIN17_CONFIG = 0; | |||
| #if defined(__MK64FX512__) || defined(__MK66FX1M0__) | |||
| } else if (sda_pin_num == 34) { | |||
| CORE_PIN34_CONFIG = 0; | |||
| } else if (sda_pin_num == 8) { | |||
| CORE_PIN8_CONFIG = 0; | |||
| } else if (sda_pin_num == 48) { | |||
| CORE_PIN48_CONFIG = 0; | |||
| #endif | |||
| } | |||
| if (scl_pin_num == 19) { | |||
| CORE_PIN19_CONFIG = 0; | |||
| } else if (scl_pin_num == 16) { | |||
| CORE_PIN16_CONFIG = 0; | |||
| #if defined(__MK64FX512__) || defined(__MK66FX1M0__) | |||
| } else if (scl_pin_num == 33) { | |||
| CORE_PIN33_CONFIG = 0; | |||
| } else if (scl_pin_num == 7) { | |||
| CORE_PIN7_CONFIG = 0; | |||
| } else if (scl_pin_num == 47) { | |||
| CORE_PIN47_CONFIG = 0; | |||
| #endif | |||
| } | |||
| SIM_SCGC4 &= ~SIM_SCGC4_I2C0; // TODO: use bitband | |||
| } | |||
| void i2c0_isr(void) | |||
| { | |||
| uint8_t status, c1, data; | |||
| static uint8_t receiving=0; | |||
| status = I2C0_S; | |||
| //serial_print("."); | |||
| if (status & I2C_S_ARBL) { | |||
| // Arbitration Lost | |||
| I2C0_S = I2C_S_ARBL; | |||
| //serial_print("a"); | |||
| if (receiving && TwoWire::rxBufferLength > 0) { | |||
| // TODO: does this detect the STOP condition in slave receive mode? | |||
| } | |||
| if (!(status & I2C_S_IAAS)) return; | |||
| } | |||
| if (status & I2C_S_IAAS) { | |||
| //serial_print("\n"); | |||
| // Addressed As A Slave | |||
| if (status & I2C_S_SRW) { | |||
| //serial_print("T"); | |||
| // Begin Slave Transmit | |||
| receiving = 0; | |||
| TwoWire::txBufferLength = 0; | |||
| if (TwoWire::user_onRequest != NULL) { | |||
| TwoWire::user_onRequest(); | |||
| } | |||
| if (TwoWire::txBufferLength == 0) { | |||
| // is this correct, transmitting a single zero | |||
| // when we should send nothing? Arduino's AVR | |||
| // implementation does this, but is it ok? | |||
| TwoWire::txBufferLength = 1; | |||
| TwoWire::txBuffer[0] = 0; | |||
| } | |||
| I2C0_C1 = I2C_C1_IICEN | I2C_C1_IICIE | I2C_C1_TX; | |||
| I2C0_D = TwoWire::txBuffer[0]; | |||
| TwoWire::txBufferIndex = 1; | |||
| } else { | |||
| // Begin Slave Receive | |||
| //serial_print("R"); | |||
| receiving = 1; | |||
| TwoWire::rxBufferLength = 0; | |||
| I2C0_C1 = I2C_C1_IICEN | I2C_C1_IICIE; | |||
| data = I2C0_D; | |||
| } | |||
| I2C0_S = I2C_S_IICIF; | |||
| return; | |||
| } | |||
| #if defined(KINETISL) | |||
| c1 = I2C0_FLT; | |||
| if ((c1 & I2C_FLT_STOPF) && (c1 & I2C_FLT_STOPIE)) { | |||
| I2C0_FLT = c1 & ~I2C_FLT_STOPIE; | |||
| if (TwoWire::user_onReceive != NULL) { | |||
| TwoWire::rxBufferIndex = 0; | |||
| TwoWire::user_onReceive(TwoWire::rxBufferLength); | |||
| } | |||
| } | |||
| #endif | |||
| c1 = I2C0_C1; | |||
| if (c1 & I2C_C1_TX) { | |||
| // Continue Slave Transmit | |||
| //serial_print("t"); | |||
| if ((status & I2C_S_RXAK) == 0) { | |||
| //serial_print("."); | |||
| // Master ACK'd previous byte | |||
| if (TwoWire::txBufferIndex < TwoWire::txBufferLength) { | |||
| I2C0_D = TwoWire::txBuffer[TwoWire::txBufferIndex++]; | |||
| } else { | |||
| I2C0_D = 0; | |||
| } | |||
| I2C0_C1 = I2C_C1_IICEN | I2C_C1_IICIE | I2C_C1_TX; | |||
| } else { | |||
| //serial_print("*"); | |||
| // Master did not ACK previous byte | |||
| I2C0_C1 = I2C_C1_IICEN | I2C_C1_IICIE; | |||
| data = I2C0_D; | |||
| } | |||
| } else { | |||
| // Continue Slave Receive | |||
| irqcount = 0; | |||
| #if defined(KINETISK) | |||
| attachInterrupt(18, TwoWire::sda_rising_isr, RISING); | |||
| #elif defined(KINETISL) | |||
| I2C0_FLT |= I2C_FLT_STOPIE; | |||
| #endif | |||
| //digitalWriteFast(4, HIGH); | |||
| data = I2C0_D; | |||
| //serial_phex(data); | |||
| if (TwoWire::rxBufferLength < BUFFER_LENGTH && receiving) { | |||
| TwoWire::rxBuffer[TwoWire::rxBufferLength++] = data; | |||
| } | |||
| //digitalWriteFast(4, LOW); | |||
| } | |||
| I2C0_S = I2C_S_IICIF; | |||
| } | |||
| // Detects the stop condition that terminates a slave receive transfer. | |||
| // Sadly, the I2C in Kinetis K series lacks the stop detect interrupt | |||
| // This pin change interrupt hack is needed to detect the stop condition | |||
| void TwoWire::sda_rising_isr(void) | |||
| { | |||
| //digitalWrite(3, HIGH); | |||
| if (!(I2C0_S & I2C_S_BUSY)) { | |||
| detachInterrupt(18); | |||
| if (user_onReceive != NULL) { | |||
| rxBufferIndex = 0; | |||
| user_onReceive(rxBufferLength); | |||
| } | |||
| //delayMicroseconds(100); | |||
| } else { | |||
| if (++irqcount >= 2 || !slave_mode) { | |||
| detachInterrupt(18); | |||
| } | |||
| } | |||
| //digitalWrite(3, LOW); | |||
| } | |||
| // Chapter 44: Inter-Integrated Circuit (I2C) - Page 1012 | |||
| // I2C0_A1 // I2C Address Register 1 | |||
| // I2C0_F // I2C Frequency Divider register | |||
| // I2C0_C1 // I2C Control Register 1 | |||
| // I2C0_S // I2C Status register | |||
| // I2C0_D // I2C Data I/O register | |||
| // I2C0_C2 // I2C Control Register 2 | |||
| // I2C0_FLT // I2C Programmable Input Glitch Filter register | |||
| static uint8_t i2c_status(void) | |||
| { | |||
| static uint32_t p=0xFFFF; | |||
| uint32_t s = I2C0_S; | |||
| if (s != p) { | |||
| //Serial.printf("(%02X)", s); | |||
| p = s; | |||
| } | |||
| return s; | |||
| } | |||
| static void i2c_wait(void) | |||
| { | |||
| #if 0 | |||
| while (!(I2C0_S & I2C_S_IICIF)) ; // wait | |||
| I2C0_S = I2C_S_IICIF; | |||
| #endif | |||
| //Serial.write('^'); | |||
| while (1) { | |||
| if ((i2c_status() & I2C_S_IICIF)) break; | |||
| } | |||
| I2C0_S = I2C_S_IICIF; | |||
| } | |||
| void TwoWire::beginTransmission(uint8_t address) | |||
| { | |||
| txBuffer[0] = (address << 1); | |||
| transmitting = 1; | |||
| txBufferLength = 1; | |||
| } | |||
| size_t TwoWire::write(uint8_t data) | |||
| { | |||
| if (transmitting || slave_mode) { | |||
| if (txBufferLength >= BUFFER_LENGTH+1) { | |||
| setWriteError(); | |||
| return 0; | |||
| } | |||
| txBuffer[txBufferLength++] = data; | |||
| return 1; | |||
| } | |||
| return 0; | |||
| } | |||
| size_t TwoWire::write(const uint8_t *data, size_t quantity) | |||
| { | |||
| if (transmitting || slave_mode) { | |||
| size_t avail = BUFFER_LENGTH+1 - txBufferLength; | |||
| if (quantity > avail) { | |||
| quantity = avail; | |||
| setWriteError(); | |||
| } | |||
| memcpy(txBuffer + txBufferLength, data, quantity); | |||
| txBufferLength += quantity; | |||
| return quantity; | |||
| } | |||
| return 0; | |||
| } | |||
| void TwoWire::flush(void) | |||
| { | |||
| } | |||
| uint8_t TwoWire::endTransmission(uint8_t sendStop) | |||
| { | |||
| uint8_t i, status, ret=0; | |||
| // clear the status flags | |||
| I2C0_S = I2C_S_IICIF | I2C_S_ARBL; | |||
| // now take control of the bus... | |||
| if (I2C0_C1 & I2C_C1_MST) { | |||
| // we are already the bus master, so send a repeated start | |||
| //Serial.print("rstart:"); | |||
| I2C0_C1 = I2C_C1_IICEN | I2C_C1_MST | I2C_C1_RSTA | I2C_C1_TX; | |||
| } else { | |||
| // we are not currently the bus master, so wait for bus ready | |||
| //Serial.print("busy:"); | |||
| uint32_t wait_begin = millis(); | |||
| while (i2c_status() & I2C_S_BUSY) { | |||
| //Serial.write('.') ; | |||
| if (millis() - wait_begin > 15) { | |||
| // bus stuck busy too long | |||
| I2C0_C1 = 0; | |||
| I2C0_C1 = I2C_C1_IICEN; | |||
| //Serial.println("abort"); | |||
| return 4; | |||
| } | |||
| } | |||
| // become the bus master in transmit mode (send start) | |||
| slave_mode = 0; | |||
| I2C0_C1 = I2C_C1_IICEN | I2C_C1_MST | I2C_C1_TX; | |||
| } | |||
| // wait until start condition establishes control of the bus | |||
| while (1) { | |||
| status = i2c_status(); | |||
| if ((status & I2C_S_BUSY)) break; | |||
| } | |||
| // transmit the address and data | |||
| for (i=0; i < txBufferLength; i++) { | |||
| I2C0_D = txBuffer[i]; | |||
| //Serial.write('^'); | |||
| while (1) { | |||
| status = i2c_status(); | |||
| if ((status & I2C_S_IICIF)) break; | |||
| if (!(status & I2C_S_BUSY)) break; | |||
| } | |||
| I2C0_S = I2C_S_IICIF; | |||
| //Serial.write('$'); | |||
| status = i2c_status(); | |||
| if ((status & I2C_S_ARBL)) { | |||
| // we lost bus arbitration to another master | |||
| // TODO: what is the proper thing to do here?? | |||
| //Serial.printf(" c1=%02X ", I2C0_C1); | |||
| I2C0_C1 = I2C_C1_IICEN; | |||
| ret = 4; // 4:other error | |||
| break; | |||
| } | |||
| if (!(status & I2C_S_BUSY)) { | |||
| // suddenly lost control of the bus! | |||
| I2C0_C1 = I2C_C1_IICEN; | |||
| ret = 4; // 4:other error | |||
| break; | |||
| } | |||
| if (status & I2C_S_RXAK) { | |||
| // the slave device did not acknowledge | |||
| if (i == 0) { | |||
| ret = 2; // 2:received NACK on transmit of address | |||
| } else { | |||
| ret = 3; // 3:received NACK on transmit of data | |||
| } | |||
| sendStop = 1; | |||
| break; | |||
| } | |||
| } | |||
| if (sendStop) { | |||
| // send the stop condition | |||
| I2C0_C1 = I2C_C1_IICEN; | |||
| // TODO: do we wait for this somehow? | |||
| } | |||
| transmitting = 0; | |||
| //Serial.print(" ret="); | |||
| //Serial.println(ret); | |||
| return ret; | |||
| } | |||
| uint8_t TwoWire::requestFrom(uint8_t address, uint8_t length, uint8_t sendStop) | |||
| { | |||
| uint8_t tmp __attribute__((unused)); | |||
| uint8_t status, count=0; | |||
| rxBufferIndex = 0; | |||
| rxBufferLength = 0; | |||
| //serial_print("requestFrom\n"); | |||
| // clear the status flags | |||
| I2C0_S = I2C_S_IICIF | I2C_S_ARBL; | |||
| // now take control of the bus... | |||
| if (I2C0_C1 & I2C_C1_MST) { | |||
| // we are already the bus master, so send a repeated start | |||
| I2C0_C1 = I2C_C1_IICEN | I2C_C1_MST | I2C_C1_RSTA | I2C_C1_TX; | |||
| } else { | |||
| // we are not currently the bus master, so wait for bus ready | |||
| while (i2c_status() & I2C_S_BUSY) ; | |||
| // become the bus master in transmit mode (send start) | |||
| slave_mode = 0; | |||
| I2C0_C1 = I2C_C1_IICEN | I2C_C1_MST | I2C_C1_TX; | |||
| } | |||
| // send the address | |||
| I2C0_D = (address << 1) | 1; | |||
| i2c_wait(); | |||
| status = i2c_status(); | |||
| if ((status & I2C_S_RXAK) || (status & I2C_S_ARBL)) { | |||
| // the slave device did not acknowledge | |||
| // or we lost bus arbitration to another master | |||
| I2C0_C1 = I2C_C1_IICEN; | |||
| return 0; | |||
| } | |||
| if (length == 0) { | |||
| // TODO: does anybody really do zero length reads? | |||
| // if so, does this code really work? | |||
| I2C0_C1 = I2C_C1_IICEN | (sendStop ? 0 : I2C_C1_MST); | |||
| return 0; | |||
| } else if (length == 1) { | |||
| I2C0_C1 = I2C_C1_IICEN | I2C_C1_MST | I2C_C1_TXAK; | |||
| } else { | |||
| I2C0_C1 = I2C_C1_IICEN | I2C_C1_MST; | |||
| } | |||
| tmp = I2C0_D; // initiate the first receive | |||
| while (length > 1) { | |||
| i2c_wait(); | |||
| length--; | |||
| if (length == 1) I2C0_C1 = I2C_C1_IICEN | I2C_C1_MST | I2C_C1_TXAK; | |||
| if (count < BUFFER_LENGTH) { | |||
| rxBuffer[count++] = I2C0_D; | |||
| } else { | |||
| tmp = I2C0_D; | |||
| } | |||
| } | |||
| i2c_wait(); | |||
| I2C0_C1 = I2C_C1_IICEN | I2C_C1_MST | I2C_C1_TX; | |||
| if (count < BUFFER_LENGTH) { | |||
| rxBuffer[count++] = I2C0_D; | |||
| } else { | |||
| tmp = I2C0_D; | |||
| } | |||
| if (sendStop) I2C0_C1 = I2C_C1_IICEN; | |||
| rxBufferLength = count; | |||
| return count; | |||
| } | |||
| int TwoWire::available(void) | |||
| { | |||
| return rxBufferLength - rxBufferIndex; | |||
| } | |||
| int TwoWire::read(void) | |||
| { | |||
| if (rxBufferIndex >= rxBufferLength) return -1; | |||
| return rxBuffer[rxBufferIndex++]; | |||
| } | |||
| int TwoWire::peek(void) | |||
| { | |||
| if (rxBufferIndex >= rxBufferLength) return -1; | |||
| return rxBuffer[rxBufferIndex]; | |||
| } | |||
| // alternate function prototypes | |||
| uint8_t TwoWire::requestFrom(uint8_t address, uint8_t quantity) | |||
| { | |||
| return requestFrom((uint8_t)address, (uint8_t)quantity, (uint8_t)true); | |||
| } | |||
| uint8_t TwoWire::requestFrom(int address, int quantity) | |||
| { | |||
| return requestFrom((uint8_t)address, (uint8_t)quantity, (uint8_t)true); | |||
| } | |||
| uint8_t TwoWire::requestFrom(int address, int quantity, int sendStop) | |||
| { | |||
| return requestFrom((uint8_t)address, (uint8_t)quantity, (uint8_t)sendStop); | |||
| } | |||
| void TwoWire::beginTransmission(int address) | |||
| { | |||
| beginTransmission((uint8_t)address); | |||
| } | |||
| uint8_t TwoWire::endTransmission(void) | |||
| { | |||
| return endTransmission(true); | |||
| } | |||
| void TwoWire::begin(int address) | |||
| { | |||
| begin((uint8_t)address); | |||
| } | |||
| void TwoWire::onReceive( void (*function)(int) ) | |||
| { | |||
| user_onReceive = function; | |||
| } | |||
| void TwoWire::onRequest( void (*function)(void) ) | |||
| { | |||
| user_onRequest = function; | |||
| } | |||
| //TwoWire Wire = TwoWire(); | |||
| TwoWire Wire; | |||
| #endif // __MK20DX128__ || __MK20DX256__ | |||
| #if defined(__AVR__) | |||
| extern "C" { | |||
| #include <stdlib.h> | |||
| #include <string.h> | |||
| @@ -22,16 +22,17 @@ | |||
| #ifndef TwoWire_h | |||
| #define TwoWire_h | |||
| #if defined(__arm__) && defined(TEENSYDUINO) | |||
| #include "WireKinetis.h" | |||
| #elif defined(__AVR__) | |||
| #include <inttypes.h> | |||
| #include "Arduino.h" | |||
| #define BUFFER_LENGTH 32 | |||
| #define WIRE_HAS_END 1 | |||
| #if defined(__arm__) && defined(CORE_TEENSY) | |||
| extern "C" void i2c0_isr(void); | |||
| #endif | |||
| class TwoWire : public Stream | |||
| { | |||
| private: | |||
| @@ -50,11 +51,6 @@ class TwoWire : public Stream | |||
| static void (*user_onRequest)(void); | |||
| static void (*user_onReceive)(int); | |||
| static void sda_rising_isr(void); | |||
| #if defined(__arm__) && defined(CORE_TEENSY) | |||
| static uint8_t sda_pin_num; | |||
| static uint8_t scl_pin_num; | |||
| friend void i2c0_isr(void); | |||
| #endif | |||
| public: | |||
| TwoWire(); | |||
| void begin(); | |||
| @@ -103,135 +99,5 @@ class TwoWire : public Stream | |||
| extern TwoWire Wire; | |||
| #if defined(__arm__) && defined(CORE_TEENSY) | |||
| class TWBRemulation | |||
| { | |||
| public: | |||
| inline TWBRemulation & operator = (int val) __attribute__((always_inline)) { | |||
| if (val == 12 || val == ((F_CPU / 400000) - 16) / 2) { // 22, 52, 112 | |||
| I2C0_C1 = 0; | |||
| #if F_BUS == 120000000 | |||
| I2C0_F = I2C_F_DIV288; // 416 kHz | |||
| #elif F_BUS == 108000000 | |||
| I2C0_F = I2C_F_DIV256; // 422 kHz | |||
| #elif F_BUS == 96000000 | |||
| I2C0_F = I2C_F_DIV240; // 400 kHz | |||
| #elif F_BUS == 90000000 | |||
| I2C0_F = I2C_F_DIV224; // 402 kHz | |||
| #elif F_BUS == 80000000 | |||
| I2C0_F = I2C_F_DIV192; // 416 kHz | |||
| #elif F_BUS == 72000000 | |||
| I2C0_F = I2C_F_DIV192; // 375 kHz | |||
| #elif F_BUS == 64000000 | |||
| I2C0_F = I2C_F_DIV160; // 400 kHz | |||
| #elif F_BUS == 60000000 | |||
| I2C0_F = I2C_F_DIV144; // 416 kHz | |||
| #elif F_BUS == 56000000 | |||
| I2C0_F = I2C_F_DIV144; // 389 kHz | |||
| #elif F_BUS == 54000000 | |||
| I2C0_F = I2C_F_DIV128; // 422 kHz | |||
| #elif F_BUS == 48000000 | |||
| I2C0_F = I2C_F_DIV112; // 400 kHz | |||
| #elif F_BUS == 40000000 | |||
| I2C0_F = I2C_F_DIV96; // 416 kHz | |||
| #elif F_BUS == 36000000 | |||
| I2C0_F = I2C_F_DIV96; // 375 kHz | |||
| #elif F_BUS == 24000000 | |||
| I2C0_F = I2C_F_DIV64; // 375 kHz | |||
| #elif F_BUS == 16000000 | |||
| I2C0_F = I2C_F_DIV40; // 400 kHz | |||
| #elif F_BUS == 8000000 | |||
| I2C0_F = I2C_F_DIV20; // 400 kHz | |||
| #elif F_BUS == 4000000 | |||
| I2C0_F = I2C_F_DIV20; // 200 kHz | |||
| #elif F_BUS == 2000000 | |||
| I2C0_F = I2C_F_DIV20; // 100 kHz | |||
| #endif | |||
| I2C0_C1 = I2C_C1_IICEN; | |||
| } else if (val == 72 || val == ((F_CPU / 100000) - 16) / 2) { // 112, 232, 472 | |||
| I2C0_C1 = 0; | |||
| #if F_BUS == 120000000 | |||
| I2C0_F = I2C_F_DIV1152; // 104 kHz | |||
| #elif F_BUS == 108000000 | |||
| I2C0_F = I2C_F_DIV1024; // 105 kHz | |||
| #elif F_BUS == 96000000 | |||
| I2C0_F = I2C_F_DIV960; // 100 kHz | |||
| #elif F_BUS == 90000000 | |||
| I2C0_F = I2C_F_DIV896; // 100 kHz | |||
| #elif F_BUS == 80000000 | |||
| I2C0_F = I2C_F_DIV768; // 104 kHz | |||
| #elif F_BUS == 72000000 | |||
| I2C0_F = I2C_F_DIV640; // 112 kHz | |||
| #elif F_BUS == 64000000 | |||
| I2C0_F = I2C_F_DIV640; // 100 kHz | |||
| #elif F_BUS == 60000000 | |||
| I2C0_F = I2C_F_DIV576; // 104 kHz | |||
| #elif F_BUS == 56000000 | |||
| I2C0_F = I2C_F_DIV512; // 109 kHz | |||
| #elif F_BUS == 54000000 | |||
| I2C0_F = I2C_F_DIV512; // 105 kHz | |||
| #elif F_BUS == 48000000 | |||
| I2C0_F = I2C_F_DIV480; // 100 kHz | |||
| #elif F_BUS == 40000000 | |||
| I2C0_F = I2C_F_DIV384; // 104 kHz | |||
| #elif F_BUS == 36000000 | |||
| I2C0_F = I2C_F_DIV320; // 113 kHz | |||
| #elif F_BUS == 24000000 | |||
| I2C0_F = I2C_F_DIV240; // 100 kHz | |||
| #elif F_BUS == 16000000 | |||
| I2C0_F = I2C_F_DIV160; // 100 kHz | |||
| #elif F_BUS == 8000000 | |||
| I2C0_F = I2C_F_DIV80; // 100 kHz | |||
| #elif F_BUS == 4000000 | |||
| I2C0_F = I2C_F_DIV40; // 100 kHz | |||
| #elif F_BUS == 2000000 | |||
| I2C0_F = I2C_F_DIV20; // 100 kHz | |||
| #endif | |||
| I2C0_C1 = I2C_C1_IICEN; | |||
| } | |||
| return *this; | |||
| } | |||
| inline operator int () const __attribute__((always_inline)) { | |||
| #if F_BUS == 120000000 | |||
| if (I2C0_F == I2C_F_DIV288) return 12; | |||
| #elif F_BUS == 108000000 | |||
| if (I2C0_F == I2C_F_DIV256) return 12; | |||
| #elif F_BUS == 96000000 | |||
| if (I2C0_F == I2C_F_DIV240) return 12; | |||
| #elif F_BUS == 90000000 | |||
| if (I2C0_F == I2C_F_DIV224) return 12; | |||
| #elif F_BUS == 80000000 | |||
| if (I2C0_F == I2C_F_DIV192) return 12; | |||
| #elif F_BUS == 72000000 | |||
| if (I2C0_F == I2C_F_DIV192) return 12; | |||
| #elif F_BUS == 64000000 | |||
| if (I2C0_F == I2C_F_DIV160) return 12; | |||
| #elif F_BUS == 60000000 | |||
| if (I2C0_F == I2C_F_DIV144) return 12; | |||
| #elif F_BUS == 56000000 | |||
| if (I2C0_F == I2C_F_DIV144) return 12; | |||
| #elif F_BUS == 54000000 | |||
| if (I2C0_F == I2C_F_DIV128) return 12; | |||
| #elif F_BUS == 48000000 | |||
| if (I2C0_F == I2C_F_DIV112) return 12; | |||
| #elif F_BUS == 40000000 | |||
| if (I2C0_F == I2C_F_DIV96) return 12; | |||
| #elif F_BUS == 36000000 | |||
| if (I2C0_F == I2C_F_DIV96) return 12; | |||
| #elif F_BUS == 24000000 | |||
| if (I2C0_F == I2C_F_DIV64) return 12; | |||
| #elif F_BUS == 16000000 | |||
| if (I2C0_F == I2C_F_DIV40) return 12; | |||
| #elif F_BUS == 8000000 | |||
| if (I2C0_F == I2C_F_DIV20) return 12; | |||
| #elif F_BUS == 4000000 | |||
| if (I2C0_F == I2C_F_DIV20) return 12; | |||
| #endif | |||
| return 72; | |||
| } | |||
| }; | |||
| extern TWBRemulation TWBR; | |||
| #endif | |||
| #endif | |||
| @@ -0,0 +1,783 @@ | |||
| /* | |||
| TwoWire.cpp - TWI/I2C library for Wiring & Arduino | |||
| Copyright (c) 2006 Nicholas Zambetti. All right reserved. | |||
| This library is free software; you can redistribute it and/or | |||
| modify it under the terms of the GNU Lesser General Public | |||
| License as published by the Free Software Foundation; either | |||
| version 2.1 of the License, or (at your option) any later version. | |||
| This library is distributed in the hope that it will be useful, | |||
| but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
| Lesser General Public License for more details. | |||
| You should have received a copy of the GNU Lesser General Public | |||
| License along with this library; if not, write to the Free Software | |||
| Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | |||
| Modified 2012 by Todd Krein (todd@krein.org) to implement repeated starts | |||
| */ | |||
| #include "Wire.h" | |||
| #if defined(__arm__) && defined(CORE_TEENSY) | |||
| #include "kinetis.h" | |||
| #include <string.h> // for memcpy | |||
| #include "core_pins.h" | |||
| //#include "HardwareSerial.h" | |||
| #include "Wire.h" | |||
| uint8_t TwoWire::rxBuffer[BUFFER_LENGTH]; | |||
| uint8_t TwoWire::rxBufferIndex = 0; | |||
| uint8_t TwoWire::rxBufferLength = 0; | |||
| uint8_t TwoWire::txBuffer[BUFFER_LENGTH+1]; | |||
| uint8_t TwoWire::txBufferIndex = 0; | |||
| uint8_t TwoWire::txBufferLength = 0; | |||
| uint8_t TwoWire::transmitting = 0; | |||
| uint8_t TwoWire::sda_pin_num = 18; | |||
| uint8_t TwoWire::scl_pin_num = 19; | |||
| void (*TwoWire::user_onRequest)(void) = NULL; | |||
| void (*TwoWire::user_onReceive)(int) = NULL; | |||
| TwoWire::TwoWire() | |||
| { | |||
| } | |||
| static uint8_t slave_mode = 0; | |||
| static uint8_t irqcount=0; | |||
| void TwoWire::begin(void) | |||
| { | |||
| //serial_begin(BAUD2DIV(115200)); | |||
| //serial_print("\nWire Begin\n"); | |||
| slave_mode = 0; | |||
| SIM_SCGC4 |= SIM_SCGC4_I2C0; // TODO: use bitband | |||
| I2C0_C1 = 0; | |||
| // On Teensy 3.0 external pullup resistors *MUST* be used | |||
| // the PORT_PCR_PE bit is ignored when in I2C mode | |||
| // I2C will not work at all without pullup resistors | |||
| // It might seem like setting PORT_PCR_PE & PORT_PCR_PS | |||
| // would enable pullup resistors. However, there seems | |||
| // to be a bug in chip while I2C is enabled, where setting | |||
| // those causes the port to be driven strongly high. | |||
| if (sda_pin_num == 18) { | |||
| CORE_PIN18_CONFIG = PORT_PCR_MUX(2)|PORT_PCR_ODE|PORT_PCR_SRE|PORT_PCR_DSE; | |||
| } else if (sda_pin_num == 17) { | |||
| CORE_PIN17_CONFIG = PORT_PCR_MUX(2)|PORT_PCR_ODE|PORT_PCR_SRE|PORT_PCR_DSE; | |||
| #if defined(__MK64FX512__) || defined(__MK66FX1M0__) | |||
| } else if (sda_pin_num == 34) { | |||
| CORE_PIN34_CONFIG = PORT_PCR_MUX(5)|PORT_PCR_ODE|PORT_PCR_SRE|PORT_PCR_DSE; | |||
| } else if (sda_pin_num == 8) { | |||
| CORE_PIN8_CONFIG = PORT_PCR_MUX(7)|PORT_PCR_ODE|PORT_PCR_SRE|PORT_PCR_DSE; | |||
| } else if (sda_pin_num == 48) { | |||
| CORE_PIN48_CONFIG = PORT_PCR_MUX(2)|PORT_PCR_ODE|PORT_PCR_SRE|PORT_PCR_DSE; | |||
| #endif | |||
| } | |||
| if (scl_pin_num == 19) { | |||
| CORE_PIN19_CONFIG = PORT_PCR_MUX(2)|PORT_PCR_ODE|PORT_PCR_SRE|PORT_PCR_DSE; | |||
| } else if (scl_pin_num == 16) { | |||
| CORE_PIN16_CONFIG = PORT_PCR_MUX(2)|PORT_PCR_ODE|PORT_PCR_SRE|PORT_PCR_DSE; | |||
| #if defined(__MK64FX512__) || defined(__MK66FX1M0__) | |||
| } else if (scl_pin_num == 33) { | |||
| CORE_PIN33_CONFIG = PORT_PCR_MUX(5)|PORT_PCR_ODE|PORT_PCR_SRE|PORT_PCR_DSE; | |||
| } else if (scl_pin_num == 7) { | |||
| CORE_PIN7_CONFIG = PORT_PCR_MUX(7)|PORT_PCR_ODE|PORT_PCR_SRE|PORT_PCR_DSE; | |||
| } else if (scl_pin_num == 47) { | |||
| CORE_PIN47_CONFIG = PORT_PCR_MUX(2)|PORT_PCR_ODE|PORT_PCR_SRE|PORT_PCR_DSE; | |||
| #endif | |||
| } | |||
| setClock(100000); | |||
| I2C0_C2 = I2C_C2_HDRS; | |||
| I2C0_C1 = I2C_C1_IICEN; | |||
| //pinMode(3, OUTPUT); | |||
| //pinMode(4, OUTPUT); | |||
| } | |||
| void TwoWire::setClock(uint32_t frequency) | |||
| { | |||
| if (!(SIM_SCGC4 & SIM_SCGC4_I2C0)) return; | |||
| #if F_BUS == 120000000 | |||
| if (frequency < 400000) { | |||
| I2C0_F = I2C_F_DIV1152; // 104 kHz | |||
| } else if (frequency < 1000000) { | |||
| I2C0_F = I2C_F_DIV288; // 416 kHz | |||
| } else { | |||
| I2C0_F = I2C_F_DIV128; // 0.94 MHz | |||
| } | |||
| I2C0_FLT = 4; | |||
| #elif F_BUS == 108000000 | |||
| if (frequency < 400000) { | |||
| I2C0_F = I2C_F_DIV1024; // 105 kHz | |||
| } else if (frequency < 1000000) { | |||
| I2C0_F = I2C_F_DIV256; // 422 kHz | |||
| } else { | |||
| I2C0_F = I2C_F_DIV112; // 0.96 MHz | |||
| } | |||
| I2C0_FLT = 4; | |||
| #elif F_BUS == 96000000 | |||
| if (frequency < 400000) { | |||
| I2C0_F = I2C_F_DIV960; // 100 kHz | |||
| } else if (frequency < 1000000) { | |||
| I2C0_F = I2C_F_DIV240; // 400 kHz | |||
| } else { | |||
| I2C0_F = I2C_F_DIV96; // 1.0 MHz | |||
| } | |||
| I2C0_FLT = 4; | |||
| #elif F_BUS == 90000000 | |||
| if (frequency < 400000) { | |||
| I2C0_F = I2C_F_DIV896; // 100 kHz | |||
| } else if (frequency < 1000000) { | |||
| I2C0_F = I2C_F_DIV224; // 402 kHz | |||
| } else { | |||
| I2C0_F = I2C_F_DIV88; // 1.02 MHz | |||
| } | |||
| I2C0_FLT = 4; | |||
| #elif F_BUS == 80000000 | |||
| if (frequency < 400000) { | |||
| I2C0_F = I2C_F_DIV768; // 104 kHz | |||
| } else if (frequency < 1000000) { | |||
| I2C0_F = I2C_F_DIV192; // 416 kHz | |||
| } else { | |||
| I2C0_F = I2C_F_DIV80; // 1.0 MHz | |||
| } | |||
| I2C0_FLT = 4; | |||
| #elif F_BUS == 72000000 | |||
| if (frequency < 400000) { | |||
| I2C0_F = I2C_F_DIV640; // 112 kHz | |||
| } else if (frequency < 1000000) { | |||
| I2C0_F = I2C_F_DIV192; // 375 kHz | |||
| } else { | |||
| I2C0_F = I2C_F_DIV72; // 1.0 MHz | |||
| } | |||
| I2C0_FLT = 4; | |||
| #elif F_BUS == 64000000 | |||
| if (frequency < 400000) { | |||
| I2C0_F = I2C_F_DIV640; // 100 kHz | |||
| } else if (frequency < 1000000) { | |||
| I2C0_F = I2C_F_DIV160; // 400 kHz | |||
| } else { | |||
| I2C0_F = I2C_F_DIV64; // 1.0 MHz | |||
| } | |||
| I2C0_FLT = 4; | |||
| #elif F_BUS == 60000000 | |||
| if (frequency < 400000) { | |||
| I2C0_F = 0x2C; // 104 kHz | |||
| } else if (frequency < 1000000) { | |||
| I2C0_F = 0x1C; // 416 kHz | |||
| } else { | |||
| I2C0_F = 0x12; // 938 kHz | |||
| } | |||
| I2C0_FLT = 4; | |||
| #elif F_BUS == 56000000 | |||
| if (frequency < 400000) { | |||
| I2C0_F = 0x2B; // 109 kHz | |||
| } else if (frequency < 1000000) { | |||
| I2C0_F = 0x1C; // 389 kHz | |||
| } else { | |||
| I2C0_F = 0x0E; // 1 MHz | |||
| } | |||
| I2C0_FLT = 4; | |||
| #elif F_BUS == 54000000 | |||
| if (frequency < 400000) { | |||
| I2C0_F = I2C_F_DIV512; // 105 kHz | |||
| } else if (frequency < 1000000) { | |||
| I2C0_F = I2C_F_DIV128; // 422 kHz | |||
| } else { | |||
| I2C0_F = I2C_F_DIV56; // 0.96 MHz | |||
| } | |||
| I2C0_FLT = 4; | |||
| #elif F_BUS == 48000000 | |||
| if (frequency < 400000) { | |||
| I2C0_F = 0x27; // 100 kHz | |||
| } else if (frequency < 1000000) { | |||
| I2C0_F = 0x1A; // 400 kHz | |||
| } else { | |||
| I2C0_F = 0x0D; // 1 MHz | |||
| } | |||
| I2C0_FLT = 4; | |||
| #elif F_BUS == 40000000 | |||
| if (frequency < 400000) { | |||
| I2C0_F = 0x29; // 104 kHz | |||
| } else if (frequency < 1000000) { | |||
| I2C0_F = 0x19; // 416 kHz | |||
| } else { | |||
| I2C0_F = 0x0B; // 1 MHz | |||
| } | |||
| I2C0_FLT = 3; | |||
| #elif F_BUS == 36000000 | |||
| if (frequency < 400000) { | |||
| I2C0_F = 0x28; // 113 kHz | |||
| } else if (frequency < 1000000) { | |||
| I2C0_F = 0x19; // 375 kHz | |||
| } else { | |||
| I2C0_F = 0x0A; // 1 MHz | |||
| } | |||
| I2C0_FLT = 3; | |||
| #elif F_BUS == 24000000 | |||
| if (frequency < 400000) { | |||
| I2C0_F = 0x1F; // 100 kHz | |||
| } else if (frequency < 1000000) { | |||
| I2C0_F = 0x12; // 375 kHz | |||
| } else { | |||
| I2C0_F = 0x02; // 1 MHz | |||
| } | |||
| I2C0_FLT = 2; | |||
| #elif F_BUS == 16000000 | |||
| if (frequency < 400000) { | |||
| I2C0_F = 0x20; // 100 kHz | |||
| } else if (frequency < 1000000) { | |||
| I2C0_F = 0x07; // 400 kHz | |||
| } else { | |||
| I2C0_F = 0x00; // 800 MHz | |||
| } | |||
| I2C0_FLT = 1; | |||
| #elif F_BUS == 8000000 | |||
| if (frequency < 400000) { | |||
| I2C0_F = 0x14; // 100 kHz | |||
| } else { | |||
| I2C0_F = 0x00; // 400 kHz | |||
| } | |||
| I2C0_FLT = 1; | |||
| #elif F_BUS == 4000000 | |||
| if (frequency < 400000) { | |||
| I2C0_F = 0x07; // 100 kHz | |||
| } else { | |||
| I2C0_F = 0x00; // 200 kHz | |||
| } | |||
| I2C0_FLT = 1; | |||
| #elif F_BUS == 2000000 | |||
| I2C0_F = 0x00; // 100 kHz | |||
| I2C0_FLT = 1; | |||
| #else | |||
| #error "F_BUS must be 120, 108, 96, 9, 80, 72, 64, 60, 56, 54, 48, 40, 36, 24, 16, 8, 4 or 2 MHz" | |||
| #endif | |||
| } | |||
| void TwoWire::setSDA(uint8_t pin) | |||
| { | |||
| if (pin == sda_pin_num) return; | |||
| if ((SIM_SCGC4 & SIM_SCGC4_I2C0)) { | |||
| if (sda_pin_num == 18) { | |||
| CORE_PIN18_CONFIG = 0; | |||
| } else if (sda_pin_num == 17) { | |||
| CORE_PIN17_CONFIG = 0; | |||
| #if defined(__MK64FX512__) || defined(__MK66FX1M0__) | |||
| } else if (sda_pin_num == 34) { | |||
| CORE_PIN34_CONFIG = 0; | |||
| } else if (sda_pin_num == 8) { | |||
| CORE_PIN8_CONFIG = 0; | |||
| } else if (sda_pin_num == 48) { | |||
| CORE_PIN48_CONFIG = 0; | |||
| #endif | |||
| } | |||
| if (pin == 18) { | |||
| CORE_PIN18_CONFIG = PORT_PCR_MUX(2)|PORT_PCR_ODE|PORT_PCR_SRE|PORT_PCR_DSE; | |||
| } else if (pin == 17) { | |||
| CORE_PIN17_CONFIG = PORT_PCR_MUX(2)|PORT_PCR_ODE|PORT_PCR_SRE|PORT_PCR_DSE; | |||
| #if defined(__MK64FX512__) || defined(__MK66FX1M0__) | |||
| } else if (pin == 34) { | |||
| CORE_PIN34_CONFIG = PORT_PCR_MUX(5)|PORT_PCR_ODE|PORT_PCR_SRE|PORT_PCR_DSE; | |||
| } else if (pin == 8) { | |||
| CORE_PIN8_CONFIG = PORT_PCR_MUX(7)|PORT_PCR_ODE|PORT_PCR_SRE|PORT_PCR_DSE; | |||
| } else if (pin == 48) { | |||
| CORE_PIN48_CONFIG = PORT_PCR_MUX(2)|PORT_PCR_ODE|PORT_PCR_SRE|PORT_PCR_DSE; | |||
| #endif | |||
| } | |||
| } | |||
| sda_pin_num = pin; | |||
| } | |||
| void TwoWire::setSCL(uint8_t pin) | |||
| { | |||
| if (pin == scl_pin_num) return; | |||
| if ((SIM_SCGC4 & SIM_SCGC4_I2C0)) { | |||
| if (scl_pin_num == 19) { | |||
| CORE_PIN19_CONFIG = 0; | |||
| } else if (scl_pin_num == 16) { | |||
| CORE_PIN16_CONFIG = 0; | |||
| #if defined(__MK64FX512__) || defined(__MK66FX1M0__) | |||
| } else if (scl_pin_num == 33) { | |||
| CORE_PIN33_CONFIG = 0; | |||
| } else if (scl_pin_num == 7) { | |||
| CORE_PIN7_CONFIG = 0; | |||
| } else if (scl_pin_num == 47) { | |||
| CORE_PIN47_CONFIG = 0; | |||
| #endif | |||
| } | |||
| if (pin == 19) { | |||
| CORE_PIN19_CONFIG = PORT_PCR_MUX(2)|PORT_PCR_ODE|PORT_PCR_SRE|PORT_PCR_DSE; | |||
| } else if (pin == 16) { | |||
| CORE_PIN16_CONFIG = PORT_PCR_MUX(2)|PORT_PCR_ODE|PORT_PCR_SRE|PORT_PCR_DSE; | |||
| #if defined(__MK64FX512__) || defined(__MK66FX1M0__) | |||
| } else if (pin == 33) { | |||
| CORE_PIN33_CONFIG = PORT_PCR_MUX(5)|PORT_PCR_ODE|PORT_PCR_SRE|PORT_PCR_DSE; | |||
| } else if (pin == 7) { | |||
| CORE_PIN7_CONFIG = PORT_PCR_MUX(7)|PORT_PCR_ODE|PORT_PCR_SRE|PORT_PCR_DSE; | |||
| } else if (pin == 47) { | |||
| CORE_PIN47_CONFIG = PORT_PCR_MUX(2)|PORT_PCR_ODE|PORT_PCR_SRE|PORT_PCR_DSE; | |||
| #endif | |||
| } | |||
| } | |||
| scl_pin_num = pin; | |||
| } | |||
| void TwoWire::begin(uint8_t address) | |||
| { | |||
| begin(); | |||
| I2C0_A1 = address << 1; | |||
| slave_mode = 1; | |||
| I2C0_C1 = I2C_C1_IICEN | I2C_C1_IICIE; | |||
| NVIC_ENABLE_IRQ(IRQ_I2C0); | |||
| } | |||
| void TwoWire::end() | |||
| { | |||
| if (!(SIM_SCGC4 & SIM_SCGC4_I2C0)) return; | |||
| NVIC_DISABLE_IRQ(IRQ_I2C0); | |||
| I2C0_C1 = 0; | |||
| if (sda_pin_num == 18) { | |||
| CORE_PIN18_CONFIG = 0; | |||
| } else if (sda_pin_num == 17) { | |||
| CORE_PIN17_CONFIG = 0; | |||
| #if defined(__MK64FX512__) || defined(__MK66FX1M0__) | |||
| } else if (sda_pin_num == 34) { | |||
| CORE_PIN34_CONFIG = 0; | |||
| } else if (sda_pin_num == 8) { | |||
| CORE_PIN8_CONFIG = 0; | |||
| } else if (sda_pin_num == 48) { | |||
| CORE_PIN48_CONFIG = 0; | |||
| #endif | |||
| } | |||
| if (scl_pin_num == 19) { | |||
| CORE_PIN19_CONFIG = 0; | |||
| } else if (scl_pin_num == 16) { | |||
| CORE_PIN16_CONFIG = 0; | |||
| #if defined(__MK64FX512__) || defined(__MK66FX1M0__) | |||
| } else if (scl_pin_num == 33) { | |||
| CORE_PIN33_CONFIG = 0; | |||
| } else if (scl_pin_num == 7) { | |||
| CORE_PIN7_CONFIG = 0; | |||
| } else if (scl_pin_num == 47) { | |||
| CORE_PIN47_CONFIG = 0; | |||
| #endif | |||
| } | |||
| SIM_SCGC4 &= ~SIM_SCGC4_I2C0; // TODO: use bitband | |||
| } | |||
| void i2c0_isr(void) | |||
| { | |||
| uint8_t status, c1, data; | |||
| static uint8_t receiving=0; | |||
| status = I2C0_S; | |||
| //serial_print("."); | |||
| if (status & I2C_S_ARBL) { | |||
| // Arbitration Lost | |||
| I2C0_S = I2C_S_ARBL; | |||
| //serial_print("a"); | |||
| if (receiving && TwoWire::rxBufferLength > 0) { | |||
| // TODO: does this detect the STOP condition in slave receive mode? | |||
| } | |||
| if (!(status & I2C_S_IAAS)) return; | |||
| } | |||
| if (status & I2C_S_IAAS) { | |||
| //serial_print("\n"); | |||
| // Addressed As A Slave | |||
| if (status & I2C_S_SRW) { | |||
| //serial_print("T"); | |||
| // Begin Slave Transmit | |||
| receiving = 0; | |||
| TwoWire::txBufferLength = 0; | |||
| if (TwoWire::user_onRequest != NULL) { | |||
| TwoWire::user_onRequest(); | |||
| } | |||
| if (TwoWire::txBufferLength == 0) { | |||
| // is this correct, transmitting a single zero | |||
| // when we should send nothing? Arduino's AVR | |||
| // implementation does this, but is it ok? | |||
| TwoWire::txBufferLength = 1; | |||
| TwoWire::txBuffer[0] = 0; | |||
| } | |||
| I2C0_C1 = I2C_C1_IICEN | I2C_C1_IICIE | I2C_C1_TX; | |||
| I2C0_D = TwoWire::txBuffer[0]; | |||
| TwoWire::txBufferIndex = 1; | |||
| } else { | |||
| // Begin Slave Receive | |||
| //serial_print("R"); | |||
| receiving = 1; | |||
| TwoWire::rxBufferLength = 0; | |||
| I2C0_C1 = I2C_C1_IICEN | I2C_C1_IICIE; | |||
| data = I2C0_D; | |||
| } | |||
| I2C0_S = I2C_S_IICIF; | |||
| return; | |||
| } | |||
| #if defined(KINETISL) | |||
| c1 = I2C0_FLT; | |||
| if ((c1 & I2C_FLT_STOPF) && (c1 & I2C_FLT_STOPIE)) { | |||
| I2C0_FLT = c1 & ~I2C_FLT_STOPIE; | |||
| if (TwoWire::user_onReceive != NULL) { | |||
| TwoWire::rxBufferIndex = 0; | |||
| TwoWire::user_onReceive(TwoWire::rxBufferLength); | |||
| } | |||
| } | |||
| #endif | |||
| c1 = I2C0_C1; | |||
| if (c1 & I2C_C1_TX) { | |||
| // Continue Slave Transmit | |||
| //serial_print("t"); | |||
| if ((status & I2C_S_RXAK) == 0) { | |||
| //serial_print("."); | |||
| // Master ACK'd previous byte | |||
| if (TwoWire::txBufferIndex < TwoWire::txBufferLength) { | |||
| I2C0_D = TwoWire::txBuffer[TwoWire::txBufferIndex++]; | |||
| } else { | |||
| I2C0_D = 0; | |||
| } | |||
| I2C0_C1 = I2C_C1_IICEN | I2C_C1_IICIE | I2C_C1_TX; | |||
| } else { | |||
| //serial_print("*"); | |||
| // Master did not ACK previous byte | |||
| I2C0_C1 = I2C_C1_IICEN | I2C_C1_IICIE; | |||
| data = I2C0_D; | |||
| } | |||
| } else { | |||
| // Continue Slave Receive | |||
| irqcount = 0; | |||
| #if defined(KINETISK) | |||
| attachInterrupt(18, TwoWire::sda_rising_isr, RISING); | |||
| #elif defined(KINETISL) | |||
| I2C0_FLT |= I2C_FLT_STOPIE; | |||
| #endif | |||
| //digitalWriteFast(4, HIGH); | |||
| data = I2C0_D; | |||
| //serial_phex(data); | |||
| if (TwoWire::rxBufferLength < BUFFER_LENGTH && receiving) { | |||
| TwoWire::rxBuffer[TwoWire::rxBufferLength++] = data; | |||
| } | |||
| //digitalWriteFast(4, LOW); | |||
| } | |||
| I2C0_S = I2C_S_IICIF; | |||
| } | |||
| // Detects the stop condition that terminates a slave receive transfer. | |||
| // Sadly, the I2C in Kinetis K series lacks the stop detect interrupt | |||
| // This pin change interrupt hack is needed to detect the stop condition | |||
| void TwoWire::sda_rising_isr(void) | |||
| { | |||
| //digitalWrite(3, HIGH); | |||
| if (!(I2C0_S & I2C_S_BUSY)) { | |||
| detachInterrupt(18); | |||
| if (user_onReceive != NULL) { | |||
| rxBufferIndex = 0; | |||
| user_onReceive(rxBufferLength); | |||
| } | |||
| //delayMicroseconds(100); | |||
| } else { | |||
| if (++irqcount >= 2 || !slave_mode) { | |||
| detachInterrupt(18); | |||
| } | |||
| } | |||
| //digitalWrite(3, LOW); | |||
| } | |||
| // Chapter 44: Inter-Integrated Circuit (I2C) - Page 1012 | |||
| // I2C0_A1 // I2C Address Register 1 | |||
| // I2C0_F // I2C Frequency Divider register | |||
| // I2C0_C1 // I2C Control Register 1 | |||
| // I2C0_S // I2C Status register | |||
| // I2C0_D // I2C Data I/O register | |||
| // I2C0_C2 // I2C Control Register 2 | |||
| // I2C0_FLT // I2C Programmable Input Glitch Filter register | |||
| static uint8_t i2c_status(void) | |||
| { | |||
| static uint32_t p=0xFFFF; | |||
| uint32_t s = I2C0_S; | |||
| if (s != p) { | |||
| //Serial.printf("(%02X)", s); | |||
| p = s; | |||
| } | |||
| return s; | |||
| } | |||
| static void i2c_wait(void) | |||
| { | |||
| #if 0 | |||
| while (!(I2C0_S & I2C_S_IICIF)) ; // wait | |||
| I2C0_S = I2C_S_IICIF; | |||
| #endif | |||
| //Serial.write('^'); | |||
| while (1) { | |||
| if ((i2c_status() & I2C_S_IICIF)) break; | |||
| } | |||
| I2C0_S = I2C_S_IICIF; | |||
| } | |||
| void TwoWire::beginTransmission(uint8_t address) | |||
| { | |||
| txBuffer[0] = (address << 1); | |||
| transmitting = 1; | |||
| txBufferLength = 1; | |||
| } | |||
| size_t TwoWire::write(uint8_t data) | |||
| { | |||
| if (transmitting || slave_mode) { | |||
| if (txBufferLength >= BUFFER_LENGTH+1) { | |||
| setWriteError(); | |||
| return 0; | |||
| } | |||
| txBuffer[txBufferLength++] = data; | |||
| return 1; | |||
| } | |||
| return 0; | |||
| } | |||
| size_t TwoWire::write(const uint8_t *data, size_t quantity) | |||
| { | |||
| if (transmitting || slave_mode) { | |||
| size_t avail = BUFFER_LENGTH+1 - txBufferLength; | |||
| if (quantity > avail) { | |||
| quantity = avail; | |||
| setWriteError(); | |||
| } | |||
| memcpy(txBuffer + txBufferLength, data, quantity); | |||
| txBufferLength += quantity; | |||
| return quantity; | |||
| } | |||
| return 0; | |||
| } | |||
| void TwoWire::flush(void) | |||
| { | |||
| } | |||
| uint8_t TwoWire::endTransmission(uint8_t sendStop) | |||
| { | |||
| uint8_t i, status, ret=0; | |||
| // clear the status flags | |||
| I2C0_S = I2C_S_IICIF | I2C_S_ARBL; | |||
| // now take control of the bus... | |||
| if (I2C0_C1 & I2C_C1_MST) { | |||
| // we are already the bus master, so send a repeated start | |||
| //Serial.print("rstart:"); | |||
| I2C0_C1 = I2C_C1_IICEN | I2C_C1_MST | I2C_C1_RSTA | I2C_C1_TX; | |||
| } else { | |||
| // we are not currently the bus master, so wait for bus ready | |||
| //Serial.print("busy:"); | |||
| uint32_t wait_begin = millis(); | |||
| while (i2c_status() & I2C_S_BUSY) { | |||
| //Serial.write('.') ; | |||
| if (millis() - wait_begin > 15) { | |||
| // bus stuck busy too long | |||
| I2C0_C1 = 0; | |||
| I2C0_C1 = I2C_C1_IICEN; | |||
| //Serial.println("abort"); | |||
| return 4; | |||
| } | |||
| } | |||
| // become the bus master in transmit mode (send start) | |||
| slave_mode = 0; | |||
| I2C0_C1 = I2C_C1_IICEN | I2C_C1_MST | I2C_C1_TX; | |||
| } | |||
| // wait until start condition establishes control of the bus | |||
| while (1) { | |||
| status = i2c_status(); | |||
| if ((status & I2C_S_BUSY)) break; | |||
| } | |||
| // transmit the address and data | |||
| for (i=0; i < txBufferLength; i++) { | |||
| I2C0_D = txBuffer[i]; | |||
| //Serial.write('^'); | |||
| while (1) { | |||
| status = i2c_status(); | |||
| if ((status & I2C_S_IICIF)) break; | |||
| if (!(status & I2C_S_BUSY)) break; | |||
| } | |||
| I2C0_S = I2C_S_IICIF; | |||
| //Serial.write('$'); | |||
| status = i2c_status(); | |||
| if ((status & I2C_S_ARBL)) { | |||
| // we lost bus arbitration to another master | |||
| // TODO: what is the proper thing to do here?? | |||
| //Serial.printf(" c1=%02X ", I2C0_C1); | |||
| I2C0_C1 = I2C_C1_IICEN; | |||
| ret = 4; // 4:other error | |||
| break; | |||
| } | |||
| if (!(status & I2C_S_BUSY)) { | |||
| // suddenly lost control of the bus! | |||
| I2C0_C1 = I2C_C1_IICEN; | |||
| ret = 4; // 4:other error | |||
| break; | |||
| } | |||
| if (status & I2C_S_RXAK) { | |||
| // the slave device did not acknowledge | |||
| if (i == 0) { | |||
| ret = 2; // 2:received NACK on transmit of address | |||
| } else { | |||
| ret = 3; // 3:received NACK on transmit of data | |||
| } | |||
| sendStop = 1; | |||
| break; | |||
| } | |||
| } | |||
| if (sendStop) { | |||
| // send the stop condition | |||
| I2C0_C1 = I2C_C1_IICEN; | |||
| // TODO: do we wait for this somehow? | |||
| } | |||
| transmitting = 0; | |||
| //Serial.print(" ret="); | |||
| //Serial.println(ret); | |||
| return ret; | |||
| } | |||
| uint8_t TwoWire::requestFrom(uint8_t address, uint8_t length, uint8_t sendStop) | |||
| { | |||
| uint8_t tmp __attribute__((unused)); | |||
| uint8_t status, count=0; | |||
| rxBufferIndex = 0; | |||
| rxBufferLength = 0; | |||
| //serial_print("requestFrom\n"); | |||
| // clear the status flags | |||
| I2C0_S = I2C_S_IICIF | I2C_S_ARBL; | |||
| // now take control of the bus... | |||
| if (I2C0_C1 & I2C_C1_MST) { | |||
| // we are already the bus master, so send a repeated start | |||
| I2C0_C1 = I2C_C1_IICEN | I2C_C1_MST | I2C_C1_RSTA | I2C_C1_TX; | |||
| } else { | |||
| // we are not currently the bus master, so wait for bus ready | |||
| while (i2c_status() & I2C_S_BUSY) ; | |||
| // become the bus master in transmit mode (send start) | |||
| slave_mode = 0; | |||
| I2C0_C1 = I2C_C1_IICEN | I2C_C1_MST | I2C_C1_TX; | |||
| } | |||
| // send the address | |||
| I2C0_D = (address << 1) | 1; | |||
| i2c_wait(); | |||
| status = i2c_status(); | |||
| if ((status & I2C_S_RXAK) || (status & I2C_S_ARBL)) { | |||
| // the slave device did not acknowledge | |||
| // or we lost bus arbitration to another master | |||
| I2C0_C1 = I2C_C1_IICEN; | |||
| return 0; | |||
| } | |||
| if (length == 0) { | |||
| // TODO: does anybody really do zero length reads? | |||
| // if so, does this code really work? | |||
| I2C0_C1 = I2C_C1_IICEN | (sendStop ? 0 : I2C_C1_MST); | |||
| return 0; | |||
| } else if (length == 1) { | |||
| I2C0_C1 = I2C_C1_IICEN | I2C_C1_MST | I2C_C1_TXAK; | |||
| } else { | |||
| I2C0_C1 = I2C_C1_IICEN | I2C_C1_MST; | |||
| } | |||
| tmp = I2C0_D; // initiate the first receive | |||
| while (length > 1) { | |||
| i2c_wait(); | |||
| length--; | |||
| if (length == 1) I2C0_C1 = I2C_C1_IICEN | I2C_C1_MST | I2C_C1_TXAK; | |||
| if (count < BUFFER_LENGTH) { | |||
| rxBuffer[count++] = I2C0_D; | |||
| } else { | |||
| tmp = I2C0_D; | |||
| } | |||
| } | |||
| i2c_wait(); | |||
| I2C0_C1 = I2C_C1_IICEN | I2C_C1_MST | I2C_C1_TX; | |||
| if (count < BUFFER_LENGTH) { | |||
| rxBuffer[count++] = I2C0_D; | |||
| } else { | |||
| tmp = I2C0_D; | |||
| } | |||
| if (sendStop) I2C0_C1 = I2C_C1_IICEN; | |||
| rxBufferLength = count; | |||
| return count; | |||
| } | |||
| int TwoWire::available(void) | |||
| { | |||
| return rxBufferLength - rxBufferIndex; | |||
| } | |||
| int TwoWire::read(void) | |||
| { | |||
| if (rxBufferIndex >= rxBufferLength) return -1; | |||
| return rxBuffer[rxBufferIndex++]; | |||
| } | |||
| int TwoWire::peek(void) | |||
| { | |||
| if (rxBufferIndex >= rxBufferLength) return -1; | |||
| return rxBuffer[rxBufferIndex]; | |||
| } | |||
| // alternate function prototypes | |||
| uint8_t TwoWire::requestFrom(uint8_t address, uint8_t quantity) | |||
| { | |||
| return requestFrom((uint8_t)address, (uint8_t)quantity, (uint8_t)true); | |||
| } | |||
| uint8_t TwoWire::requestFrom(int address, int quantity) | |||
| { | |||
| return requestFrom((uint8_t)address, (uint8_t)quantity, (uint8_t)true); | |||
| } | |||
| uint8_t TwoWire::requestFrom(int address, int quantity, int sendStop) | |||
| { | |||
| return requestFrom((uint8_t)address, (uint8_t)quantity, (uint8_t)sendStop); | |||
| } | |||
| void TwoWire::beginTransmission(int address) | |||
| { | |||
| beginTransmission((uint8_t)address); | |||
| } | |||
| uint8_t TwoWire::endTransmission(void) | |||
| { | |||
| return endTransmission(true); | |||
| } | |||
| void TwoWire::begin(int address) | |||
| { | |||
| begin((uint8_t)address); | |||
| } | |||
| void TwoWire::onReceive( void (*function)(int) ) | |||
| { | |||
| user_onReceive = function; | |||
| } | |||
| void TwoWire::onRequest( void (*function)(void) ) | |||
| { | |||
| user_onRequest = function; | |||
| } | |||
| //TwoWire Wire = TwoWire(); | |||
| TwoWire Wire; | |||
| #endif // __MK20DX128__ || __MK20DX256__ | |||
| @@ -0,0 +1,230 @@ | |||
| /* | |||
| TwoWire.h - TWI/I2C library for Arduino & Wiring | |||
| Copyright (c) 2006 Nicholas Zambetti. All right reserved. | |||
| This library is free software; you can redistribute it and/or | |||
| modify it under the terms of the GNU Lesser General Public | |||
| License as published by the Free Software Foundation; either | |||
| version 2.1 of the License, or (at your option) any later version. | |||
| This library is distributed in the hope that it will be useful, | |||
| but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
| Lesser General Public License for more details. | |||
| You should have received a copy of the GNU Lesser General Public | |||
| License along with this library; if not, write to the Free Software | |||
| Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | |||
| Modified 2012 by Todd Krein (todd@krein.org) to implement repeated starts | |||
| */ | |||
| #ifndef TwoWireKinetis_h | |||
| #define TwoWireKinetis_h | |||
| #if defined(__arm__) && defined(TEENSYDUINO) | |||
| extern "C" void i2c0_isr(void); | |||
| #include <inttypes.h> | |||
| #include "Arduino.h" | |||
| #define BUFFER_LENGTH 32 | |||
| #define WIRE_HAS_END 1 | |||
| class TwoWire : public Stream | |||
| { | |||
| private: | |||
| static uint8_t rxBuffer[]; | |||
| static uint8_t rxBufferIndex; | |||
| static uint8_t rxBufferLength; | |||
| static uint8_t txAddress; | |||
| static uint8_t txBuffer[]; | |||
| static uint8_t txBufferIndex; | |||
| static uint8_t txBufferLength; | |||
| static uint8_t transmitting; | |||
| static void onRequestService(void); | |||
| static void onReceiveService(uint8_t*, int); | |||
| static void (*user_onRequest)(void); | |||
| static void (*user_onReceive)(int); | |||
| static void sda_rising_isr(void); | |||
| static uint8_t sda_pin_num; | |||
| static uint8_t scl_pin_num; | |||
| friend void i2c0_isr(void); | |||
| public: | |||
| TwoWire(); | |||
| void begin(); | |||
| void begin(uint8_t); | |||
| void begin(int); | |||
| void end(); | |||
| void setClock(uint32_t); | |||
| void setSDA(uint8_t); | |||
| void setSCL(uint8_t); | |||
| void beginTransmission(uint8_t); | |||
| void beginTransmission(int); | |||
| uint8_t endTransmission(void); | |||
| uint8_t endTransmission(uint8_t); | |||
| uint8_t requestFrom(uint8_t, uint8_t); | |||
| uint8_t requestFrom(uint8_t, uint8_t, uint8_t); | |||
| uint8_t requestFrom(int, int); | |||
| uint8_t requestFrom(int, int, int); | |||
| virtual size_t write(uint8_t); | |||
| virtual size_t write(const uint8_t *, size_t); | |||
| virtual int available(void); | |||
| virtual int read(void); | |||
| virtual int peek(void); | |||
| virtual void flush(void); | |||
| void onReceive( void (*)(int) ); | |||
| void onRequest( void (*)(void) ); | |||
| // added by Teensyduino installer, for compatibility | |||
| // with pre-1.0 sketches and libraries | |||
| void send(uint8_t b) { write(b); } | |||
| void send(uint8_t *s, uint8_t n) { write(s, n); } | |||
| void send(int n) { write((uint8_t)n); } | |||
| void send(char *s) { write(s); } | |||
| uint8_t receive(void) { | |||
| int c = read(); | |||
| if (c < 0) return 0; | |||
| return c; | |||
| } | |||
| inline size_t write(unsigned long n) { return write((uint8_t)n); } | |||
| inline size_t write(long n) { return write((uint8_t)n); } | |||
| inline size_t write(unsigned int n) { return write((uint8_t)n); } | |||
| inline size_t write(int n) { return write((uint8_t)n); } | |||
| using Print::write; | |||
| }; | |||
| extern TwoWire Wire; | |||
| class TWBRemulation | |||
| { | |||
| public: | |||
| inline TWBRemulation & operator = (int val) __attribute__((always_inline)) { | |||
| if (val == 12 || val == ((F_CPU / 400000) - 16) / 2) { // 22, 52, 112 | |||
| I2C0_C1 = 0; | |||
| #if F_BUS == 120000000 | |||
| I2C0_F = I2C_F_DIV288; // 416 kHz | |||
| #elif F_BUS == 108000000 | |||
| I2C0_F = I2C_F_DIV256; // 422 kHz | |||
| #elif F_BUS == 96000000 | |||
| I2C0_F = I2C_F_DIV240; // 400 kHz | |||
| #elif F_BUS == 90000000 | |||
| I2C0_F = I2C_F_DIV224; // 402 kHz | |||
| #elif F_BUS == 80000000 | |||
| I2C0_F = I2C_F_DIV192; // 416 kHz | |||
| #elif F_BUS == 72000000 | |||
| I2C0_F = I2C_F_DIV192; // 375 kHz | |||
| #elif F_BUS == 64000000 | |||
| I2C0_F = I2C_F_DIV160; // 400 kHz | |||
| #elif F_BUS == 60000000 | |||
| I2C0_F = I2C_F_DIV144; // 416 kHz | |||
| #elif F_BUS == 56000000 | |||
| I2C0_F = I2C_F_DIV144; // 389 kHz | |||
| #elif F_BUS == 54000000 | |||
| I2C0_F = I2C_F_DIV128; // 422 kHz | |||
| #elif F_BUS == 48000000 | |||
| I2C0_F = I2C_F_DIV112; // 400 kHz | |||
| #elif F_BUS == 40000000 | |||
| I2C0_F = I2C_F_DIV96; // 416 kHz | |||
| #elif F_BUS == 36000000 | |||
| I2C0_F = I2C_F_DIV96; // 375 kHz | |||
| #elif F_BUS == 24000000 | |||
| I2C0_F = I2C_F_DIV64; // 375 kHz | |||
| #elif F_BUS == 16000000 | |||
| I2C0_F = I2C_F_DIV40; // 400 kHz | |||
| #elif F_BUS == 8000000 | |||
| I2C0_F = I2C_F_DIV20; // 400 kHz | |||
| #elif F_BUS == 4000000 | |||
| I2C0_F = I2C_F_DIV20; // 200 kHz | |||
| #elif F_BUS == 2000000 | |||
| I2C0_F = I2C_F_DIV20; // 100 kHz | |||
| #endif | |||
| I2C0_C1 = I2C_C1_IICEN; | |||
| } else if (val == 72 || val == ((F_CPU / 100000) - 16) / 2) { // 112, 232, 472 | |||
| I2C0_C1 = 0; | |||
| #if F_BUS == 120000000 | |||
| I2C0_F = I2C_F_DIV1152; // 104 kHz | |||
| #elif F_BUS == 108000000 | |||
| I2C0_F = I2C_F_DIV1024; // 105 kHz | |||
| #elif F_BUS == 96000000 | |||
| I2C0_F = I2C_F_DIV960; // 100 kHz | |||
| #elif F_BUS == 90000000 | |||
| I2C0_F = I2C_F_DIV896; // 100 kHz | |||
| #elif F_BUS == 80000000 | |||
| I2C0_F = I2C_F_DIV768; // 104 kHz | |||
| #elif F_BUS == 72000000 | |||
| I2C0_F = I2C_F_DIV640; // 112 kHz | |||
| #elif F_BUS == 64000000 | |||
| I2C0_F = I2C_F_DIV640; // 100 kHz | |||
| #elif F_BUS == 60000000 | |||
| I2C0_F = I2C_F_DIV576; // 104 kHz | |||
| #elif F_BUS == 56000000 | |||
| I2C0_F = I2C_F_DIV512; // 109 kHz | |||
| #elif F_BUS == 54000000 | |||
| I2C0_F = I2C_F_DIV512; // 105 kHz | |||
| #elif F_BUS == 48000000 | |||
| I2C0_F = I2C_F_DIV480; // 100 kHz | |||
| #elif F_BUS == 40000000 | |||
| I2C0_F = I2C_F_DIV384; // 104 kHz | |||
| #elif F_BUS == 36000000 | |||
| I2C0_F = I2C_F_DIV320; // 113 kHz | |||
| #elif F_BUS == 24000000 | |||
| I2C0_F = I2C_F_DIV240; // 100 kHz | |||
| #elif F_BUS == 16000000 | |||
| I2C0_F = I2C_F_DIV160; // 100 kHz | |||
| #elif F_BUS == 8000000 | |||
| I2C0_F = I2C_F_DIV80; // 100 kHz | |||
| #elif F_BUS == 4000000 | |||
| I2C0_F = I2C_F_DIV40; // 100 kHz | |||
| #elif F_BUS == 2000000 | |||
| I2C0_F = I2C_F_DIV20; // 100 kHz | |||
| #endif | |||
| I2C0_C1 = I2C_C1_IICEN; | |||
| } | |||
| return *this; | |||
| } | |||
| inline operator int () const __attribute__((always_inline)) { | |||
| #if F_BUS == 120000000 | |||
| if (I2C0_F == I2C_F_DIV288) return 12; | |||
| #elif F_BUS == 108000000 | |||
| if (I2C0_F == I2C_F_DIV256) return 12; | |||
| #elif F_BUS == 96000000 | |||
| if (I2C0_F == I2C_F_DIV240) return 12; | |||
| #elif F_BUS == 90000000 | |||
| if (I2C0_F == I2C_F_DIV224) return 12; | |||
| #elif F_BUS == 80000000 | |||
| if (I2C0_F == I2C_F_DIV192) return 12; | |||
| #elif F_BUS == 72000000 | |||
| if (I2C0_F == I2C_F_DIV192) return 12; | |||
| #elif F_BUS == 64000000 | |||
| if (I2C0_F == I2C_F_DIV160) return 12; | |||
| #elif F_BUS == 60000000 | |||
| if (I2C0_F == I2C_F_DIV144) return 12; | |||
| #elif F_BUS == 56000000 | |||
| if (I2C0_F == I2C_F_DIV144) return 12; | |||
| #elif F_BUS == 54000000 | |||
| if (I2C0_F == I2C_F_DIV128) return 12; | |||
| #elif F_BUS == 48000000 | |||
| if (I2C0_F == I2C_F_DIV112) return 12; | |||
| #elif F_BUS == 40000000 | |||
| if (I2C0_F == I2C_F_DIV96) return 12; | |||
| #elif F_BUS == 36000000 | |||
| if (I2C0_F == I2C_F_DIV96) return 12; | |||
| #elif F_BUS == 24000000 | |||
| if (I2C0_F == I2C_F_DIV64) return 12; | |||
| #elif F_BUS == 16000000 | |||
| if (I2C0_F == I2C_F_DIV40) return 12; | |||
| #elif F_BUS == 8000000 | |||
| if (I2C0_F == I2C_F_DIV20) return 12; | |||
| #elif F_BUS == 4000000 | |||
| if (I2C0_F == I2C_F_DIV20) return 12; | |||
| #endif | |||
| return 72; | |||
| } | |||
| }; | |||
| extern TWBRemulation TWBR; | |||
| #endif | |||
| #endif | |||