2009-09-18 09:07 AM
2011-05-17 12:36 AM
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.2011-05-17 12:36 AM
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, mirou2011-05-17 12:36 AM
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 ]2011-05-17 12:36 AM
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 help2011-05-17 12:36 AM
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... :)2011-05-17 12:36 AM
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, Alois2011-05-17 12:36 AM
2011-05-17 12:36 AM
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 Steve2011-05-17 12:36 AM
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.