I2C Not Sending Data -- Configuration Issue?

Tip / Sign in to post questions, reply, level up, and achieve exciting badges. Know more

cross mob
User12789
Level 3
Level 3
10 sign-ins First solution authored 5 sign-ins
I'm writing an I2C driver for the XMC4700 and am having problems getting it to actually do anything on the I2C bus. I'm not using DAVE, or any libraries--I'm writing to the peripheral registers directly.

The hardware configuration is the XMC4700 Relax board. I'm configuring my I2C driver to use USIC channel U1C1, with the pins configured as follows: SDA (P3.15 DX0A/DOUT0), SCL (P0.13 DX1B/SCLKOUT). I have the pins themselves configured as outputs, ALT Function 2, open drain.

I have taken USIC1 and PORTS out of reset.

Here's how I have U1C1 configured:

KSCFG = USIC_CH_KSCFG_MODEN_Msk | USIC_CH_KSCFG_BPMODEN_Msk

CCR = 4

PCR = USIC_CH_PCR_IICMode_SCRIEN_Msk | USIC_CH_PCR_IICMode_RSCRIEN_Msk | USIC_CH_PCR_IICMode_PCRIEN_Msk |
USIC_CH_PCR_IICMode_NACKIEN_Msk | USIC_CH_PCR_IICMode_ARLIEN_Msk | USIC_CH_PCR_IICMode_ERRIEN_Msk |
USIC_CH_PCR_IICMode_ACKIEN_Msk | (0xa << USIC_CH_PCR_IICMode_HDEL_Pos)

DX0CR = USIC_CH_DX0CR_DSEN_Msk | 0b000

DX1CR = USIC_CH_DX1CR_DSEN_Msk | 0b001

SCTR = USIC_CH_SCTR_SDIR_Msk | (1 << USIC_CH_SCTR_PDL_Pos) | (0b11 << USIC_CH_SCTR_TRM_Pos) | (0x3f << USIC_CH_SCTR_FLE_Pos) | (7 << USIC_CH_SCTR_WLE_Pos)

TCSR = (0b01 << USIC_CH_TCSR_TDEN_Pos) | USIC_CH_TCSR_TDSSM_Msk

BRG = (9 << USIC_CH_BRG_DCTQ_Pos) | ((pdiv - 1) << USIC_CH_BRG_PDIV_Pos);
FDR = (step << USIC_CH_FDR_STEP_Pos) | (2 << USIC_CH_FDR_DM_Pos);


After setting everything up as above, I'm attempting to do an I2C write operation to an MCP9808 temperature sensor connected to the I2C bus attached to P0.13 and P3.15. Both SCL and SDA have 10K pull-ups to Vcc. There are no other I2C devices on the bus. To start the transfer, I'm writing the following to U1C1's TBUF[0] register:

