Browse Source

Support Wire1 and Wire2

main
PaulStoffregen 6 years ago
parent
commit
21ab71102b
2 changed files with 109 additions and 81 deletions
  1. +89
    -64
      WireIMXRT.cpp
  2. +20
    -17
      WireIMXRT.h

+ 89
- 64
WireIMXRT.cpp View File

@@ -6,37 +6,24 @@

#include "debug/printf.h"

void i2c_setclock(uint32_t frequency);

void TwoWire::begin(void)
{
// use 24 MHz clock
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)
{
// TODO: slave mode
}

void TwoWire::end()
@@ -80,7 +67,7 @@ uint8_t TwoWire::endTransmission(uint8_t sendStop)

// wait while bus is busy
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_MBF) break; // we already have bus control
// TODO: timeout...
@@ -88,26 +75,26 @@ uint8_t TwoWire::endTransmission(uint8_t sendStop)
//printf("m=%x\n", status);

// 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;

while (1) {
// transmit stuff, if we haven't already
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);
while (fifo_used < 4) {
if (i == 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;
} else if (i < len) {
LPI2C1_MTDR = LPI2C_MTDR_CMD_TRANSMIT | txBuffer[i++];
port->MTDR = LPI2C_MTDR_CMD_TRANSMIT | txBuffer[i++];
} else {
if (sendStop) LPI2C1_MTDR = LPI2C_MTDR_CMD_STOP;
if (sendStop) port->MTDR = LPI2C_MTDR_CMD_STOP;
i++;
break;
}
@@ -115,15 +102,15 @@ uint8_t TwoWire::endTransmission(uint8_t sendStop)
}
}
// monitor status
status = LPI2C1_MSR; // pg 2899 & 2892
status = port->MSR; // pg 2899 & 2892
if (status & LPI2C_MSR_ALF) {
//printf("arbitration lost\n");
return 4; // we lost bus arbitration to another master
}
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
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 3; // NACK for data TODO: how to discern addr from data?
}
@@ -143,7 +130,7 @@ uint8_t TwoWire::endTransmission(uint8_t sendStop)
return 0;
}
} else {
uint32_t fifo_used = LPI2C1_MFSR & 0x07; // pg 2914
uint32_t fifo_used = port->MFSR & 0x07; // pg 2914
if (fifo_used == 0) {
//digitalWriteFast(15, HIGH);
//delayMicroseconds(2);
@@ -163,7 +150,7 @@ uint8_t TwoWire::requestFrom(uint8_t address, uint8_t length, uint8_t sendStop)

// wait while bus is busy
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_MBF) break; // we already have bus control
// TODO: timeout...
@@ -171,9 +158,9 @@ uint8_t TwoWire::requestFrom(uint8_t address, uint8_t length, uint8_t sendStop)
//printf("idle2, msr=%x\n", status);

// 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;
if (length < 1) length = 1;
if (length > 255) length = 255;
@@ -185,17 +172,17 @@ uint8_t TwoWire::requestFrom(uint8_t address, uint8_t length, uint8_t sendStop)
while (1) {
// transmit stuff, if we haven't already
if (cmd < 3) {
fifo = LPI2C1_MFSR & 0x07; // pg 2914
fifo = port->MFSR & 0x07; // pg 2914
//if (fifo < 4) printf("t=%ld\n", fifo);
while (fifo < 4 && cmd < 3) {
if (cmd == 0) {
LPI2C1_MTDR = LPI2C_MTDR_CMD_START | 1 | address;
port->MTDR = LPI2C_MTDR_CMD_START | 1 | address;
} else if (cmd == 1) {
// 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 {
if (sendStop) LPI2C1_MTDR = LPI2C_MTDR_CMD_STOP;
if (sendStop) port->MTDR = LPI2C_MTDR_CMD_STOP;
}
cmd++;
fifo = fifo + 1;
@@ -203,15 +190,15 @@ uint8_t TwoWire::requestFrom(uint8_t address, uint8_t length, uint8_t sendStop)
}
// receive stuff
if (rxBufferLength < sizeof(rxBuffer)) {
fifo = (LPI2C1_MFSR >> 16) & 0x07;
fifo = (port->MFSR >> 16) & 0x07;
//if (fifo > 0) printf("r=%ld\n", fifo);
while (fifo > 0 && rxBufferLength < sizeof(rxBuffer)) {
rxBuffer[rxBufferLength++] = LPI2C1_MRDR;
rxBuffer[rxBufferLength++] = port->MRDR;
fifo = fifo - 1;
}
}
// monitor status
status = LPI2C1_MSR; // pg 2899 & 2892
status = port->MSR; // pg 2899 & 2892
if (status & LPI2C_MSR_ALF) {
//printf("arbitration lost\n");
break;
@@ -239,23 +226,62 @@ uint8_t TwoWire::requestFrom(uint8_t address, uint8_t length, uint8_t sendStop)





PROGMEM
constexpr TwoWire::I2C_Hardware_t TwoWire::i2c1_hardware = {
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
};
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
//SETHOLD: 2-63
@@ -298,18 +324,17 @@ void i2c_setclock(uint32_t frequency)
CLKHI = CLOCK_PERIOD/2 - LATENCY - 1 = 27
DATAVD = CLKLO/3 - LATENCY = 7 // guesswork
SETHOLD = ??? = 22

#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);
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

+ 20
- 17
WireIMXRT.h View File

@@ -42,19 +42,25 @@ public:
typedef struct {
volatile uint32_t &clock_gate_register;
uint32_t clock_gate_mask;
uint8_t sda_pin[5];
uint8_t sda_mux[5];
uint8_t scl_pin[5];
uint8_t scl_mux[5];
volatile uint32_t &sda_mux_register;
volatile uint32_t &scl_mux_register;
volatile uint32_t &sda_pad_register;
volatile uint32_t &scl_pad_register;
volatile uint32_t &sda_input_register;
volatile uint32_t &scl_input_register;
uint8_t sda_mux_value;
uint8_t scl_mux_value;
uint8_t sda_input_value;
uint8_t scl_input_value;
IRQ_NUMBER_t irq;
} I2C_Hardware_t;
static const I2C_Hardware_t i2c0_hardware;
static const I2C_Hardware_t i2c1_hardware;
static const I2C_Hardware_t i2c2_hardware;
static const I2C_Hardware_t i2c3_hardware;
static const I2C_Hardware_t i2c4_hardware;
public:
constexpr TwoWire(uintptr_t port_addr, const I2C_Hardware_t &myhardware)
: port_addr(port_addr), hardware(myhardware) {
constexpr TwoWire(IMXRT_LPI2C_t *myport, const I2C_Hardware_t &myhardware)
: port(myport), hardware(myhardware) {
}
void begin();
void begin(uint8_t address);
@@ -63,8 +69,10 @@ public:
}
void end();
void setClock(uint32_t frequency);
void setSDA(uint8_t pin);
void setSCL(uint8_t pin);
void setSDA(uint8_t pin) {
}
void setSCL(uint8_t pin) {
}
void beginTransmission(uint8_t address) {
txBuffer[0] = (address << 1);
transmitting = 1;
@@ -141,14 +149,9 @@ public:
}
using Print::write;
private:
//IMXRT_LPI2C_t & port() { return (*(IMXRT_LPI2C_t *) port_addr); }
uint8_t i2c_status(void) {
//return port().S;
return 0;
}
void isr(void);
bool wait_idle(void);
uintptr_t port_addr;
//void isr(void);
//bool wait_idle(void);
IMXRT_LPI2C_t * const port;
const I2C_Hardware_t &hardware;
uint8_t rxBuffer[BUFFER_LENGTH] = {};
uint8_t rxBufferIndex = 0;

Loading…
Cancel
Save