Browse Source

Add hardware access through port reference

main
PaulStoffregen 7 years ago
parent
commit
31a33832a8
2 changed files with 147 additions and 149 deletions
  1. +138
    -148
      WireKinetis.cpp
  2. +9
    -1
      WireKinetis.h

+ 138
- 148
WireKinetis.cpp View File

@@ -28,9 +28,23 @@
#include "core_pins.h"
#include "Wire.h"

// undefine these, so we can't accidentally access the hardware directly.
#undef I2C0_A1
#undef I2C0_F
#undef I2C0_C1
#undef I2C0_S
#undef I2C0_D
#undef I2C0_C2
#undef I2C0_FLT
#undef I2C0_RA
#undef I2C0_SMB
#undef I2C0_A2
#undef I2C0_SLTH
#undef I2C0_SLTL

void sda_rising_isr(void);

TwoWire::TwoWire()
TwoWire::TwoWire(KINETIS_I2C_t &myport) : port(myport)
{
rxBufferIndex = 0;
rxBufferLength = 0;
@@ -50,7 +64,7 @@ void TwoWire::begin(void)

slave_mode = 0;
SIM_SCGC4 |= SIM_SCGC4_I2C0; // TODO: use bitband
I2C0_C1 = 0;
port.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
@@ -85,8 +99,8 @@ void TwoWire::begin(void)
#endif
}
setClock(100000);
I2C0_C2 = I2C_C2_HDRS;
I2C0_C1 = I2C_C1_IICEN;
port.C2 = I2C_C2_HDRS;
port.C1 = I2C_C1_IICEN;
//pinMode(3, OUTPUT);
//pinMode(4, OUTPUT);
}
@@ -97,156 +111,156 @@ void TwoWire::setClock(uint32_t frequency)

