Continue to Site

Welcome to EDAboard.com

Welcome to our site! EDAboard.com is an international Electronics Discussion Forum focused on EDA software, circuits, schematics, books, theory, papers, asic, pld, 8051, DSP, Network, RF, Analog Design, PCB, Service Manuals... and a whole lot more! To participate you need to register. Registration is free. Click here to register now.

I2C timing stm32

Rimvis123

Junior Member level 2
Junior Member level 2
Joined
Oct 30, 2023
Messages
22
Helped
1
Reputation
2
Reaction score
0
Trophy points
1
Activity points
204
hello,

I'm new with I2C and I don't understand from where people are getting this 0x00707CBB timing adress in Stm32. I'm using Stm32wb55cgu6 and SCD-40 CO2 sesnor and i used this adress, everything works fine, but how to get it? Because when I just create and open stm32CubeIDE I only get 0x00000E14 timing adress.
 
Hi,

give complete informations:
Which people?
What source? (link?)
What makes you think it is an address?

****
On the other hand:
CubeIDE is made that a designer does not need to read to several thousands of pages of microcontroller documentation.

But if you want to go into details the manufacturer provides all informations. Like RM04343. It´s not hard to find if you g on the manufacturer´s website for the according microcontroller.

Klaus
 
Thanks for your answer. When i used google ant was typing "How to connect gas sensor with stm32 using I2C" I saw some issue request with codes in which I saw this number. Now for example you can see this number in codes like this (somebody had soome issues with I2C, but still there are 0x000707CBB. https://www.eevblog.com/forum/microcontrollers/stm32-i2c-with-hal-what-am-i-doing-wrong/
Here too :https://community.st.com/t5/stm32-m...-use-the-stm32l432-as-slave-while/td-p/114319
These are not links which I used to code, but these also have this number in I2C timing, so how they know, that you need exatly this? Stm32wb55cgu datasheet does not give this number, SCD-40 also. And yeah this is not adress, for example scd-40 0x62 is I2C adress.
 
Hi,

When i used google ant was typing "How to connect gas sensor with stm32 using I2C"
What answers do you expect with this question?
* Maybe someone has done exactly this and ... it will show you their code ... in best case with a little bit of documentation.

I - as a long term electronics designer - have a different view on the "problem":
I2C is a standard. The STM as well as the sensor has to keep on this standard.
Thus - for the STM - it does not matter what I2C device is connected.
Standard I2C clock speed is defined to be 100kHz. Each microcontroller needs to support this, each device needs to support this.
So just do a standard STM I2C setup and you are on the safe side .. independent of what I2C device you use.

***
ONLY if you want to leave this standard (but then you should tell: why), then you have to go deeper.
One reason may be that you need faster data transfer.
Then first have a look into the seonsor datasheet what spped it supports.
(standard mode: 100 kbit/s, full speed: 400 kbit/s, fast mode: 1 Mbit/s, high speed: 3,2 Mbit/s)
I dont´recommend to use different, non standard frequencies.

Again: these should be exceptions. If you chose a higher speed than 100kbit/s then you need to be sure EVERY I2C device on the bus needs to support this speed.

*****
It´s like learning a different language. And I2C is like a language.
You don´t learn to speak with "person x", you learn to speak "langage X"

For sure the meaning of the bytes depend on the I2C devices. But this has nothing to do with I2C interface setup within the STM.

I2C communication is always:
START | Save_Address RW | ACK | DATA | ACK | .... | STOP
and the meaning of DATA is the device specific part, everything else is just I2C standard.

Klaus
 
Last edited:
Hi,


What answers do you expect with this question?
* Maybe someone has done exactly this and ... it will show you their code ... in best case with a little bit of documentation.

I - as a long term electronics designer - have a different view on the "problem":
I2C is a standard. The STM as well as the sensor has to keep on this standard.
Thus - for the STM - it does not matter what I2C device is connected.
Standard I2C clock speed is defined to be 100kHz. Each microcontroller needs to support this, each device needs to support this.
So just do a standard STM I2C setup and you are on the safe side .. independent of what I2C device you use.

***
ONLY if you want to leave this standard (but then you should tell: why), then you have to go deeper.
One reason may be that you need faster data transfer.
Then first have a look into the seonsor datasheet what spped it supports.
(standard mode: 100 kbit/s, full speed: 400 kbit/s, fast mode: 1 Mbit/s, high speed: 3,2 Mbit/s)
I dont´recommend to use different, non standard frequencies.

Again: these should be exceptions. If you chose a higher speed than 100kbit/s then you need to be sure EVERY I2C device on the bus needs to support this speed.

*****
It´s like learning a different language. And I2C is like a language.
You don´t learn to speak with "person x", you learn to speak "langage X"

For sure the meaning of the bytes depend on the I2C devices. But this has nothing to do with I2C interface setup within the STM.

I2C communication is always:
START | Save_Address RW | ACK | DATA | ACK | .... | STOP
and the meaning of DATA is the device specific part, everything else is just I2C standard.

Klaus
I know it's a little bit late, but here is my implementation for stm32g030.
It might be useful to someone

C:
/* ======================================================================
 * The function calculates optimal timing of the I2C bus
 *
 * @param pclk1_hz    - PCLK frequency (Hz)
 * @param i2c_freq_hz - target I2C clock frequency (Hz)
 * @retvalue          - timing register value
 * ======================================================================*/
uint32_t I2C_calculate_timing(const uint32_t pclk1_hz, const uint32_t i2c_freq_hz)
{
    const uint32_t clock_period_ns = 1000000000 / pclk1_hz;
    const uint32_t i2c_period_ns   = 1000000000 / i2c_freq_hz;
    const uint32_t af_delay_ns     = 50; // Analog filter delay (ns)
 
    // Determine speed mode limits & digital filter delay (ns)
    uint32_t tlow_min, thigh_min, tsudat_min, dfn;
 
    if (i2c_freq_hz <= 100000) {
        tlow_min   = i2c_period_ns * 470 >> 10;
        thigh_min  = i2c_period_ns * 400 >> 10;
        tsudat_min = 250;
        dfn = 4;
    } else if (i2c_freq_hz <= 400000) {
        tlow_min   = i2c_period_ns * 540 >> 10;
        thigh_min  = i2c_period_ns * 250 >> 10;
        tsudat_min = 100;
        dfn = 2;
    }  else if (i2c_freq_hz <= 1000000) {
        tlow_min   = i2c_period_ns * 520 >> 10;
        thigh_min  = i2c_period_ns * 270 >> 10;
        tsudat_min = 50;
        dfn = 0;
    } else {
        return 0;
    }
 
    const uint32_t filter_delay_ns = af_delay_ns + (dfn * clock_period_ns);
    const uint32_t sdadel_min_ns = filter_delay_ns;
    const uint32_t sdadel_max_ns = i2c_period_ns >> 2;
    const uint32_t scldel_min_ns = tsudat_min + filter_delay_ns;
 
    // Target period with 20% margin
    const uint32_t period_max = i2c_period_ns + (i2c_period_ns / 5);
    const uint32_t period_min = i2c_period_ns - (i2c_period_ns / 5);
 
    uint32_t tmp_presc  = 0;
    uint32_t tmp_scldel = 0;
    uint32_t tmp_sdadel = 0;
    uint32_t tmp_sclh   = 0;
    uint32_t tmp_scll   = 0;
    uint32_t tmp_error  = UINT32_MAX;

    // Binary search helper function for SCLH and SCLL
    for (uint32_t presc = 0; presc < 16; presc++) {
        const uint32_t ti2cclk = clock_period_ns * (presc + 1);
     
        for (uint32_t scldel = 0; scldel < 16; scldel++) {
            const uint32_t tscldel = (scldel + 1) * ti2cclk;
            if (tscldel < scldel_min_ns) continue;
         
            for (uint32_t sdadel = 0; sdadel < 16; sdadel++) {
                const uint32_t tsdadel = sdadel * ti2cclk;
                if (tsdadel < sdadel_min_ns || tsdadel > sdadel_max_ns) continue;
             
                const uint32_t tsync = filter_delay_ns + 2 * ti2cclk;
             
                // Binary search for SCLH
                uint32_t sclh_min = (thigh_min - filter_delay_ns + ti2cclk - 1) / ti2cclk - 1;
                if (sclh_min >= 256) continue;
                uint32_t sclh_max = 255;
             
                while (sclh_min <= sclh_max) {
                    const uint32_t sclh = (sclh_min + sclh_max) >> 1;
                    const uint32_t tsclh = (sclh + 1) * ti2cclk;
                    const uint32_t thigh = tsclh + filter_delay_ns;
                 
                    if (thigh < thigh_min) {
                        sclh_min = sclh + 1;
                        continue;
                    }
                 
                    if (ti2cclk >= thigh) {
                        sclh_min = sclh + 1;
                        continue;
                    }
                 
                    // Binary search for SCLL
                    uint32_t scll_min = (tlow_min - filter_delay_ns + ti2cclk - 1) / ti2cclk - 1;
                    if (scll_min >= 256) {
                        sclh_min = sclh + 1;
                        continue;
                    }
                    uint32_t scll_max = 255;
                 
                    while (scll_min <= scll_max) {
                        const uint32_t scll = (scll_min + scll_max) >> 1;
                        const uint32_t tscll = (scll + 1) * ti2cclk;
                        const uint32_t tlow = tscll + filter_delay_ns;
                     
                        if (tlow < tlow_min) {
                            scll_min = scll + 1;
                            continue;
                        }
                     
                        if (ti2cclk >= (tlow - filter_delay_ns) / 4) {
                            scll_min = scll + 1;
                            continue;
                        }
                     
                        const uint32_t ttotal = tscll + tsclh + 2 * tsync;
                     
                        if (ttotal < period_min) {
                            scll_min = scll + 1;
                            continue;
                        }
                     
                        if (ttotal > period_max) {
                            scll_max = scll - 1;
                            continue;
                        }
                     
                        // Calculate error
                        const uint32_t error = (ttotal > i2c_period_ns)
                            ? ttotal - i2c_period_ns
                            : i2c_period_ns - ttotal;
                     
                        // Update if better timing found
                        if (error < tmp_error) {
                            tmp_error  = error;
                            tmp_presc  = presc;
                            tmp_scldel = scldel;
                            tmp_sdadel = sdadel;
                            tmp_sclh   = sclh;
                            tmp_scll   = scll;
                        }
                     
                        // Try to find better error by decreasing SCLL
                        scll_max = scll - 1;
                    }
                    // Try to find better error by decreasing SCLH
                    sclh_max = sclh - 1;
                }
            }
        }
    }
 
    if (tmp_error == UINT32_MAX) {
        return 0;
    }
 
    return (tmp_presc << 28) | (tmp_scldel << 20) | (tmp_sdadel << 16) | (tmp_sclh << 8) | tmp_scll;
}
 
Last edited:
Hi,

some comments:

You did a lot of effort .. and I guess your solution does work.

There may be a reason for you (we don´t know this reason) .... but for 99.99% of applications the I2C should be used as standard interface.
But here it seems you leave the standard ... and made rocket science out of it.

(Since many newbies are already terrified by the name "interface" or "I2C": The code above is NOT what you need. Just use I2C as shown in many examples. The code above is only needed (if ever) by non standard applications that need to go to the timing limits of special ICs)

Again ... your solution may be perfect for you ... but "I2C standard" only tells of 3 speed grades (that I know)
The speed grades (standard mode: 100 kbit/s, full speed: 400 kbit/s, fast mode: 1 Mbit/s, high speed: 3,2 Mbit/s) are maximum ratings.
No need to be exact for the frequencies, no need to be exact for the bit timings (they already included enough margin).

So the usualy way is
* to include an I2C library and a command similar to "I2C_start (100000)" ... (as example) that´s all
* or to use the setup code generator like the STM32CubeIDE and just set it to 100.000 Hz (or any of the above clock frequencies) .. that´s all

That´s the benefit of a standard interface with standard clock frequencies .. it´s simple to use. No high accuracy required.

...
The other thing to mention is:
You write the code in a way that all the processing is done during run time. Usually - since all the vlues are known at compile time - all the calculations are done by the complier. Thus usually it neither needs code space nor processing time inside the microcontroller to do all the math and logic.

....

Again ... you maybe did a perfect job ... but the effort is not worth it in 99.99% of I2C usage.

Klaus
 

LaTeX Commands Quick-Menu:

Similar threads

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top