cancel
Showing results for 
Search instead for 
Did you mean: 

I2C not working properly

aloisp
Associate II
Posted on September 18, 2009 at 18:07

I2C not working properly

14 REPLIES 14
aloisp
Associate II
Posted on May 17, 2011 at 09:36

Hello,

is there anybody who managed to have I2C working properly and could help me? My problem is that only start and stop bit work, but no address or data is sent over the bus.

Here is my code:

/* I2C Configuration*/

SCU_APBPeriphClockConfig(__GPIO2, ENABLE);

SCU_APBPeriphReset(__GPIO2,DISABLE);

SCU_APBPeriphClockConfig(__I2C0,ENABLE);

SCU_APBPeriphReset(__I2C0,DISABLE);

GPIO_InitTypeDef GPIO_InitStructure;

GPIO_DeInit(GPIO2);

GPIO_InitStructure.GPIO_Direction = GPIO_PinInput;

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1;

GPIO_InitStructure.GPIO_Type = GPIO_Type_OpenCollector ;

GPIO_InitStructure.GPIO_IPConnected = GPIO_IPConnected_Enable;

GPIO_InitStructure.GPIO_Alternate = GPIO_OutputAlt2;

GPIO_Init (GPIO2, &GPIO_InitStructure);

I2C_InitTypeDef I2C_Struct;

I2C_DeInit(I2C0);

I2C_Struct.I2C_GeneralCall = I2C_GeneralCall_Disable;

I2C_Struct.I2C_Ack = I2C_Ack_Enable;

I2C_Struct.I2C_CLKSpeed =100000;

I2C_Struct.I2C_OwnAddress = 0xA0;

I2C_Init(I2C0, &I2C_Struct);

I2C_ITConfig (I2C0, DISABLE);

/* I2C Communication */

I2C_Cmd (I2C0, ENABLE);

I2C0->CR |= 0x08; // Start bit

while(!(I2C0->SR1 & 0x81) );

I2C0->DR = 0x42; // Adress of the I2C peripheral

while (!(I2C0->SR2 & 0x20));

I2C0->CR |= 0x20;

I2C0->DR = 0x41; // Data to be sent to the I2C peripheral

while ( !(I2C0->SR1 & 0x88));

I2C0->CR |= 0x02; // Stop bit

I2C_Cmd(I2C0, DISABLE);

The program hangs when checking for end of address transmission:

while (!(I2C0->SR2 & 0x20));

If I comment all the while statements out, the program will run to the end. Looking at the signals with an oscilloscope, I can see the start and stop bit, but no address and data...

Any idea what is wrong in my code?

Thanks for your help.

amira1
Associate II
Posted on May 17, 2011 at 09:36

Hi k7g2lm3,

you have 2 I2C examples in STR9 library and they work very well.

May be you have problem in your code. I will check it.

Best regards,

mirou

gu48bz
Associate II
Posted on May 17, 2011 at 09:36

Hi!

I have spent ages getting the I2C peripheral working on this IC, I've now got a real nice driver written. Sadly all the examples seem to be running using smoke and mirrors and the ST Ref manual is a tad vague in places.

So to your code...

SCU_APBPeriphClockConfig(__GPIO2, ENABLE);

SCU_APBPeriphReset(__GPIO2,DISABLE);

// At switch on I2C devices can get in a state where they

// are still waiting for a command due to all the bus lines bouncing

// around at startup have started clocking data into the device(s).

// Enable the ports as open collector port outputs

// and clock out at least 9 SCL pulses, then generate a stop

// condition and then leave the clock line high.

// For example of this checkout hitex demo code for the STR912.

// After that continue as normal ...

SCU_APBPeriphClockConfig(__I2C0,ENABLE);

// I typically do a disable, then an enable so to get things

// in a known state...

SCU_APBPeriphReset(__I2C0,ENABLE);

SCU_APBPeriphReset(__I2C0,DISABLE);

GPIO_InitTypeDef GPIO_InitStructure;

