2019-09-11 04:22 AM
I've been working with I2C on STM32s for some time and I noticed an issue while probing my signals with an oscilloscope.
I set my project with CubeMX and usse Atollic TrueStudio as an IDE. Everything works fine. However, I've noticed that the real frequency of I²C is always slightly below the frequency set on CubeMX. I'm using the NucleoF746ZG
For example, if I set the I²C to run at 100 kHz, the real frequency will be around 92 kHz. If I set the I²C to run at 400 kHz, the real frequency would be around 307 kHz, etc.
If I'm probing the clock frequency, it's sharp on 8 MHz, as it should be (MCO coming from ST-Link).
I was working with STM32F4 before and I dont remember having this issue as I've already probed the signals and it was exactly 100 kHz, 400 kHz or 1 MHz.
Is there something I am missing with the clock configuration for this particular peripheral on this MCU ?
Solved! Go to Solution.
2019-09-11 07:01 AM
How exactly are you communicating with the other device?
Interrupts? Maybe there are other interrupts with higher priority which affect I2C, try to set a higher priority for your I2C interrupts.
DMA? Same thing, try to increase I2C's DMA priority.
Try to isolate the problem - disable every other thing going on in the firmware and leave just the I2C.
Try to use another clock for I2C - i.e. the HSI.
Try to manually check Cube's automatically calculated read-only I2C "Timing" parameter, is it correct?
2019-09-11 06:31 AM
I tried again with a STM32F4 on a Nucleo F446ZE and indeed, the frequency of I2C is sharp on the desired value.
I tried to change the clock configuration of the projet on the F7, with the same sources, prescaler value than on the F4 but it didn't improve the situation.
2019-09-11 06:41 AM
Are you testing both boards with the same I2C slave device? Maybe F7's slave device stretches the clock.
2019-09-11 06:43 AM
I'm testing both boards with the exact same circuit.
2019-09-11 06:46 AM
I also tried to enable the "no stretch mode" with the F7 and it didn't change anything.
2019-09-11 06:56 AM
Well, look at I2C clock source frequency and I2C_TIMINGR values.
2019-09-11 07:01 AM
How exactly are you communicating with the other device?
Interrupts? Maybe there are other interrupts with higher priority which affect I2C, try to set a higher priority for your I2C interrupts.
DMA? Same thing, try to increase I2C's DMA priority.
Try to isolate the problem - disable every other thing going on in the firmware and leave just the I2C.
Try to use another clock for I2C - i.e. the HSI.
Try to manually check Cube's automatically calculated read-only I2C "Timing" parameter, is it correct?
2019-09-11 07:49 AM
I've tried several ways, including DMA in the past. I did isolate the I²C, with the exact same main() between the F4 project and F7 project. Right now, there is nothing else than the I²C transfer for both project. This transfer right now is done without DMA nor interrupts in order to isolate it from anything else.
I've tried to change the I²C clock source to HSI or others, I've also tried to increase the source frequency with no effect.
I did check Cube's "Timing" parameter and it didn't correspond to the example in the reference manual with the parameters I had (Source frequency, etc). I changed it manually inside the Init function with the value given in the reference manual and the I²C indeed has the correct frequency now. Thank you for the hint !
So it seems CubeMX does not update (or computes in the wrong way) the "Timing" parameter. How can we notify ST for this bug ?
2019-09-11 07:52 AM
You can check my answer to @After Forever , this was indeed the issue. CubeMX computes a wrong value of I2C_TIMINGR. I did change this value manually according to my parameters and the reference manual and the frequency change accordingly and is now correct. Thank you !
2019-09-12 06:37 AM
I've investigated the issue a bit more and in fact, it does not appear to be a bug : I simply did not specifies rise and fall time for my signals (mostly due to pull-up resistors). So when CubeMX computed the value of TSCL, it did not took into consideration Tsync1 and Tsync2. The workaround I found out is to compile the project with both rise and fall time at 0, plot the signal and write down the real period of the signal. The difference between the real period of your signal and the period you program is due to rise and fall time of the signals and thus, wrong assumptions of Tsync1 and Tsync2. you can then adjust Trise and Tfall according to this difference.
For example, if you want a 1 MHz I²C, you use 1 MHz in CubeMX, Trise = 0, Tfall = 0. You are expecting Tscl to be 1000 ns. You measure for example 1100 ns. You have then to add 100 ns for the rise time (fall time stays pretty much equals to 0). You'll then have the exact frequency you want.