#if F_BUS == 120000000
if (frequency < 400000) {
I2C0_F = I2C_F_DIV1152; // 104 kHz
port.F = I2C_F_DIV1152; // 104 kHz
} else if (frequency < 1000000) {
I2C0_F = I2C_F_DIV288; // 416 kHz
port.F = I2C_F_DIV288; // 416 kHz
} else {
I2C0_F = I2C_F_DIV128; // 0.94 MHz
port.F = I2C_F_DIV128; // 0.94 MHz
}
I2C0_FLT = 4;
port.FLT = 4;
#elif F_BUS == 108000000
if (frequency < 400000) {
I2C0_F = I2C_F_DIV1024; // 105 kHz
port.F = I2C_F_DIV1024; // 105 kHz
} else if (frequency < 1000000) {
I2C0_F = I2C_F_DIV256; // 422 kHz
port.F = I2C_F_DIV256; // 422 kHz
} else {
I2C0_F = I2C_F_DIV112; // 0.96 MHz
port.F = I2C_F_DIV112; // 0.96 MHz
}
I2C0_FLT = 4;
port.FLT = 4;
#elif F_BUS == 96000000
if (frequency < 400000) {
I2C0_F = I2C_F_DIV960; // 100 kHz
port.F = I2C_F_DIV960; // 100 kHz
} else if (frequency < 1000000) {
I2C0_F = I2C_F_DIV240; // 400 kHz
port.F = I2C_F_DIV240; // 400 kHz
} else {
I2C0_F = I2C_F_DIV96; // 1.0 MHz
port.F = I2C_F_DIV96; // 1.0 MHz
}
I2C0_FLT = 4;
port.FLT = 4;
#elif F_BUS == 90000000
if (frequency < 400000) {
I2C0_F = I2C_F_DIV896; // 100 kHz
port.F = I2C_F_DIV896; // 100 kHz
} else if (frequency < 1000000) {
I2C0_F = I2C_F_DIV224; // 402 kHz
port.F = I2C_F_DIV224; // 402 kHz
} else {
I2C0_F = I2C_F_DIV88; // 1.02 MHz
port.F = I2C_F_DIV88; // 1.02 MHz
}
I2C0_FLT = 4;
port.FLT = 4;
#elif F_BUS == 80000000
if (frequency < 400000) {
I2C0_F = I2C_F_DIV768; // 104 kHz
port.F = I2C_F_DIV768; // 104 kHz
} else if (frequency < 1000000) {
I2C0_F = I2C_F_DIV192; // 416 kHz
port.F = I2C_F_DIV192; // 416 kHz
} else {
I2C0_F = I2C_F_DIV80; // 1.0 MHz
port.F = I2C_F_DIV80; // 1.0 MHz
}
I2C0_FLT = 4;
port.FLT = 4;
#elif F_BUS == 72000000
if (frequency < 400000) {
I2C0_F = I2C_F_DIV640; // 112 kHz
port.F = I2C_F_DIV640; // 112 kHz
} else if (frequency < 1000000) {
I2C0_F = I2C_F_DIV192; // 375 kHz
port.F = I2C_F_DIV192; // 375 kHz
} else {
I2C0_F = I2C_F_DIV72; // 1.0 MHz
port.F = I2C_F_DIV72; // 1.0 MHz
}
I2C0_FLT = 4;
port.FLT = 4;
#elif F_BUS == 64000000
if (frequency < 400000) {
I2C0_F = I2C_F_DIV640; // 100 kHz
port.F = I2C_F_DIV640; // 100 kHz
} else if (frequency < 1000000) {
I2C0_F = I2C_F_DIV160; // 400 kHz
port.F = I2C_F_DIV160; // 400 kHz
} else {
I2C0_F = I2C_F_DIV64; // 1.0 MHz
port.F = I2C_F_DIV64; // 1.0 MHz
}
I2C0_FLT = 4;
port.FLT = 4;
#elif F_BUS == 60000000
if (frequency < 400000) {
I2C0_F = 0x2C; // 104 kHz
port.F = 0x2C; // 104 kHz
} else if (frequency < 1000000) {
I2C0_F = 0x1C; // 416 kHz
port.F = 0x1C; // 416 kHz
} else {
I2C0_F = 0x12; // 938 kHz
port.F = 0x12; // 938 kHz
}
I2C0_FLT = 4;
port.FLT = 4;
#elif F_BUS == 56000000
if (frequency < 400000) {
I2C0_F = 0x2B; // 109 kHz
port.F = 0x2B; // 109 kHz
} else if (frequency < 1000000) {
I2C0_F = 0x1C; // 389 kHz
port.F = 0x1C; // 389 kHz
} else {
I2C0_F = 0x0E; // 1 MHz
port.F = 0x0E; // 1 MHz
}
I2C0_FLT = 4;
port.FLT = 4;
#elif F_BUS == 54000000
if (frequency < 400000) {
I2C0_F = I2C_F_DIV512; // 105 kHz
port.F = I2C_F_DIV512; // 105 kHz
} else if (frequency < 1000000) {
I2C0_F = I2C_F_DIV128; // 422 kHz
port.F = I2C_F_DIV128; // 422 kHz
} else {
I2C0_F = I2C_F_DIV56; // 0.96 MHz
port.F = I2C_F_DIV56; // 0.96 MHz
}
I2C0_FLT = 4;
port.FLT = 4;
#elif F_BUS == 48000000
if (frequency < 400000) {
I2C0_F = 0x27; // 100 kHz
port.F = 0x27; // 100 kHz
} else if (frequency < 1000000) {
I2C0_F = 0x1A; // 400 kHz
port.F = 0x1A; // 400 kHz
} else {
I2C0_F = 0x0D; // 1 MHz
port.F = 0x0D; // 1 MHz
}
I2C0_FLT = 4;
port.FLT = 4;
#elif F_BUS == 40000000
if (frequency < 400000) {
I2C0_F = 0x29; // 104 kHz
port.F = 0x29; // 104 kHz
} else if (frequency < 1000000) {
I2C0_F = 0x19; // 416 kHz
port.F = 0x19; // 416 kHz
} else {
I2C0_F = 0x0B; // 1 MHz
port.F = 0x0B; // 1 MHz
}
I2C0_FLT = 3;
port.FLT = 3;
#elif F_BUS == 36000000
if (frequency < 400000) {
I2C0_F = 0x28; // 113 kHz
port.F = 0x28; // 113 kHz
} else if (frequency < 1000000) {
I2C0_F = 0x19; // 375 kHz
port.F = 0x19; // 375 kHz
} else {
I2C0_F = 0x0A; // 1 MHz
port.F = 0x0A; // 1 MHz
}
I2C0_FLT = 3;
port.FLT = 3;
#elif F_BUS == 24000000
if (frequency < 400000) {
I2C0_F = 0x1F; // 100 kHz
port.F = 0x1F; // 100 kHz
} else if (frequency < 1000000) {
I2C0_F = 0x12; // 375 kHz
port.F = 0x12; // 375 kHz
} else {
I2C0_F = 0x02; // 1 MHz
port.F = 0x02; // 1 MHz
}
I2C0_FLT = 2;
port.FLT = 2;
#elif F_BUS == 16000000
if (frequency < 400000) {
I2C0_F = 0x20; // 100 kHz
port.F = 0x20; // 100 kHz
} else if (frequency < 1000000) {
I2C0_F = 0x07; // 400 kHz
port.F = 0x07; // 400 kHz
} else {
I2C0_F = 0x00; // 800 MHz
port.F = 0x00; // 800 MHz
}
I2C0_FLT = 1;
port.FLT = 1;
#elif F_BUS == 8000000
if (frequency < 400000) {
I2C0_F = 0x14; // 100 kHz
port.F = 0x14; // 100 kHz
} else {
I2C0_F = 0x00; // 400 kHz
port.F = 0x00; // 400 kHz
}
I2C0_FLT = 1;
port.FLT = 1;
#elif F_BUS == 4000000
if (frequency < 400000) {
I2C0_F = 0x07; // 100 kHz
port.F = 0x07; // 100 kHz
} else {
I2C0_F = 0x00; // 200 kHz
port.F = 0x00; // 200 kHz
}
I2C0_FLT = 1;
port.FLT = 1;
#elif F_BUS == 2000000
I2C0_F = 0x00; // 100 kHz
I2C0_FLT = 1;
port.F = 0x00; // 100 kHz
port.FLT = 1;
#else
#error "F_BUS must be 120, 108, 96, 90, 80, 72, 64, 60, 56, 54, 48, 40, 36, 24, 16, 8, 4 or 2 MHz"
#endif
@@ -325,9 +339,9 @@ void TwoWire::setSCL(uint8_t pin)
void TwoWire::begin(uint8_t address)
{
begin();
I2C0_A1 = address << 1;
port.A1 = address << 1;
slave_mode = 1;
I2C0_C1 = I2C_C1_IICEN | I2C_C1_IICIE;
port.C1 = I2C_C1_IICEN | I2C_C1_IICIE;
NVIC_ENABLE_IRQ(IRQ_I2C0);
}

