Calculate the Clock Control Register (CCR) values and actual bus frequency for I2C (Inter-Integrated Circuit) communication based on your microcontroller's peripheral clock and desired speed.
Standard Mode (100 kHz) – Duty 1:1
Fast Mode (400 kHz) – Duty 2:1
Fast Mode (400 kHz) – Duty 16:9
Calculated CCR Value:0
Actual SCL Frequency:0 kHz
Clock Period (T):0 μs
Frequency Error:0%
Understanding I2C Baud Rate Calculation
The I2C (Inter-Integrated Circuit) protocol uses a clock signal (SCL) to synchronize data transfer between a master and slave device. Configuring the correct baud rate is critical for ensuring data integrity, especially when interfacing with sensors, EEPROMs, or other microcontrollers.
How the Calculation Works
In most microcontrollers (like STM32, AVR, or PIC), the I2C baud rate is determined by the peripheral clock frequency ($f_{PCLK}$) and a divisor stored in the Clock Control Register (CCR). The formula changes depending on the mode (Standard vs. Fast) and the duty cycle.
1. Standard Mode (Sm)
Standard mode typically operates at 100 kHz with a 50% duty cycle (1:1 ratio of High to Low states).
CCR = f_PCLK / (2 × f_SCL_Target)
2. Fast Mode (Fm) – Duty 2:1
Fast mode operates up to 400 kHz. In a 2:1 duty cycle configuration, the Low state is twice as long as the High state.
CCR = f_PCLK / (3 × f_SCL_Target)
3. Fast Mode (Fm) – Duty 16:9
For higher speeds or specific bus capacitance requirements, a 16:9 duty cycle allows for a longer Low period relative to the High period.
CCR = f_PCLK / (25 × f_SCL_Target)
Why is there a Frequency Error?
Since the CCR register must store an integer value, the calculated result is often rounded. This rounding causes the actual generated frequency to differ slightly from the target frequency. Generally, an error within ±5% is acceptable for I2C communication.
Key Definitions
PCLK (Peripheral Clock): The frequency of the clock driving the I2C peripheral (input in MHz).
SCL (Serial Clock Line): The target communication speed (usually 100 kHz or 400 kHz).
CCR (Clock Control Register): The integer value programmed into the MCU to divide the PCLK down to the SCL speed.
Duty Cycle: The ratio of the clock signal's High time to Low time ($T_{high} : T_{low}$).
Common I2C Speeds
Standard Mode (Sm): Up to 100 kbit/s
Fast Mode (Fm): Up to 400 kbit/s
Fast Mode Plus (Fm+): Up to 1 Mbit/s
High Speed Mode (Hs): Up to 3.4 Mbit/s
function calculateI2C() {
// Get input elements
var pclkInput = document.getElementById("pclk");
var targetInput = document.getElementById("targetSpeed");
var dutySelect = document.getElementById("dutyCycle");
var errorDiv = document.getElementById("errorMsg");
var resultDiv = document.getElementById("result");
// Parse values
var pclkMHz = parseFloat(pclkInput.value);
var targetKHz = parseFloat(targetInput.value);
var mode = dutySelect.value;
// Reset display
errorDiv.style.display = "none";
resultDiv.style.display = "none";
// Validation
if (isNaN(pclkMHz) || pclkMHz <= 0) {
errorDiv.innerHTML = "Please enter a valid Peripheral Clock Frequency greater than 0.";
errorDiv.style.display = "block";
return;
}
if (isNaN(targetKHz) || targetKHz <= 0) {
errorDiv.innerHTML = "Please enter a valid Target Speed greater than 0.";
errorDiv.style.display = "block";
return;
}
// Convert units to Hz for calculation
var pclkHz = pclkMHz * 1000000;
var targetHz = targetKHz * 1000;
// Calculation Logic based on Mode
var ccr = 0;
var actualFreq = 0;
var minCCR = 0;
if (mode === "standard") {
// Standard Mode: Thigh = CCR * Tpclk, Tlow = CCR * Tpclk
// T_i2c = 2 * CCR * Tpclk
// CCR = f_pclk / (2 * f_target)
// Usually Min CCR is 4 for STM32 Standard Mode
minCCR = 4;
ccr = Math.round(pclkHz / (2 * targetHz));
if (ccr < minCCR) ccr = minCCR;
actualFreq = pclkHz / (2 * ccr);
} else if (mode === "fast21") {
// Fast Mode Duty 2:1
// Thigh = CCR * Tpclk, Tlow = 2 * CCR * Tpclk
// T_i2c = 3 * CCR * Tpclk
// CCR = f_pclk / (3 * f_target)
// Usually Min CCR is 1
minCCR = 1;
ccr = Math.round(pclkHz / (3 * targetHz));
if (ccr < minCCR) ccr = minCCR;
actualFreq = pclkHz / (3 * ccr);
} else if (mode === "fast169") {
// Fast Mode Duty 16:9
// Thigh = 9 * CCR * Tpclk, Tlow = 16 * CCR * Tpclk
// T_i2c = 25 * CCR * Tpclk
// CCR = f_pclk / (25 * f_target)
// Usually Min CCR is 1
minCCR = 1;
ccr = Math.round(pclkHz / (25 * targetHz));
if (ccr us
var errorPercent = ((actualFreqKHz – targetKHz) / targetKHz) * 100;
// Update UI
document.getElementById("ccrResult").innerHTML = "0x" + ccr.toString(16).toUpperCase() + " (" + ccr + ")";
document.getElementById("actualFreqResult").innerHTML = actualFreqKHz.toFixed(2) + " kHz";
document.getElementById("periodResult").innerHTML = periodUs.toFixed(3) + " μs";
var errorSpan = document.getElementById("errorResult");
errorSpan.innerHTML = (errorPercent > 0 ? "+" : "") + errorPercent.toFixed(2) + "%";
// Style error based on severity
if (Math.abs(errorPercent) > 5) {
errorSpan.style.color = "#dc3545"; // Red if bad
} else {
errorSpan.style.color = "#28a745"; // Green if good
}
resultDiv.style.display = "block";
}