i2c help

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

cross mob
Not applicable
Hello.

I'm still pretty new to the XMC4500 and I'm at a loss with this i2c issue I'm having.

I'm trying (not me, the xmc4500) to talk to an INA3221 current sensor.
It's slave address is configured as 0x40.

I'm building this in Keil uVision5.

Here is my code.. it's basically taken from the i2c example as part of the XMC4500 package for Keil.

// address is 0x40 << 1
#define IO_ADDRESS 0x80

#define MANF_ID_REG 0xFE

#define SDA_PIN P2_5
#define SCL_PIN P2_4
XMC_GPIO_CONFIG_t i2c_sda =
{
.mode = XMC_GPIO_MODE_OUTPUT_OPEN_DRAIN_ALT2,
.output_strength = XMC_GPIO_OUTPUT_STRENGTH_MEDIUM
};

XMC_GPIO_CONFIG_t i2c_scl =
{
.mode = XMC_GPIO_MODE_OUTPUT_OPEN_DRAIN_ALT2,
.output_strength = XMC_GPIO_OUTPUT_STRENGTH_MEDIUM
};


XMC_I2C_CH_CONFIG_t i2c_cfg =
{
.baudrate = 100000U,
};
int main(void)
{
volatile uint8_t received_data;
volatile uint8_t rcv_data2;

XMC_I2C_CH_Init(XMC_I2C0_CH1, &i2c_cfg);
XMC_I2C_CH_SetInputSource(XMC_I2C0_CH1, XMC_I2C_CH_INPUT_SDA, USIC0_C1_DX0_P2_5);
XMC_I2C_CH_SetInputSource(XMC_I2C0_CH1, XMC_I2C_CH_INPUT_SCL, USIC0_C1_DX1_P2_4);
XMC_I2C_CH_Start(XMC_I2C0_CH1);

XMC_GPIO_Init(SCL_PIN, &i2c_scl);
XMC_GPIO_Init(SDA_PIN, &i2c_sda);

XMC_I2C_CH_MasterStart(XMC_I2C0_CH1, IO_ADDRESS , XMC_I2C_CH_CMD_WRITE);
while((XMC_I2C_CH_GetStatusFlag(XMC_I2C0_CH1) & XMC_I2C_CH_STATUS_FLAG_ACK_RECEIVED) == 0U)
{
/* wait for ACK */
}
XMC_I2C_CH_ClearStatusFlag(XMC_I2C0_CH1, XMC_I2C_CH_STATUS_FLAG_ACK_RECEIVED);

XMC_I2C_CH_MasterTransmit(XMC_I2C0_CH1, MANF_ID_REG);
while((XMC_I2C_CH_GetStatusFlag(XMC_I2C0_CH1) & XMC_I2C_CH_STATUS_FLAG_ACK_RECEIVED) == 0U)
{
/* wait for ACK */
}
XMC_I2C_CH_ClearStatusFlag(XMC_I2C0_CH1, XMC_I2C_CH_STATUS_FLAG_ACK_RECEIVED);

XMC_I2C_CH_MasterTransmit(XMC_I2C0_CH1, 0xffU);
while((XMC_I2C_CH_GetStatusFlag(XMC_I2C0_CH1) & XMC_I2C_CH_STATUS_FLAG_ACK_RECEIVED) == 0U)
{
/* wait for ACK */
}
XMC_I2C_CH_ClearStatusFlag(XMC_I2C0_CH1, XMC_I2C_CH_STATUS_FLAG_ACK_RECEIVED);


// Restart read
XMC_I2C_CH_MasterRepeatedStart(XMC_I2C0_CH1, IO_ADDRESS , XMC_I2C_CH_CMD_READ);
while((XMC_I2C_CH_GetStatusFlag(XMC_I2C0_CH1) & XMC_I2C_CH_STATUS_FLAG_ACK_RECEIVED) == 0U)
{
/* wait for ACK */
}
XMC_I2C_CH_ClearStatusFlag(XMC_I2C0_CH1, XMC_I2C_CH_STATUS_FLAG_ACK_RECEIVED);


XMC_I2C_CH_MasterReceiveAck(XMC_I2C0_CH1);
while((XMC_I2C_CH_GetStatusFlag(XMC_I2C0_CH1) & (XMC_I2C_CH_STATUS_FLAG_RECEIVE_INDICATION |
XMC_I2C_CH_STATUS_FLAG_ALTERNATIVE_RECEIVE_INDICATION)) == 0U)
{
/* wait for ACK */
}
XMC_I2C_CH_ClearStatusFlag(XMC_I2C0_CH1, XMC_I2C_CH_STATUS_FLAG_RECEIVE_INDICATION |
XMC_I2C_CH_STATUS_FLAG_ALTERNATIVE_RECEIVE_INDICATION);

received_data = XMC_I2C_CH_GetReceivedData(XMC_I2C0_CH1);

XMC_I2C_CH_MasterStop(XMC_I2C0_CH1);

XMC_I2C_CH_MasterReceiveNack(XMC_I2C0_CH1);
while((XMC_I2C_CH_GetStatusFlag(XMC_I2C0_CH1) & (XMC_I2C_CH_STATUS_FLAG_RECEIVE_INDICATION |
XMC_I2C_CH_STATUS_FLAG_ALTERNATIVE_RECEIVE_INDICATION)) == 0U)
{
/* wait for ACK */
}
XMC_I2C_CH_ClearStatusFlag(XMC_I2C0_CH1, XMC_I2C_CH_STATUS_FLAG_RECEIVE_INDICATION |
XMC_I2C_CH_STATUS_FLAG_ALTERNATIVE_RECEIVE_INDICATION);

rcv_data2 = XMC_I2C_CH_GetReceivedData(XMC_I2C0_CH1);

XMC_I2C_CH_MasterStop(XMC_I2C0_CH1);

while(1);
}