GPIO_DeInit(GPIO2);

GPIO_InitStructure.GPIO_Direction = GPIO_PinInput; // ERROR - Set to OUTPUT, not INPUT

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1;

GPIO_InitStructure.GPIO_Type = GPIO_Type_OpenCollector ;

GPIO_InitStructure.GPIO_IPConnected = GPIO_IPConnected_Enable; // NOTE - VERY CRITICAL, OTHERWISE WON'T SEE ANY ACK's or data read back. Relies on that in 91x_gpio.c that the input register is configured, even if we declare the port as an output.

GPIO_InitStructure.GPIO_Alternate = GPIO_OutputAlt2;

GPIO_Init (GPIO2, &GPIO_InitStructure);

I2C_InitTypeDef I2C_Struct;

I2C_DeInit(I2C0);

I2C_Struct.I2C_GeneralCall = I2C_GeneralCall_Disable;

I2C_Struct.I2C_Ack = I2C_Ack_Enable;

I2C_Struct.I2C_CLKSpeed =100000;

I2C_Struct.I2C_OwnAddress = 0xA0; // IF I2C Master then not required. I set to 0.

I2C_Init(I2C0, &I2C_Struct);

I2C_ITConfig (I2C0, DISABLE);

/* I2C Communication */

I2C_Cmd (I2C0, ENABLE); // Remove this line

// TODO - Check SR1 that busy flag is not set. Not essential though

// You can use I2C_GenerateStart( I2C0, ENABLE ); with HAL ...

I2C0->CR |= 0x08; // Start bit

while(!(I2C0->SR1 & 0x81) ); // I only check for I2C_FLAG_SB but should be ok as is.

// Can also do with I2C_Send7bitAddress( I2C0, (byAddress << 1), I2C_MODE_TRANSMITTER );

I2C0->DR = 0x42; // Address of the I2C peripheral.

// Remember that bit 0 = R/W flag,

// so may need to shift your address left by 1.

// Must check for SR1 next that I2C_FLAG_BTF | I2C_FLAG_EVF are not set.

// before continuing. critical!

// I also check 0x10 on SR2 to see if device ACK'd or not. If not then

// generate stop condition and bail out. A msut if dealing with EEPROM's

// etc. that have a reprogramming cycle and don't ack when in this cycle.

// REMOVE while (!(I2C0->SR2 & 0x20));

// Can also do this with I2C_Cmd (I2C0, ENABLE);

I2C0->CR |= 0x20;

// Can also do this with I2C_SendData(...)

I2C0->DR = 0x41; // Data to be sent to the I2C peripheral

while ( !(I2C0->SR1 & 0x88));

// Can also do that with I2C_GenerateSTOP( I2C0, ENABLE );

I2C0->CR |= 0x02; // Stop bit

I2C_Cmd(I2C0, DISABLE); // Remove this command

On all while loops I suggest having a long timeout, so in the case of hw failure the routine won't get stuck.

Let me know if you plan to do reading of more than a couple of bytes, as I2C read from a device is even more of a teaser! :D

PS. and if that works u owe me a virtual beer! :-]

[ This message was edited by: stevesky on 07-02-2007 01:08 ]

[ This message was edited by: stevesky on 07-02-2007 01:11 ]

aloisp
Associate II
Posted on May 17, 2011 at 09:36

Hi Mirou,

I tried these examples as well but they do not work. If I do not configure the I2C peripheral, I do not get anything (no start and stop bit). If I configure it as shown in my first post, I have start and stop bit working, but no adress nore data is sent. Do you think that it is possible that the I2C peripheral of the microcontroller is physically damaged (for example the internal data shift register of the I2C)?

Thanks for your help

aloisp
Associate II
Posted on May 17, 2011 at 09:36

Hi stevesky,