TBUF[0] = (0b100 << 😎 | (slaveaddr << 1)

That should cause the USIC to initiate an I2C start condition on the bus and send the slave address on the bus. I've got a logic analyzer connected to both SCL and SDA and see no transitions on either line. When I write to TBUF[0], the only U1C1 register changes I see are these:

TCSR.TDV changes from 0 to 1
TCSR.TE changes from 0 to 1

In particular, I do not see PSR.SCR go to 1, which would indicate the START condition has been initiated. I do see that DX0CR.DXS = 1 and DX1CR.DXS = 1, which, if I'm reading the reference manual correctly, should be the current values of the bus lines. They should be high in idle state, which they are, but they should transition during a start sequence, which they don't.

Since I'm not seeing any I2C bus activity, I checked that the two ports (P0.13/P3.15) work as normal GPIO ports, and they do, both as push-pull outputs and open-drain outputs.

What am I missing here? I'm sure that I have a minor configuration error preventing things from working, but I've been over the code many times and just don't see it.
0 Likes
21 Replies
User10696
Level 4
Level 4
First solution authored
Are both of the signals high before you start the transmission? The pull-ups should pull both clock and data high during the bus idle. If one of the signals is low, the transmission does not start.
0 Likes
User10696
Level 4
Level 4
First solution authored
Just another thought, have you enabled the periphal clock to the USICs in the SCU module?
I find it much easier to program the peripherials using the XMClib functions.
0 Likes
User12789
Level 3
Level 3
10 sign-ins First solution authored 5 sign-ins
amanning wrote:
Are both of the signals high before you start the transmission? The pull-ups should pull both clock and data high during the bus idle. If one of the signals is low, the transmission does not start.


Yes, both of the signals are high before I start the transmission. They go high as soon as I set the two port pins in open drain mode and they stay high when I try to start the transfer. I've verified this on an oscilloscope.

Here's a scope shot of the two I2C lines. Yellow is SCL and green is SDA. Both remain high before, during, and after my writing to TBUF[0].

4557.attach
0 Likes
User12789
Level 3
Level 3
10 sign-ins First solution authored 5 sign-ins
amanning wrote:
Just another thought, have you enabled the periphal clock to the USICs in the SCU module?
I find it much easier to program the peripherials using the XMClib functions.


Yes, the USIC is getting peripheral clock (the CCU->CGATSTAT1 register indicates that USIC1's clock is not gated).
0 Likes
User12789
Level 3
Level 3
10 sign-ins First solution authored 5 sign-ins
Anyone from Infineon reading this? Can you help with this issue?
0 Likes
jferreira
Employee
Employee
10 sign-ins 5 sign-ins First like received
Hi,

Please use XMCLib.

Regards,
Jesus
0 Likes
User12789
Level 3
Level 3
10 sign-ins First solution authored 5 sign-ins
jferreira wrote:
Please use XMCLib.


That's not an option in this case. Any real, substantive help here would be greatly appreciated as there are several reasons I can't use a vendor library for this project.
0 Likes
User10696
Level 4
Level 4
First solution authored
Maybe if you publish the complete register dump of the USIC, then someone may be able to see what is incorrect.
0 Likes
User12789
Level 3
Level 3
10 sign-ins First solution authored 5 sign-ins
I'm still banging my head against the wall trying to get some activity on the I2C bus, but no success so far.

I've even gone as far as comparing my code against the I2C driver in XMClib and my code is setting up the USIC registers in an identical fashion to how the XMClib code does it.

Can this be a hardware issue? I'm thinking that I see no I2C activity because the I2C peripheral somehow thinks the I2C bus is busy... I'm using an XMC4700 Relax board and SDA is P3.15 and SCK is P0.13 on USIC U1C1.
The ports are set up as digital outputs, Altfunc 2, opendrain, and I've driven both ports high (the I2C idle state). I can probe the bus with a scope and see both lines sitting at 3V3.

To rule out any issues with I2C devices, I've made things as simple as possible by removing all I2C devices from the bus--the only thing on the bus are two weak (10K) pull-up resistors to 3V3. I've got a logic analyzer on both SDA and SCK
and see no transitions when I write to TBUF[0] with the appropriate slave address and the appropriate TDC code (0b100) to send a Start condition.

The USIC does react when I write to TBUF... The TDV and TE bits in the TCSR register go from 0 to 1 as soon as the write to TBUF[0] occurs. But nothing is seen on the I2C bus...
0 Likes
jferreira
Employee
Employee
10 sign-ins 5 sign-ins First like received
Hi,

Are the input multiplexer setup correctly, in USIC DX0CR and DX1CR registers?

Regards,
Jesus
0 Likes
User12789
Level 3
Level 3
10 sign-ins First solution authored 5 sign-ins
jferreira wrote:
Hi,

Are the input multiplexer setup correctly, in USIC DX0CR and DX1CR registers?


Hi Jesus. Thanks for the reply. Here's my code that sets up the DX0CR and DX1CR registers:

port->DX0CR = (port->DX0CR & ~USIC_CH_DX0CR_DSEL_Msk) | 0b000; // SDA on P3.15
port->DX1CR = (port->DX1CR & ~USIC_CH_DX1CR_DSEL_Msk) | 0b001; // SCL on P0.13
0 Likes
jferreira
Employee
Employee
10 sign-ins 5 sign-ins First like received
Hi,

Those seems to be correct.
Could you verify that you are following the procedure described in section 18.5.2 Operating the IIC of the reference manual?

Regards,
Jesus
0 Likes
User12789
Level 3
Level 3
10 sign-ins First solution authored 5 sign-ins
Yes, I'm closely following the procedure described in section 18.5.2 of the reference manual.
0 Likes
jferreira
Employee
Employee
10 sign-ins 5 sign-ins First like received
Hi,

Do you mind sharing your code?

Regards,
Jesus
0 Likes
User12789
Level 3
Level 3
10 sign-ins First solution authored 5 sign-ins
Hi Jesus,

Here's the code for my I2C initialization and I2c write functions:


int32_t i2cInit(uint32_t module, uint32_t channel, uint32_t speed, uint32_t mode)

{

uint32_t port;

if((module > 2) || (channel > 1))
return(-1);

port = (module * 2) + channel;

if(i2cInited[port])
return(0);

i2cInited[port] = 1;

if(!i2cMutex[port])
if((i2cMutex[port] = OsCreateMutex()) == (pSCB *)0)
OsPanic("i2cInit: unable to create mutex\n");


if(!(i2cRegs[port]->CCFG & USIC_CH_CCFG_IIC_Msk))
return(-1); // I2C mode not available on this USIC module/channel


SCU_CLK->CGATCLR1 = SCU_CLK_CGATCLR1_USIC1_Msk; // disable clock gating to USIC1
SCU_RESET->PRSET1 = SCU_RESET_PRSET1_USIC1RS_Msk; // assert USIC1 reset
SCU_RESET->PRCLR1 = SCU_RESET_PRCLR1_USIC1RS_Msk; // de-assert USIC1 reset

OsEnableVector(USIC1_0_IRQn); // set interrupt vector for I2C Rx interrupt (SR0)
OsSetIntPriority(USIC1_0_IRQn, I2C_PRIO); // set interrupt priority
OsEnableVector(USIC1_1_IRQn); // set interrupt vector for I2C Tx interrupt (SR1)
OsSetIntPriority(USIC1_1_IRQn, I2C_PRIO); // set interrupt priority

i2cRegs[port]->KSCFG = USIC_CH_KSCFG_MODEN_Msk | USIC_CH_KSCFG_BPMODEN_Msk; // enable the module in run mode 0
while(!(i2cRegs[port]->KSCFG & USIC_CH_KSCFG_MODEN_Msk))
; // wait for module to enable

i2cRegs[port]->CCR = 0; // disable the channel and set all interrupt sources to off, disable parity generation

i2cRegs[port]->SCTR = USIC_CH_SCTR_SDIR_Msk | // shift direction is MSB first
(1 << USIC_CH_SCTR_PDL_Pos) | // passive data level is 1
(0b11 << USIC_CH_SCTR_TRM_Pos) | // transmission mode
(0x3f << USIC_CH_SCTR_FLE_Pos) | // frame length
(7 << USIC_CH_SCTR_WLE_Pos); // word length 8 bits
i2cRegs[port]->PCR = USIC_CH_PCR_IICMode_SCRIEN_Msk | // enable start condition interrupt
USIC_CH_PCR_IICMode_RSCRIEN_Msk | // enable repeated start condition interrupt
USIC_CH_PCR_IICMode_PCRIEN_Msk | // enable stop condition interrupt
USIC_CH_PCR_IICMode_NACKIEN_Msk | // enable NACK interrupt
USIC_CH_PCR_IICMode_ARLIEN_Msk | // enable arbitration lost interrupt
USIC_CH_PCR_IICMode_ERRIEN_Msk | // enable error interrupt
USIC_CH_PCR_IICMode_ACKIEN_Msk; // enable ACK interrupt
i2cRegs[port]->PCR |= speed == 100 ? 0 : USIC_CH_PCR_IICMode_STIM_Msk; // set symbol timing for 100 kHz or 400 kHz
i2cRegs[port]->PCR |= 0xa << USIC_CH_PCR_IICMode_HDEL_Pos;
i2cSetBaudRate(port, speed, 10); // calculate bit rate and set rate registers (BRG & FDR)
i2cRegs[port]->TCSR = (0b01 << USIC_CH_TCSR_TDEN_Pos) | USIC_CH_TCSR_TDSSM_Msk; // WLEMD=0, SELMD=0, FLEMD=0, WAMD=0, HPCMD=0, SOF=1, EOF=xx, TDSSM=1, TDEN=01
i2cRegs[port]->PSCR = 0x1ffff; // clear all protocol status bits

i2cRegs[port]->DX0CR = USIC_CH_DX0CR_DSEN_Msk | 0b000; // set input on DX0A, INSW=0, DFEN=0, DESN=0, DPOL=0, SFSEL=0, CM=0, DXS=0
i2cRegs[port]->DX1CR = USIC_CH_DX1CR_DSEN_Msk | 0b001; // set input on DX1B, INSW=0, DFEN=0, DESN=0, DPOL=0, SFSEL=0, CM=0, DXS=0

GPIOInitPin(GPIO_PORT3, GPIO_PIN15, GPIO_DIGITAL, GPIO_AF2, GPIO_OUTPUT, GPIO_A1P, GPIO_STRONG, GPIO_SOFTEDGE, GPIO_NOPULL, GPIO_OPENDRAIN); // SDA
GPIOInitPin(GPIO_PORT0, GPIO_PIN13, GPIO_DIGITAL, GPIO_AF2, GPIO_OUTPUT, GPIO_A1P, GPIO_STRONG, GPIO_SOFTEDGE, GPIO_NOPULL, GPIO_OPENDRAIN); // SCK
GPIOSetPin(GPIO_PORT3, GPIO_PIN15);
GPIOSetPin(GPIO_PORT0, GPIO_PIN13);

i2cRegs[port]->INPR = (0 << USIC_CH_INPR_AINP_Pos) | // alternate receive interrupt -> SR0
(1 << USIC_CH_INPR_TSINP_Pos) | // transmit shit interrupt -> SR1
(2 << USIC_CH_INPR_PINP_Pos); //protocol interrupt ->SR2
i2cRegs[port]->CCR = 4 | USIC_CH_CCR_AIEN_Msk | USIC_CH_CCR_TSIEN_Msk; // enable I2C mode and receive/alternative/transmit interrupts

return(port);
}



int32_t i2cWrite(uint32_t port, uint32_t slaveaddr, uint8_t *buf, uint32_t cnt, uint32_t flgs)

{

uint32_t s;

if(port > NUM_I2C)
return(-1);

i2cbuf[port].tid = OsGetCurTid(); // set tid of owning task
i2cbuf[port].op = I2COP_WRITE;
i2cbuf[port].state = I2CSTATE_TRANSMIT; // start in TRANSMIT state
i2cbuf[port].cnt = cnt;
i2cbuf[port].rescnt = 0;
i2cbuf[port].buf = buf;
i2cbuf[port].slaveaddr = slaveaddr;

i2cRegs[port]->TBUF[0] = SEND_START | (slaveaddr << 1) | 0; // send start and slave address to kick off I2C write

if(OsSleep((uint32_t)&i2cbuf[port], I2CWRITETIMEOUT) == SYS_TIMEOUT) // sleep waiting for operation complete (all further processing happens in the interrupt handler)
return(-1);

i2cbuf[port].op = I2COP_NOP; // clear buf
return(i2cbuf[port].rescnt); // return with count of bytes written

}

0 Likes
jferreira
Employee
Employee
10 sign-ins 5 sign-ins First like received
Hi,

Could you try to do the GPIO initialization after the start of the USIC in I2C mode, i.e.
  ...
i2cRegs[port]->DX0CR = USIC_CH_DX0CR_DSEN_Msk | 0b000; // set input on DX0A, INSW=0, DFEN=0, DESN=0, DPOL=0, SFSEL=0, CM=0, DXS=0
i2cRegs[port]->DX1CR = USIC_CH_DX1CR_DSEN_Msk | 0b001; // set input on DX1B, INSW=0, DFEN=0, DESN=0, DPOL=0, SFSEL=0, CM=0, DXS=0

i2cRegs[port]->INPR = (0 << USIC_CH_INPR_AINP_Pos) | // alternate receive interrupt -> SR0
(1 << USIC_CH_INPR_TSINP_Pos) | // transmit shit interrupt -> SR1
(2 << USIC_CH_INPR_PINP_Pos); //protocol interrupt ->SR2

i2cRegs[port]->CCR = 4 | USIC_CH_CCR_AIEN_Msk | USIC_CH_CCR_TSIEN_Msk; // enable I2C mode and receive/alternative/transmit interrupts

GPIOInitPin(GPIO_PORT3, GPIO_PIN15, GPIO_DIGITAL, GPIO_AF2, GPIO_OUTPUT, GPIO_A1P, GPIO_STRONG, GPIO_SOFTEDGE, GPIO_NOPULL, GPIO_OPENDRAIN); // SDA
GPIOInitPin(GPIO_PORT0, GPIO_PIN13, GPIO_DIGITAL, GPIO_AF2, GPIO_OUTPUT, GPIO_A1P, GPIO_STRONG, GPIO_SOFTEDGE, GPIO_NOPULL, GPIO_OPENDRAIN); // SCK

return(port);
}

Regards,
Jesus
0 Likes
User12789
Level 3
Level 3
10 sign-ins First solution authored 5 sign-ins
Hi Jesus,

I tried your suggestion and it didn't work. 😞
0 Likes
User12789
Level 3
Level 3
10 sign-ins First solution authored 5 sign-ins
Bump. Anyone have any ideas?
0 Likes
jferreira
Employee
Employee
10 sign-ins 5 sign-ins First like received
Hi,

Can you check the value of TCSR.TDV bit?
If stays at 1 no more communication will happen.

Regards,
Jesus
0 Likes
User10696
Level 4
Level 4
First solution authored
I am having exactly the same problem with a completely different setup. I am using the XMC4500 together with the CMSIS I2C Driver.
The driver has a "Bus Clear" function, which is meant to produce 9 clocks to free the bus in case a slave is blocking the bus. This does not work! If the bus is blocked, no clock pulses are sent, as the USIC thinks the bus is busy.
To solve this problem I toggle the clock pin manually and then set the pin configuration back to open drain.

I have found the following:
If I manually clear the bus and then call the init function of the driver everything work correctly, but if I call the init of the driver and then clear the bus, it does not work. All the USIC and GPIO registers look the same, but something must be different in the USIC.

Changing the GPIO settings after the USIC is setup seems to cause problems that cannot be seen by looking at the registers.

@SadaAnt: Maybe by changing the order of the initialization you can solve the problem.
0 Likes
User20504
Level 1
Level 1
Hi

I have some problems to get I2C running on my device.
I am using XMC4300 and digilent TMP3 sensor via I2C.
After reading all articles and examples, i am confused if i shall use I2C or XMC i2c lib?

Code in Main:
XMC_I2C_CH_Init(i2c, &i2c_cfg);
XMC_I2C_CH_SetInputSource(i2c, XMC_I2C_CH_INPUT_SDA , USIC0_C0_DX0_P1_5);
XMC_I2C_CH_SetInputSource(i2c, XMC_I2C_CH_INPUT_SCL , USIC0_C0_DX1_P0_8);
XMC_I2C_CH_Start(XMC_I2C0_CH0);


XMC_I2C_CH_MasterStart(XMC_I2C0_CH0, TMP3_ADDRESS, XMC_I2C_CH_CMD_WRITE);
XMC_I2C_CH_MasterTransmit(i2c, 0x00);


Code in app:
XMC_I2C_CH_MasterRepeatedStart(XMC_I2C0_CH0, TMP3_ADDRESS, XMC_I2C_CH_CMD_READ);
received_data = XMC_I2C_CH_GetReceivedData(XMC_I2C0_CH0);


This is not working at all.. can somebody help me?
Thank you!

Regards
Roman

---------------------------

Edit:
Meanwhile its working, but honestly it was try and error 😞
in main i`ve added the Init:
XMC_GPIO_Init(SCL_PIN, &i2c_scl);
XMC_GPIO_Init(SDA_PIN, &i2c_sda);

And in the app i added other lines:
XMC_I2C_CH_MasterStart(XMC_I2C0_CH0, TMP3_ADDRESS, XMC_I2C_CH_CMD_WRITE);
XMC_I2C_CH_MasterRepeatedStart(XMC_I2C0_CH0, TMP3_ADDRESS, XMC_I2C_CH_CMD_READ);
XMC_I2C_CH_SlaveTransmit(XMC_I2C0_CH0, 0x00);
received_data = XMC_I2C_CH_GetReceivedData(XMC_I2C0_CH0);
XMC_I2C_CH_MasterStop(XMC_I2C1_CH0);

Regards
0 Likes