cancel
Showing results for 
Search instead for 
Did you mean: 

No I2C Clock signal after Restart Condition

uli stone
Associate II

Hello,

I raised this problem in another topic I posted, but it is with another title and I'm not sure I will get there the help (title might be missleading).

I have the problem after sending Slave Address and Register Address and creating a start condition I don't get any clock signal from the STM32F4 microcontroller.

Hoch can I solve this?

Thank you0690X000006DUzQQAW.png

12 REPLIES 12
Danish1
Lead II

Please could you post some more information about your problem. You probably included a lot of it in your post to the other topic. But how many of us will bother to search for that post?

From your trace, I see you generate a STOP condition as well as a START. My understanding is that a restart is a start-condition without a STOP condition before it (so no other bus-master may try to get control). And after that (RE)START, the I2C peripheral is waiting for you to feed it the slave address.

Help us to help you,

Danish

uli stone
Associate II

Hi @Danish,

I'm very sorry for the inconvenience, please accpet my sincere apology.

I will try to give you all the information I have.

I'm working with the STM32F429 Disco Board, and there is only one Slave connected, no other Master (only the STm32F4 should act as master).

Please notice that sometimes the logic analyser interpretation is wrong! In the first picture posted here the address send is 0x42 followed by 0x01 (logic analyser says 0x61 and 0x00 which is wrong when compared to the SCL clock).

Somehow the second address is not transmitted over the bus.

Following is the code to to send both addresses and read 8 bit data.

    	I2C2_St();
    	I2C2_Ad(0x42);
    	I2C2_Wr(0x01);
    	I2C2_St();
    	I2C2_Ad(0x43);
    	I2C2_R(0);
    	I2C2_Sp();

Here are the functions which are used for Start, Address, write, Stop.

0690X000006DTAGQA4.png

This is the latest image showing the pin output of my logic analyser (without the for-delay loop, 20 cyles, in the functions for Start/Stop/Address/Write/Read).

0690X000006DZheQAG.png

I additionally experienced that when going through this code step by step:

    	I2C2_St();
    	I2C2_Ad(0x42);
    	I2C2_Wr(0x01);
    	I2C2_St();
    	I2C2_Ad(0x43);
    	I2C2_R(0);
    	I2C2_Sp();

I get for the 0x43 address sending, 7 clock pulses and then the the clock signal stops (when running through it without a pause I don't get anything, as shown above).

0690X000006DZhjQAG.png

I hope this clears up everything (?) thank you for trying to helping to solve the problem I'm facing!

Uli

Danish1
Lead II

No apology needed. We're all volunteers here; it's just better to frame your request so more people are willing to help.

I notice a lot of delay loops in your code. I regard this as a bad thing. It is good to be able to give up on an operation that has failed, in which case you could usefully flag back to a higher level that things have failed. But you shouldn't rely on software delays to allow the I2C peripheral to do its job. If you want to be sure that a write to a peripheral has happened (rather than sitting in a bus-matrix-buffer; probably not a problem for stm32f4 but necessary for stm32f7) then you can stall the cpu for the necessary time with a __DSB() instruction.

The I2C peripheral sets flags to tell you that it has completed an operation and is ready for the cpu to tell it what to do next. My guess for your immediate problem is that you ask for the repeated-start once TXE is asserted. You should wait for BTF (EV8_2).

The flags you need to check at each stage are shown in the Reference Manual; for stm32f4 this is section 27.3.3 figures 243 and 244. Sadly they don't show repeated-start but I find that you can issue the repeated-start when it is ok to issue a stop.

Hope this helps,

Danish

uli stone
Associate II

Hi @Danish​ ,

thank you very much for your valuable advice. Sadly it only helped a bit (especially only 7 bits).

After I changed the code to this:

void I2C2_Write(unsigned char write_data)
{
	I2C2->DR = write_data;
	int counter_lost_communication = 0;
	while (!(I2C2->SR1 & I2C_SR1_BTF) && (counter_lost_communication<249))
		counter_lost_communication++;
}

I then get after the restart condition 7 clock pulses, after that the clock signal is not giving more pulses.

When I comment the break condition out of the while loop, the code gets stuck at exactly the BTF-Flag. So it looks like I'm not getting any Byte transfer finished flag.

The inital idea was to use TXE instead of BTF because I'm using a sensor which sometimes will not ACK. But I think this at the moment does not solve my problem.0690X000006Dav8QAC.png

For the for-loops, I removed them. It was my desperate attempt to get the code working.

I hope you can help me further to solve this problem.

Thank you very much

Danish1
Lead II

Try with those counts-to-249 to much higher values. I2C is very slow in microcontroller terms. My guess is that it times out and then you start hitting I2C2->CR1 from within I2C2_R() which is why you don't get the last bit of address properly clocked.

And when things do bomb out with the very high counts, either your code is wrong or the peripheral is not ACKing for legitimate reasons - in which case you should give up the entire conversation and issue a stop condition.

If you only intend to receive one byte, the small print in Figure 244 EV6 says that you should disable acknowledge before clearing the ADDR flag. I don't think your program-flow does this. I tend to do it with the write to CR1 that sets START.

Oh and when writing byte-after-byte of data, you don't need to wait for BTF to complete. TXE is fine (there's one byte of buffering in the peripheral). It's only when you want to issue a stop or repeated-start that you should wait for BTF.

Hope this helps,

Danish

uli stone
Associate II

Sadly Increasing the exit_counter for the I2C Communication and removing I2C2_Read(0); does not help, I get the exact same logic analyser output as posted today.

Only thing which changes it (and I get all clock pulses for the send Address) is removing the Re-Start() condition, but then I don't have any clock signal for receiving the data.

I connected another sensor and with the second sensor my I2C Communication does work perfectly!

I have the same camera and change it, its the same thing there, called ov7670.

Danish1
Lead II

Something I find strange is that the address you provide after restart in your "Sadly it only helped a bit (especially only 7 bits)." reply seems to be 0x42 again - not the 0x43 needed for a read. Could you double-check that didn't get mis-edited?

I suppose it's possible your sensor doesn't cope with I2C restarts and is driving its ACK early, in which case the stm32 I2C module might think it has lost arbitration and relinquish the bus, and so not drive another clock so the bus stays with the sensor driving the ACK. You can find out which device is driving the SDA line by putting series resistors at strategic points into the line and looking for the voltage drop. 100 ohms should be sufficient without interfering with communication.

Regards,

Danish

uli stone
Associate II

Hi @Danish​ ,

I tried till 4 in the morning and have now the clock pulses for the Second Address. It only works when I do the following:

I2C2_St();
I2C2_Ad(0x42);
I2C2_Wr(0x01);
I2C2_Sp();
for(int delay=0; delay<100; delay++); // code does only work with a delay here!
I2C2_St();
I2C2_Ad(0x43);
I2C2_R(0);
I2C2_Sp();

But for now, I'm still faceing the problem, that I don't get any clock pulses for the signal to be read! How can I figure out why there is no clock signal? After the second address (9th pulse which is a ACK) the SCL-Line is low and the SDA Line goes high.

Maybe you can shed some light, what I forgot or what the difference between the STM32F4 StdLib is to my code. Because with with the StdLib the Communication is working - and I couldn't find any derivation of my code to the code on this site.

Danish1
Lead II

That delay loop is because you need to wait until I2C_SR2_MSL is clear to know that the stop-condition has completed before you can issue the next start condition.