Thanks a lot for the time you spent in working on this problem. I modified the code according to your suggestions, but I could not manage to have the I2C working. I think my problem must be somewhere else, as the busy flag of the I2Cn_SR1 status register is never set. In STR91xF_Ref-Manual_12126.pdf we find concerning the busy flag: ''This bit is set by hardware on detection of a Start condition and cleared by hardware on detection of a Stop condition. It indicates a communication in progress on the bus.''

I went once more through the documentation of the I2C bus and decided to follow exactly the scheme which can be found on page 286 of this manual (figure 76):

7-bit Master transmitter

S___Address|A_______Data|A___P

_EV5_________EV6|EV8______EV8

With:

EV5: EVF=1, SB=1, cleared by reading I2Cn_SR1 register followed by writing I2Cn_DR register.

EV6: EVF=1, ENDAD=1 cleared by reading I2Cn_SR2 register followed by writing I2Cn_CR register (for example PE=1).

EV8: EVF=1, BTF=1, cleared by writing to the I2Cn_DR register.

Concerning BTF (taken from the manual): ''Following a byte transmission, this bit is set after reception of the acknowledge clock pulse.''

If checking this flag with EV8, it should not be necessary to additionally check the AF flag (Acknowledge failure). Correct me if I am wrong.

Here is my actual code:

/* I2C Configuration*/

SCU_APBPeriphClockConfig(__GPIO2, ENABLE);

SCU_APBPeriphReset(__GPIO2,DISABLE);

SCU_APBPeriphClockConfig(__I2C0,ENABLE);

SCU_APBPeriphReset(__I2C0,ENABLE);

SCU_APBPeriphReset(__I2C0,DISABLE);

GPIO_InitTypeDef GPIO_InitStructure;

GPIO_DeInit(GPIO2);

GPIO_InitStructure.GPIO_Direction = GPIO_PinOutput;

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1;

GPIO_InitStructure.GPIO_Type = GPIO_Type_OpenCollector ;

GPIO_InitStructure.GPIO_IPConnected = GPIO_IPConnected_Enable;

GPIO_InitStructure.GPIO_Alternate = GPIO_OutputAlt2;

GPIO_Init (GPIO2, &GPIO_InitStructure);

I2C_InitTypeDef I2C_Struct;

I2C_DeInit(I2C0);

I2C_Struct.I2C_GeneralCall = I2C_GeneralCall_Disable;

I2C_Struct.I2C_Ack = I2C_Ack_Enable;

I2C_Struct.I2C_CLKSpeed =100000;

I2C_Struct.I2C_OwnAddress = 0x00;

I2C_Init(I2C0, &I2C_Struct);

I2C_ITConfig (I2C0, DISABLE);

/* I2C Communication */

//Start bit

I2C_GenerateStart(I2C0, ENABLE);

//Next check EV5: I2C_FLAG_EVF | I2C_FLAG_BUSY | I2C_FLAG_M_SL | I2C_FLAG_SB

while(!I2C_CheckEvent(I2C0, I2C_EVENT_MASTER_MODE_SELECT) );

//Send address

I2C_Send7bitAddress(I2C0,0x42,I2C_MODE_TRANSMITTER);

//Next check EV6: I2C_FLAG_EVF | I2C_FLAG_BUSY | I2C_FLAG_M_SL | I2C_FLAG_ENDA

while(!I2C_CheckEvent(I2C0, I2C_EVENT_MASTER_MODE_SELECTED) );

//Next check EV8: I2C_FLAG_EVF | I2C_FLAG_BUSY | I2C_FLAG_M_SL | I2C_FLAG_BTF | I2C_FLAG_TRA

while(!I2C_CheckEvent(I2C0, I2C_EVENT_MASTER_BYTE_TRANSMITTED));

//Write I2Cn_CR register TWICE with PE=1

I2C_Cmd (I2C0, ENABLE);

//Send data

I2C_SendData(I2C0,0x41);

//Next check EV8: I2C_FLAG_EVF | I2C_FLAG_BUSY | I2C_FLAG_M_SL | I2C_FLAG_BTF | I2C_FLAG_TRA