I'm expecting preset values in the requested register and I'm getting not those values.

Can anyone spot anything obvious that I'm doing wrong?

Thanks.
-stv
0 Likes
6 Replies
DRubeša
Employee
Employee
First solution authored First like received
Hi -stv,

I have some remarks and some questions for you to check 🙂

1. As I can see from the datasheet of INA3221 device, the slave address is 1000 00(A0)(R/W) (I hope it´s understandable). This A0 bit depends to which signal did you connect A0 pin. Can you verify that in your case this pin is connected to ground (this should set A0 bit to 0)?
2. You could also include configuration of the output level for the both pins. It maybe be not necessary but you´re not doing anything wrong (as you can see the I2C protocol starts with both pins high). So just to the configuration structure add:
.output_level   = XMC_GPIO_OUTPUT_LEVEL_HIGH

3. You are requesting the read-out of the "Manufacturer ID" register as I can understand from your code. However, this register field is read-only so following code section is redundant:
XMC_I2C_CH_MasterTransmit(XMC_I2C0_CH1, 0xffU);
while((XMC_I2C_CH_GetStatusFlag(XMC_I2C0_CH1) & XMC_I2C_CH_STATUS_FLAG_ACK_RECEIVED) == 0U)
{
/* wait for ACK */
}
XMC_I2C_CH_ClearStatusFlag(XMC_I2C0_CH1, XMC_I2C_CH_STATUS_FLAG_ACK_RECEIVED);


Also you can see that in the documentation where is stated:
To change the register pointer for a read operation, write a new value to the register pointer. 
This write is accomplished by issuing a slave address byte with the R/W bit low, followed by the register pointer byte.
No additional data are required.

4. This first "XMC_I2C_CH_MasterStop()" function call (right before "XMC_I2C_CH_MasterReceiveNack" function call) should not be there. You only transmit STOP bit at the end of transmission, as you done properly in your code at the end before "while" loop. So you should remove this function call.

Try to modify the code based on my suggestions and let me know do you still have issue. Also, please let me know does your code successfully reaches "while" loop (meaning all the ACK bits are received and accepted). It would be nice if the issue is still present to screenshot the PSR_I2Cmode register just before and after you should receive data.

Best regards,
Deni
0 Likes
lock attach
Attachments are accessible only for community members.
Not applicable
1. As I can see from the datasheet of INA3221 device, the slave address is 1000 00(A0)(R/W) (I hope it´s understandable). This A0 bit depends to which signal did you connect A0 pin. Can you verify that in your case this pin is connected to ground (this should set A0 bit to 0)?


Yes I do know that. The address I pass to the function is 0x80. I know that i2c only uses 7 bits for the address and that last bit is for R/W bit.
And I know the slave responds, because I get the ACK's.

2. You could also include configuration of the output level for the both pins. It maybe be not necessary but you´re not doing anything wrong (as you can see the I2C protocol starts with both pins high). So just to the configuration structure add:
.output_level   = XMC_GPIO_OUTPUT_LEVEL_HIGH


done.