@@ -335,7 +349,7 @@ void TwoWire::end()
{
if (!(SIM_SCGC4 & SIM_SCGC4_I2C0)) return;
NVIC_DISABLE_IRQ(IRQ_I2C0);
I2C0_C1 = 0;
port.C1 = 0;
if (sda_pin_num == 18) {
CORE_PIN18_CONFIG = 0;
} else if (sda_pin_num == 17) {
@@ -370,11 +384,11 @@ void i2c0_isr(void)
uint8_t status, c1, data;
static uint8_t receiving=0;

status = I2C0_S;
status = Wire.port.S;
//serial_print(".");
if (status & I2C_S_ARBL) {
// Arbitration Lost
I2C0_S = I2C_S_ARBL;
Wire.port.S = I2C_S_ARBL;
//serial_print("a");
if (receiving && Wire.rxBufferLength > 0) {
// TODO: does this detect the STOP condition in slave receive mode?
@@ -401,31 +415,31 @@ void i2c0_isr(void)
Wire.txBufferLength = 1;
Wire.txBuffer[0] = 0;
}
I2C0_C1 = I2C_C1_IICEN | I2C_C1_IICIE | I2C_C1_TX;
I2C0_D = Wire.txBuffer[0];
Wire.port.C1 = I2C_C1_IICEN | I2C_C1_IICIE | I2C_C1_TX;
Wire.port.D = Wire.txBuffer[0];
Wire.txBufferIndex = 1;
} else {
// Begin Slave Receive
//serial_print("R");
receiving = 1;
Wire.rxBufferLength = 0;
I2C0_C1 = I2C_C1_IICEN | I2C_C1_IICIE;
data = I2C0_D;
Wire.port.C1 = I2C_C1_IICEN | I2C_C1_IICIE;
data = Wire.port.D;
}
I2C0_S = I2C_S_IICIF;
Wire.port.S = I2C_S_IICIF;
return;
}
#if defined(KINETISL)
c1 = I2C0_FLT;
c1 = Wire.port.FLT;
if ((c1 & I2C_FLT_STOPF) && (c1 & I2C_FLT_STOPIE)) {
I2C0_FLT = c1 & ~I2C_FLT_STOPIE;
Wire.port.FLT = c1 & ~I2C_FLT_STOPIE;
if (Wire.user_onReceive != NULL) {
Wire.rxBufferIndex = 0;
Wire.user_onReceive(Wire.rxBufferLength);
}
}
#endif
c1 = I2C0_C1;
c1 = Wire.port.C1;
if (c1 & I2C_C1_TX) {
// Continue Slave Transmit
//serial_print("t");
@@ -433,16 +447,16 @@ void i2c0_isr(void)
//serial_print(".");
// Master ACK'd previous byte
if (Wire.txBufferIndex < Wire.txBufferLength) {
I2C0_D = Wire.txBuffer[Wire.txBufferIndex++];
Wire.port.D = Wire.txBuffer[Wire.txBufferIndex++];
} else {
I2C0_D = 0;
Wire.port.D = 0;
}
I2C0_C1 = I2C_C1_IICEN | I2C_C1_IICIE | I2C_C1_TX;
Wire.port.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;
Wire.port.C1 = I2C_C1_IICEN | I2C_C1_IICIE;
data = Wire.port.D;
}
} else {
// Continue Slave Receive
@@ -450,17 +464,17 @@ void i2c0_isr(void)
#if defined(KINETISK)
attachInterrupt(18, sda_rising_isr, RISING);
#elif defined(KINETISL)
I2C0_FLT |= I2C_FLT_STOPIE;
Wire.port.FLT |= I2C_FLT_STOPIE;
#endif
//digitalWriteFast(4, HIGH);
data = I2C0_D;
data = Wire.port.D;
//serial_phex(data);
if (Wire.rxBufferLength < BUFFER_LENGTH && receiving) {
Wire.rxBuffer[Wire.rxBufferLength++] = data;
}
//digitalWriteFast(4, LOW);
}
I2C0_S = I2C_S_IICIF;
Wire.port.S = I2C_S_IICIF;
}