while(!I2C_CheckEvent(I2C0, I2C_EVENT_MASTER_BYTE_TRANSMITTED));

//Stop bit

I2C_GenerateSTOP (I2C0, ENABLE);

The program hangs at the first while statement, as the busy flag is not set (all others are set : EVF, SB, M/SL). Of course I could only check the SB flag as you suggest, but if the busy flag is not set, then something is not working properly :(

Looking at the data line with an oscilloscope, I can confirm that the line goes from logical high to logical low when start bit is generated. Something is really strange.

Could you test my code in its actual version? I have been trying to have this I2C working for days, but my problem is maybe somewhere else (some conflict with other peripherals or a damaged mcu). Thanks a lot.

Concerning your virtual beer, we will arrange something... 🙂

aloisp
Associate II
Posted on May 17, 2011 at 09:36

Hi Steve,

I tried your suggestion (check the busy flag before generating the start bit), but still the busy flag would not appear as expected. As this code is part of a bigger project, I started to remove everything but the I2C configuration and communication. Oh surprise, the I2C worked! So reenabling the rest of the program step by step, I finally found that the problem was caused by a bug in the 91x_gpio.c library. This bug has been noticed by seawwh (see discussion ''A bug in 91x_gpio.c'').

During the last weeks I spent so much time trying to test all possible combinations of configuration and communication sequences for the I2C peripheral that I had the feeling the problem had to be somewhere else. It was!!!

Many thanks for your help. Where shall the bottle of wine be delivered?

Regards,

Alois

hugh2
Associate II
Posted on May 17, 2011 at 09:36

The original post was too long to process during our migration. Please click on the provided URL to read the original post. https://st--c.eu10.content.force.com/sfc/dist/version/download/?oid=00Db0000000YtG6&ids=0680X000006I6Vj&d=%2Fa%2F0X0000000bpX%2FqX9LDnfV8yAYqlSYrA_uJ3Os4nswSqcI1D8S1EYzgp0&asPdf=false
gu48bz
Associate II
Posted on May 17, 2011 at 09:36

Hi!

Yeh, sure I can. One attempt later and you are right - it blocks on the first while loop. One debug session and here is how to fix it. Checked it on Mr Logic Analyser and it looks good.

Basically to make your code work you need to do two things:

Before you do a call to I2C_GenerateStart do a call to I2C_CheckEvent( I2C0, I2C_FLAG_BUSY ). This resolves your busy flag. I do this in my code as standard, based on the advice I got from Hitex.

so:

I2C_CheckEvent( I2C0, I2C_FLAG_BUSY );

I2C_GenerateStart(I2C0, ENABLE);

Next up, don't believe the documentation! They claim that after writing the address check for EV6 and then EV8. Check for EV6 only. So the code goes:

//Send address

I2C_Send7bitAddress(I2C0,0xA0,I2C_MODE_TRANSMITTER);

//Next check EV6: I2C_FLAG_EVF | I2C_FLAG_BUSY | I2C_FLAG_M_SL | I2C_FLAG_ENDA

while(!I2C_CheckEvent(I2C0, I2C_EVENT_MASTER_MODE_SELECTED) );

//Write I2Cn_CR register TWICE with PE=1

I2C_Cmd (I2C0, ENABLE);

//Send data

I2C_SendData(I2C0,0x00);

//Next check EV8: I2C_FLAG_EVF | I2C_FLAG_BUSY | I2C_FLAG_M_SL | I2C_FLAG_BTF | I2C_FLAG_TRA

while(!I2C_CheckEvent(I2C0, I2C_EVENT_MASTER_BYTE_TRANSMITTED));

//Stop bit

I2C_GenerateSTOP (I2C0, ENABLE);

If that works I must be on for a bottle of wine! :-]

Cheers

Steve

daniel8
Associate II
Posted on May 17, 2011 at 09:36

As a sanity check, I assume you have pull-ups on your SCL and SDA lines on your board? If not, the bus will always be coming back as busy, and you wont get anywhere.