3. You are requesting the read-out of the "Manufacturer ID" register as I can understand from your code. However, this register field is read-only so following code section is redundant:
XMC_I2C_CH_MasterTransmit(XMC_I2C0_CH1, 0xffU);
while((XMC_I2C_CH_GetStatusFlag(XMC_I2C0_CH1) & XMC_I2C_CH_STATUS_FLAG_ACK_RECEIVED) == 0U)
{
/* wait for ACK */
}
XMC_I2C_CH_ClearStatusFlag(XMC_I2C0_CH1, XMC_I2C_CH_STATUS_FLAG_ACK_RECEIVED);



Whoops.. it's actually the wrong address too.. .it's 0xFE that I want. So I just removed this.

Also you can see that in the documentation where is stated:
To change the register pointer for a read operation, write a new value to the register pointer. 
This write is accomplished by issuing a slave address byte with the R/W bit low, followed by the register pointer byte.
No additional data are required.


Yup. Understood.


4. This first "XMC_I2C_CH_MasterStop()" function call (right before "XMC_I2C_CH_MasterReceiveNack" function call) should not be there. You only transmit STOP bit at the end of transmission, as you done properly in your code at the end before "while" loop. So you should remove this function call.


Yeah that was stupid.
I just took out the while loop and now I just ask for two bytes which should give me 0x5449 according to the datasheet.

Try to modify the code based on my suggestions and let me know do you still have issue.
Also, please let me know does your code successfully reaches "while" loop (meaning all the ACK bits are received and accepted). It would be nice if the issue is still present to screenshot the PSR_I2Cmode register just before and after you should receive data.


I have attached the latest code with your modifications. I've also attached a screenshot from my scope. You can see that the slave is answering me and I think I'm doing everything right.
That's why I'm perplexed.


Thanks for your help, I really appreciate it.
0 Likes
DRubeša
Employee
Employee
First solution authored First like received
So,

not the news I was hoping to hear 😞
Nevertheless, let´s try some other things. The main problem is that I don´t have the mentioned slave device, so I cannot replicate your problem. I took a look on the net for an examples that use the mentioned device, but I just found some Arduino and LABView examples....not very useful. I´ve made some adjustments to the picture you sent me. This way it´s much more easier to follow what happens with the communication between two devices.

2403.attach

here you can notice several things...first I added decoding of the every bit that you´ve captured. Also, I´ve added number on top the slices which are related to the function calls. I will post code sections with appropriate number so it´s easier to follow. I can notice from this snapshot that we receive some data (green value suggest slave controlling SDA line and red values suggest master controlling SDA line). It looks, though, that this data does not correspond to the Manufacturer ID that we addressed (0xFE). I must admit that I don´t know why this is the case.

XMC_I2C_CH_MasterStart(XMC_I2C0_CH1, IO_ADDRESS, XMC_I2C_CH_CMD_WRITE);         #1
XMC_I2C_CH_MasterTransmit(XMC_I2C0_CH1, MANF_ID_REG); #2
XMC_I2C_CH_MasterRepeatedStart(XMC_I2C0_CH1, IO_ADDRESS, XMC_I2C_CH_CMD_READ); #3
XMC_I2C_CH_MasterReceiveAck(XMC_I2C0_CH1); #4
XMC_I2C_CH_MasterReceiveNack(XMC_I2C0_CH1); #5
XMC_I2C_CH_MasterStop(XMC_I2C0_CH1); #6


So, my further suggestions...can you please use step by step debugging and see what is the content of USIC0_CH1.RBUFD register EXACTLY once the "XMC_I2C_CH_MasterReceiveAck(XMC_I2C0_CH1)" is executed. We care only about lower 8 bits.
It should match with the data seen on the picture above (meaning, the register value should be 0xC8).

Best regards,
Deni
0 Likes
Not applicable
Hi Deni --

Thanks again for the reply. On Friday I got my i2c framework working with another i2c device so I know for sure the i2c on the XMC 4500 is working.
There must be some odd thing with the INA3221.

I'll update this once I find out what the issue is. Thanks again for your help.

-stv
0 Likes
DRubeša
Employee
Employee
First solution authored First like received
Hah,

you were faster then me...sorry, I accidentally pressed "Submit" button even though I´ve finished my post. So, take a look at my comments in previous post and yes, take a look at INA3221...it behaves strange 😉

Best regards,
Deni
0 Likes
Not applicable
This ended up being a Hardware issue... I'm off the hook! 🙂 Thanks again for your help.
0 Likes