// Detects the stop condition that terminates a slave receive transfer.
@@ -469,7 +483,7 @@ void i2c0_isr(void)
void sda_rising_isr(void)
{
//digitalWrite(3, HIGH);
if (!(I2C0_S & I2C_S_BUSY)) {
if (!(Wire.port.S & I2C_S_BUSY)) {
detachInterrupt(18);
if (Wire.user_onReceive != NULL) {
Wire.rxBufferIndex = 0;
@@ -494,30 +508,6 @@ void sda_rising_isr(void)
// 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;
}

size_t TwoWire::write(uint8_t data)
{
if (transmitting || slave_mode) {
@@ -552,12 +542,12 @@ 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;
port.S = I2C_S_IICIF | I2C_S_ARBL;
// now take control of the bus...
if (I2C0_C1 & I2C_C1_MST) {
if (port.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;
port.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:");
@@ -566,15 +556,15 @@ uint8_t TwoWire::endTransmission(uint8_t sendStop)
//Serial.write('.') ;
if (millis() - wait_begin > 15) {
// bus stuck busy too long
I2C0_C1 = 0;
I2C0_C1 = I2C_C1_IICEN;
port.C1 = 0;
port.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;
port.C1 = I2C_C1_IICEN | I2C_C1_MST | I2C_C1_TX;
}
// wait until start condition establishes control of the bus
while (1) {
@@ -583,27 +573,27 @@ uint8_t TwoWire::endTransmission(uint8_t sendStop)
}
// transmit the address and data
for (i=0; i < txBufferLength; i++) {
I2C0_D = txBuffer[i];
port.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;
port.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;
//Serial.printf(" c1=%02X ", port.C1);
port.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;
port.C1 = I2C_C1_IICEN;
ret = 4; // 4:other error
break;
}
@@ -620,7 +610,7 @@ uint8_t TwoWire::endTransmission(uint8_t sendStop)
}
if (sendStop) {
// send the stop condition
I2C0_C1 = I2C_C1_IICEN;
port.C1 = I2C_C1_IICEN;
// TODO: do we wait for this somehow?
}
transmitting = 0;
@@ -639,64 +629,64 @@ uint8_t TwoWire::requestFrom(uint8_t address, uint8_t length, uint8_t sendStop)
rxBufferLength = 0;
//serial_print("requestFrom\n");
// clear the status flags
I2C0_S = I2C_S_IICIF | I2C_S_ARBL;
port.S = I2C_S_IICIF | I2C_S_ARBL;
// now take control of the bus...
if (I2C0_C1 & I2C_C1_MST) {
if (port.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;
port.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;
port.C1 = I2C_C1_IICEN | I2C_C1_MST | I2C_C1_TX;
}
// send the address
I2C0_D = (address << 1) | 1;
port.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;
port.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);
port.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;
port.C1 = I2C_C1_IICEN | I2C_C1_MST | I2C_C1_TXAK;
} else {
I2C0_C1 = I2C_C1_IICEN | I2C_C1_MST;
port.C1 = I2C_C1_IICEN | I2C_C1_MST;
}
tmp = I2C0_D; // initiate the first receive
tmp = port.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 (length == 1) port.C1 = I2C_C1_IICEN | I2C_C1_MST | I2C_C1_TXAK;
if (count < BUFFER_LENGTH) {
rxBuffer[count++] = I2C0_D;
rxBuffer[count++] = port.D;
} else {
tmp = I2C0_D;
tmp = port.D;
}
}
i2c_wait();
I2C0_C1 = I2C_C1_IICEN | I2C_C1_MST | I2C_C1_TX;
port.C1 = I2C_C1_IICEN | I2C_C1_MST | I2C_C1_TX;
if (count < BUFFER_LENGTH) {
rxBuffer[count++] = I2C0_D;
rxBuffer[count++] = port.D;
} else {
tmp = I2C0_D;
tmp = port.D;
}
if (sendStop) I2C0_C1 = I2C_C1_IICEN;
if (sendStop) port.C1 = I2C_C1_IICEN;
rxBufferLength = count;
return count;
}



TwoWire Wire;
TwoWire Wire(KINETIS_I2C0);




+ 9
- 1
WireKinetis.h View File

@@ -42,7 +42,7 @@ extern "C" void i2c0_isr(void);
class TwoWire : public Stream
{
public:
TwoWire();
TwoWire(KINETIS_I2C_t &myport);
void begin();
void begin(uint8_t address);
void begin(int address) {
@@ -128,6 +128,14 @@ public:
}
using Print::write;
private:
uint8_t i2c_status(void) {
return port.S;
}
void i2c_wait(void) {
while (!(port.S & I2C_S_IICIF)) ; // wait (TODO: timeout)
port.S = I2C_S_IICIF;
}
KINETIS_I2C_t &port;
uint8_t rxBuffer[BUFFER_LENGTH];
uint8_t rxBufferIndex;
uint8_t rxBufferLength;

Loading…
Cancel
Save