|
|
|
|
|
|
|
|
|
|
|
|
|
|
#include "debug/printf.h" |
|
|
#include "debug/printf.h" |
|
|
|
|
|
|
|
|
void i2c_setclock(uint32_t frequency); |
|
|
|
|
|
|
|
|
|
|
|
void TwoWire::begin(void) |
|
|
void TwoWire::begin(void) |
|
|
{ |
|
|
{ |
|
|
// use 24 MHz clock |
|
|
// use 24 MHz clock |
|
|
CCM_CSCDR2 = (CCM_CSCDR2 & ~CCM_CSCDR2_LPI2C_CLK_PODF(63)) | CCM_CSCDR2_LPI2C_CLK_SEL; |
|
|
CCM_CSCDR2 = (CCM_CSCDR2 & ~CCM_CSCDR2_LPI2C_CLK_PODF(63)) | CCM_CSCDR2_LPI2C_CLK_SEL; |
|
|
CCM_CCGR2 |= CCM_CCGR2_LPI2C1(CCM_CCGR_ON); |
|
|
|
|
|
LPI2C1_MCR = LPI2C_MCR_RST; |
|
|
|
|
|
i2c_setclock(100000); |
|
|
|
|
|
IOMUXC_SW_MUX_CTL_PAD_GPIO_AD_B1_00 = 3 | 0x10; // 18/A4 AD_B1_01 GPIO1.17 I2C1_SDA |
|
|
|
|
|
IOMUXC_SW_MUX_CTL_PAD_GPIO_AD_B1_01 = 3 | 0x10; // 19/A5 AD_B1_00 GPIO1.16 I2C1_SCL |
|
|
|
|
|
IOMUXC_LPI2C1_SCL_SELECT_INPUT = 1; |
|
|
|
|
|
IOMUXC_LPI2C1_SDA_SELECT_INPUT = 1; |
|
|
|
|
|
IOMUXC_SW_PAD_CTL_PAD_GPIO_AD_B1_00 |= IOMUXC_PAD_PKE | IOMUXC_PAD_PUE | IOMUXC_PAD_PUS(3); |
|
|
|
|
|
IOMUXC_SW_PAD_CTL_PAD_GPIO_AD_B1_01 |= IOMUXC_PAD_PKE | IOMUXC_PAD_PUE | IOMUXC_PAD_PUS(3); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void TwoWire::setClock(uint32_t frequency) |
|
|
|
|
|
{ |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void TwoWire::setSDA(uint8_t pin) |
|
|
|
|
|
{ |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void TwoWire::setSCL(uint8_t pin) |
|
|
|
|
|
{ |
|
|
|
|
|
|
|
|
hardware.clock_gate_register |= hardware.clock_gate_mask; |
|
|
|
|
|
port->MCR = LPI2C_MCR_RST; |
|
|
|
|
|
setClock(100000); |
|
|
|
|
|
hardware.sda_mux_register = hardware.sda_mux_value; |
|
|
|
|
|
hardware.scl_mux_register = hardware.scl_mux_value; |
|
|
|
|
|
hardware.sda_input_register = hardware.sda_input_value; |
|
|
|
|
|
hardware.scl_input_register = hardware.scl_input_value; |
|
|
|
|
|
hardware.sda_pad_register |= IOMUXC_PAD_PKE | IOMUXC_PAD_PUE | IOMUXC_PAD_PUS(3); |
|
|
|
|
|
hardware.scl_pad_register |= IOMUXC_PAD_PKE | IOMUXC_PAD_PUE | IOMUXC_PAD_PUS(3); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
void TwoWire::begin(uint8_t address) |
|
|
void TwoWire::begin(uint8_t address) |
|
|
{ |
|
|
{ |
|
|
|
|
|
// TODO: slave mode |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
void TwoWire::end() |
|
|
void TwoWire::end() |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// wait while bus is busy |
|
|
// wait while bus is busy |
|
|
while (1) { |
|
|
while (1) { |
|
|
status = LPI2C1_MSR; // pg 2899 & 2892 |
|
|
|
|
|
|
|
|
status = port->MSR; // pg 2899 & 2892 |
|
|
if (!(status & LPI2C_MSR_BBF)) break; // bus is available |
|
|
if (!(status & LPI2C_MSR_BBF)) break; // bus is available |
|
|
if (status & LPI2C_MSR_MBF) break; // we already have bus control |
|
|
if (status & LPI2C_MSR_MBF) break; // we already have bus control |
|
|
// TODO: timeout... |
|
|
// TODO: timeout... |
|
|
|
|
|
|
|
|
//printf("m=%x\n", status); |
|
|
//printf("m=%x\n", status); |
|
|
|
|
|
|
|
|
// TODO: is this correct if the prior use didn't send stop? |
|
|
// TODO: is this correct if the prior use didn't send stop? |
|
|
//LPI2C1_MSR = LPI2C_MSR_PLTF | LPI2C_MSR_ALF | LPI2C_MSR_NDF | LPI2C_MSR_SDF; // clear flags |
|
|
|
|
|
LPI2C1_MSR = status; |
|
|
|
|
|
|
|
|
//port->MSR = LPI2C_MSR_PLTF | LPI2C_MSR_ALF | LPI2C_MSR_NDF | LPI2C_MSR_SDF; // clear flags |
|
|
|
|
|
port->MSR = status; |
|
|
|
|
|
|
|
|
//printf("MSR=%lX, MFSR=%lX\n", status, LPI2C1_MFSR); |
|
|
|
|
|
|
|
|
//printf("MSR=%lX, MFSR=%lX\n", status, port->MFSR); |
|
|
//elapsedMillis timeout=0; |
|
|
//elapsedMillis timeout=0; |
|
|
|
|
|
|
|
|
while (1) { |
|
|
while (1) { |
|
|
// transmit stuff, if we haven't already |
|
|
// transmit stuff, if we haven't already |
|
|
if (i <= len) { |
|
|
if (i <= len) { |
|
|
uint32_t fifo_used = LPI2C1_MFSR & 0x07; // pg 2914 |
|
|
|
|
|
|
|
|
uint32_t fifo_used = port->MFSR & 0x07; // pg 2914 |
|
|
//if (fifo_used < 4) printf("t=%ld\n", fifo_used); |
|
|
//if (fifo_used < 4) printf("t=%ld\n", fifo_used); |
|
|
while (fifo_used < 4) { |
|
|
while (fifo_used < 4) { |
|
|
if (i == 0) { |
|
|
if (i == 0) { |
|
|
//printf("start %x\n", txBuffer[0]); |
|
|
//printf("start %x\n", txBuffer[0]); |
|
|
LPI2C1_MTDR = LPI2C_MTDR_CMD_START | txBuffer[0]; |
|
|
|
|
|
|
|
|
port->MTDR = LPI2C_MTDR_CMD_START | txBuffer[0]; |
|
|
i = 1; |
|
|
i = 1; |
|
|
} else if (i < len) { |
|
|
} else if (i < len) { |
|
|
LPI2C1_MTDR = LPI2C_MTDR_CMD_TRANSMIT | txBuffer[i++]; |
|
|
|
|
|
|
|
|
port->MTDR = LPI2C_MTDR_CMD_TRANSMIT | txBuffer[i++]; |
|
|
} else { |
|
|
} else { |
|
|
if (sendStop) LPI2C1_MTDR = LPI2C_MTDR_CMD_STOP; |
|
|
|
|
|
|
|
|
if (sendStop) port->MTDR = LPI2C_MTDR_CMD_STOP; |
|
|
i++; |
|
|
i++; |
|
|
break; |
|
|
break; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
// monitor status |
|
|
// monitor status |
|
|
status = LPI2C1_MSR; // pg 2899 & 2892 |
|
|
|
|
|
|
|
|
status = port->MSR; // pg 2899 & 2892 |
|
|
if (status & LPI2C_MSR_ALF) { |
|
|
if (status & LPI2C_MSR_ALF) { |
|
|
//printf("arbitration lost\n"); |
|
|
//printf("arbitration lost\n"); |
|
|
return 4; // we lost bus arbitration to another master |
|
|
return 4; // we lost bus arbitration to another master |
|
|
} |
|
|
} |
|
|
if (status & LPI2C_MSR_NDF) { |
|
|
if (status & LPI2C_MSR_NDF) { |
|
|
//printf("NACK, f=%d, i=%d\n", LPI2C1_MFSR & 0x07, i); |
|
|
|
|
|
|
|
|
//printf("NACK, f=%d, i=%d\n", port->MFSR & 0x07, i); |
|
|
// TODO: check that hardware really sends stop automatically |
|
|
// TODO: check that hardware really sends stop automatically |
|
|
LPI2C1_MCR = LPI2C_MCR_MEN | LPI2C_MCR_RTF; // clear the FIFO |
|
|
|
|
|
|
|
|
port->MCR = LPI2C_MCR_MEN | LPI2C_MCR_RTF; // clear the FIFO |
|
|
return 2; // NACK for address |
|
|
return 2; // NACK for address |
|
|
//return 3; // NACK for data TODO: how to discern addr from data? |
|
|
//return 3; // NACK for data TODO: how to discern addr from data? |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
return 0; |
|
|
return 0; |
|
|
} |
|
|
} |
|
|
} else { |
|
|
} else { |
|
|
uint32_t fifo_used = LPI2C1_MFSR & 0x07; // pg 2914 |
|
|
|
|
|
|
|
|
uint32_t fifo_used = port->MFSR & 0x07; // pg 2914 |
|
|
if (fifo_used == 0) { |
|
|
if (fifo_used == 0) { |
|
|
//digitalWriteFast(15, HIGH); |
|
|
//digitalWriteFast(15, HIGH); |
|
|
//delayMicroseconds(2); |
|
|
//delayMicroseconds(2); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// wait while bus is busy |
|
|
// wait while bus is busy |
|
|
while (1) { |
|
|
while (1) { |
|
|
status = LPI2C1_MSR; // pg 2899 & 2892 |
|
|
|
|
|
|
|
|
status = port->MSR; // pg 2899 & 2892 |
|
|
if (!(status & LPI2C_MSR_BBF)) break; // bus is available |
|
|
if (!(status & LPI2C_MSR_BBF)) break; // bus is available |
|
|
if (status & LPI2C_MSR_MBF) break; // we already have bus control |
|
|
if (status & LPI2C_MSR_MBF) break; // we already have bus control |
|
|
// TODO: timeout... |
|
|
// TODO: timeout... |
|
|
|
|
|
|
|
|
//printf("idle2, msr=%x\n", status); |
|
|
//printf("idle2, msr=%x\n", status); |
|
|
|
|
|
|
|
|
// TODO: is this correct if the prior use didn't send stop? |
|
|
// TODO: is this correct if the prior use didn't send stop? |
|
|
LPI2C1_MSR = LPI2C_MSR_PLTF | LPI2C_MSR_ALF | LPI2C_MSR_NDF | LPI2C_MSR_SDF; // clear flags |
|
|
|
|
|
|
|
|
port->MSR = LPI2C_MSR_PLTF | LPI2C_MSR_ALF | LPI2C_MSR_NDF | LPI2C_MSR_SDF; // clear flags |
|
|
|
|
|
|
|
|
//printf("MSR=%lX, MFSR=%lX\n", status, LPI2C1_MFSR); |
|
|
|
|
|
|
|
|
//printf("MSR=%lX, MFSR=%lX\n", status, port->MFSR); |
|
|
address = (address & 0x7F) << 1; |
|
|
address = (address & 0x7F) << 1; |
|
|
if (length < 1) length = 1; |
|
|
if (length < 1) length = 1; |
|
|
if (length > 255) length = 255; |
|
|
if (length > 255) length = 255; |
|
|
|
|
|
|
|
|
while (1) { |
|
|
while (1) { |
|
|
// transmit stuff, if we haven't already |
|
|
// transmit stuff, if we haven't already |
|
|
if (cmd < 3) { |
|
|
if (cmd < 3) { |
|
|
fifo = LPI2C1_MFSR & 0x07; // pg 2914 |
|
|
|
|
|
|
|
|
fifo = port->MFSR & 0x07; // pg 2914 |
|
|
//if (fifo < 4) printf("t=%ld\n", fifo); |
|
|
//if (fifo < 4) printf("t=%ld\n", fifo); |
|
|
while (fifo < 4 && cmd < 3) { |
|
|
while (fifo < 4 && cmd < 3) { |
|
|
if (cmd == 0) { |
|
|
if (cmd == 0) { |
|
|
LPI2C1_MTDR = LPI2C_MTDR_CMD_START | 1 | address; |
|
|
|
|
|
|
|
|
port->MTDR = LPI2C_MTDR_CMD_START | 1 | address; |
|
|
} else if (cmd == 1) { |
|
|
} else if (cmd == 1) { |
|
|
// causes bus stuck... need way to recover |
|
|
// causes bus stuck... need way to recover |
|
|
//LPI2C1_MTDR = LPI2C_MTDR_CMD_START | (length - 1); |
|
|
|
|
|
LPI2C1_MTDR = LPI2C_MTDR_CMD_RECEIVE | (length - 1); |
|
|
|
|
|
|
|
|
//port->MTDR = LPI2C_MTDR_CMD_START | (length - 1); |
|
|
|
|
|
port->MTDR = LPI2C_MTDR_CMD_RECEIVE | (length - 1); |
|
|
} else { |
|
|
} else { |
|
|
if (sendStop) LPI2C1_MTDR = LPI2C_MTDR_CMD_STOP; |
|
|
|
|
|
|
|
|
if (sendStop) port->MTDR = LPI2C_MTDR_CMD_STOP; |
|
|
} |
|
|
} |
|
|
cmd++; |
|
|
cmd++; |
|
|
fifo = fifo + 1; |
|
|
fifo = fifo + 1; |
|
|
|
|
|
|
|
|
} |
|
|
} |
|
|
// receive stuff |
|
|
// receive stuff |
|
|
if (rxBufferLength < sizeof(rxBuffer)) { |
|
|
if (rxBufferLength < sizeof(rxBuffer)) { |
|
|
fifo = (LPI2C1_MFSR >> 16) & 0x07; |
|
|
|
|
|
|
|
|
fifo = (port->MFSR >> 16) & 0x07; |
|
|
//if (fifo > 0) printf("r=%ld\n", fifo); |
|
|
//if (fifo > 0) printf("r=%ld\n", fifo); |
|
|
while (fifo > 0 && rxBufferLength < sizeof(rxBuffer)) { |
|
|
while (fifo > 0 && rxBufferLength < sizeof(rxBuffer)) { |
|
|
rxBuffer[rxBufferLength++] = LPI2C1_MRDR; |
|
|
|
|
|
|
|
|
rxBuffer[rxBufferLength++] = port->MRDR; |
|
|
fifo = fifo - 1; |
|
|
fifo = fifo - 1; |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
// monitor status |
|
|
// monitor status |
|
|
status = LPI2C1_MSR; // pg 2899 & 2892 |
|
|
|
|
|
|
|
|
status = port->MSR; // pg 2899 & 2892 |
|
|
if (status & LPI2C_MSR_ALF) { |
|
|
if (status & LPI2C_MSR_ALF) { |
|
|
//printf("arbitration lost\n"); |
|
|
//printf("arbitration lost\n"); |
|
|
break; |
|
|
break; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
PROGMEM |
|
|
constexpr TwoWire::I2C_Hardware_t TwoWire::i2c1_hardware = { |
|
|
constexpr TwoWire::I2C_Hardware_t TwoWire::i2c1_hardware = { |
|
|
CCM_CCGR2, CCM_CCGR2_LPI2C1(CCM_CCGR_ON), |
|
|
CCM_CCGR2, CCM_CCGR2_LPI2C1(CCM_CCGR_ON), |
|
|
18, 17, 255, 255, 255, |
|
|
|
|
|
2, 2, 0, 0, 0, |
|
|
|
|
|
19, 16, 255, 255, 255, |
|
|
|
|
|
2, 2, 0, 0, 0, |
|
|
|
|
|
|
|
|
IOMUXC_SW_MUX_CTL_PAD_GPIO_AD_B1_00, // 18/A4 AD_B1_01 GPIO1.17 I2C1_SDA |
|
|
|
|
|
IOMUXC_SW_MUX_CTL_PAD_GPIO_AD_B1_01, // 19/A5 AD_B1_00 GPIO1.16 I2C1_SCL |
|
|
|
|
|
IOMUXC_SW_PAD_CTL_PAD_GPIO_AD_B1_00, |
|
|
|
|
|
IOMUXC_SW_PAD_CTL_PAD_GPIO_AD_B1_01, |
|
|
|
|
|
IOMUXC_LPI2C1_SDA_SELECT_INPUT, |
|
|
|
|
|
IOMUXC_LPI2C1_SCL_SELECT_INPUT, |
|
|
|
|
|
3 | 0x10, |
|
|
|
|
|
3 | 0x10, |
|
|
|
|
|
1, |
|
|
|
|
|
1, |
|
|
IRQ_LPI2C1 |
|
|
IRQ_LPI2C1 |
|
|
}; |
|
|
}; |
|
|
|
|
|
TwoWire Wire(&IMXRT_LPI2C1, TwoWire::i2c1_hardware); |
|
|
|
|
|
|
|
|
|
|
|
PROGMEM |
|
|
|
|
|
constexpr TwoWire::I2C_Hardware_t TwoWire::i2c3_hardware = { |
|
|
|
|
|
CCM_CCGR2, CCM_CCGR2_LPI2C3(CCM_CCGR_ON), |
|
|
|
|
|
IOMUXC_SW_MUX_CTL_PAD_GPIO_AD_B1_06, // 17/A3 AD_B1_06 GPIO1.22 I2C3_SDA |
|
|
|
|
|
IOMUXC_SW_MUX_CTL_PAD_GPIO_AD_B1_07, // 16/A2 AD_B1_07 GPIO1.23 I2C3_SCL |
|
|
|
|
|
IOMUXC_SW_PAD_CTL_PAD_GPIO_AD_B1_06, |
|
|
|
|
|
IOMUXC_SW_PAD_CTL_PAD_GPIO_AD_B1_07, |
|
|
|
|
|
IOMUXC_LPI2C3_SDA_SELECT_INPUT, |
|
|
|
|
|
IOMUXC_LPI2C3_SCL_SELECT_INPUT, |
|
|
|
|
|
1 | 0x10, |
|
|
|
|
|
1 | 0x10, |
|
|
|
|
|
2, |
|
|
|
|
|
2, |
|
|
|
|
|
IRQ_LPI2C3 |
|
|
|
|
|
}; |
|
|
|
|
|
TwoWire Wire1(&IMXRT_LPI2C3, TwoWire::i2c3_hardware); |
|
|
|
|
|
|
|
|
|
|
|
PROGMEM |
|
|
|
|
|
constexpr TwoWire::I2C_Hardware_t TwoWire::i2c4_hardware = { |
|
|
|
|
|
CCM_CCGR6, CCM_CCGR6_LPI2C4_SERIAL(CCM_CCGR_ON), |
|
|
|
|
|
IOMUXC_SW_MUX_CTL_PAD_GPIO_AD_B0_13, // 25/A11 AD_B0_13 GPIO1.13 I2C4_SDA |
|
|
|
|
|
IOMUXC_SW_MUX_CTL_PAD_GPIO_AD_B0_12, // 24/A10 AD_B1_12 GPIO1.12 I2C4_SCL |
|
|
|
|
|
IOMUXC_SW_PAD_CTL_PAD_GPIO_AD_B0_13, |
|
|
|
|
|
IOMUXC_SW_PAD_CTL_PAD_GPIO_AD_B0_12, |
|
|
|
|
|
IOMUXC_LPI2C4_SDA_SELECT_INPUT, |
|
|
|
|
|
IOMUXC_LPI2C4_SCL_SELECT_INPUT, |
|
|
|
|
|
0 | 0x10, |
|
|
|
|
|
0 | 0x10, |
|
|
|
|
|
1, |
|
|
|
|
|
1, |
|
|
|
|
|
IRQ_LPI2C4 |
|
|
|
|
|
}; |
|
|
|
|
|
TwoWire Wire2(&IMXRT_LPI2C4, TwoWire::i2c4_hardware); |
|
|
|
|
|
|
|
|
TwoWire Wire(0, TwoWire::i2c1_hardware); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void i2c_setclock(uint32_t frequency) |
|
|
|
|
|
|
|
|
void TwoWire::setClock(uint32_t frequency) |
|
|
{ |
|
|
{ |
|
|
// timing params, pg 2363 |
|
|
// timing params, pg 2363 |
|
|
//SETHOLD: 2-63 |
|
|
//SETHOLD: 2-63 |
|
|
|
|
|
|
|
|
CLKHI = CLOCK_PERIOD/2 - LATENCY - 1 = 27 |
|
|
CLKHI = CLOCK_PERIOD/2 - LATENCY - 1 = 27 |
|
|
DATAVD = CLKLO/3 - LATENCY = 7 // guesswork |
|
|
DATAVD = CLKLO/3 - LATENCY = 7 // guesswork |
|
|
SETHOLD = ??? = 22 |
|
|
SETHOLD = ??? = 22 |
|
|
|
|
|
|
|
|
#endif |
|
|
#endif |
|
|
LPI2C1_MCR = 0; |
|
|
|
|
|
LPI2C1_MCCR0 = LPI2C_MCCR0_CLKHI(55) | LPI2C_MCCR0_CLKLO(59) | |
|
|
|
|
|
|
|
|
port->MCR = 0; |
|
|
|
|
|
port->MCCR0 = LPI2C_MCCR0_CLKHI(55) | LPI2C_MCCR0_CLKLO(59) | |
|
|
LPI2C_MCCR0_DATAVD(25) | LPI2C_MCCR0_SETHOLD(40); |
|
|
LPI2C_MCCR0_DATAVD(25) | LPI2C_MCCR0_SETHOLD(40); |
|
|
LPI2C1_MCCR1 = LPI2C1_MCCR0; |
|
|
|
|
|
LPI2C1_MCFGR0 = 0; |
|
|
|
|
|
LPI2C1_MCFGR1 = /*LPI2C_MCFGR1_TIMECFG |*/ LPI2C_MCFGR1_PRESCALE(1); |
|
|
|
|
|
LPI2C1_MCFGR2 = LPI2C_MCFGR2_FILTSDA(5) | LPI2C_MCFGR2_FILTSCL(5) | LPI2C_MCFGR2_BUSIDLE(3900); |
|
|
|
|
|
LPI2C1_MCFGR3 = LPI2C_MCFGR3_PINLOW(3900); |
|
|
|
|
|
LPI2C1_MFCR = LPI2C_MFCR_RXWATER(1) | LPI2C_MFCR_TXWATER(1); |
|
|
|
|
|
LPI2C1_MCR = LPI2C_MCR_MEN; |
|
|
|
|
|
|
|
|
port->MCCR1 = port->MCCR0; |
|
|
|
|
|
port->MCFGR0 = 0; |
|
|
|
|
|
port->MCFGR1 = /*LPI2C_MCFGR1_TIMECFG |*/ LPI2C_MCFGR1_PRESCALE(1); |
|
|
|
|
|
port->MCFGR2 = LPI2C_MCFGR2_FILTSDA(5) | LPI2C_MCFGR2_FILTSCL(5) | LPI2C_MCFGR2_BUSIDLE(3900); |
|
|
|
|
|
port->MCFGR3 = LPI2C_MCFGR3_PINLOW(3900); |
|
|
|
|
|
port->MFCR = LPI2C_MFCR_RXWATER(1) | LPI2C_MFCR_TXWATER(1); |
|
|
|
|
|
port->MCR = LPI2C_MCR_MEN; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
#endif |
|
|
#endif |