Skip to content

Commit 1b1205e

Browse files
committed
Clamp scldel/sdadel to 4-bit and update divider calculations
Previously this code was calculating scldel/sdadel values > 15 which were correct, but could not be successfully used by the hardware. Update divider calculations to generally pick a larger prescaler value, resulting in a slower scaled clock. This means that scldel/sdadel values up to 15 still result in the required delays Fixes #238
1 parent be3100f commit 1b1205e

File tree

1 file changed

+23
-10
lines changed

1 file changed

+23
-10
lines changed

src/i2c.rs

Lines changed: 23 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -184,8 +184,8 @@ macro_rules! i2c_timing {
184184
// Fast-mode (Fm) or Fast-mode Plus (Fm+)
185185
// here we pick SCLL + 1 = 2 * (SCLH + 1)
186186

187-
// Prescaler, 384 ticks for sclh/scll. Round up then subtract 1
188-
let presc_reg = ((ratio - 1) / 384) as u8;
187+
// Prescaler, 96 ticks for sclh/scll. Round up then subtract 1
188+
let presc_reg = ((ratio - 1) / 96) as u8;
189189
// ratio < 1200 by pclk 120MHz max., therefore presc < 16
190190

191191
// Actual precale value selected
@@ -206,8 +206,8 @@ macro_rules! i2c_timing {
206206
// Fast-mode (Fm)
207207
assert!($i2cclk >= 8_000_000); // See table in datsheet
208208

209-
let sdadel = $i2cclk / 4_000_000 / presc;
210-
let scldel = $i2cclk / 2_000_000 / presc - 1;
209+
let sdadel = $i2cclk / 3_000_000 / presc;
210+
let scldel = $i2cclk / 1_000_000 / presc - 1;
211211

212212
(sdadel, scldel)
213213
};
@@ -224,10 +224,17 @@ macro_rules! i2c_timing {
224224
// here we pick SCLL = SCLH
225225
assert!($i2cclk >= 2_000_000); // See table in datsheet
226226

227-
// Prescaler, 512 ticks for sclh/scll. Round up then
227+
// Prescaler, 128 or 256 ticks for sclh/scll. Round up then
228228
// subtract 1
229-
let presc = (ratio - 1) / 512;
230-
let presc_reg = cmp::min(presc, 15) as u8;
229+
let presc_reg = (ratio - 1)
230+
/ if $freq < 8000 {
231+
256
232+
} else if $freq < 80_000 {
233+
128
234+
} else {
235+
64
236+
};
237+
let presc_reg = cmp::min(presc_reg, 15) as u8;
231238

232239
// Actual prescale value selected
233240
let presc = (presc_reg + 1) as u32;
@@ -257,9 +264,12 @@ macro_rules! i2c_timing {
257264
assert!(presc_reg < 16);
258265

259266
// Keep values within reasonable limits for fast per_ck
260-
let sdadel = cmp::max(sdadel, 2);
267+
let sdadel = cmp::max(sdadel, 1);
261268
let scldel = cmp::max(scldel, 4);
262269

270+
let sdadel = cmp::min(sdadel, 15);
271+
let scldel = cmp::min(scldel, 15);
272+
263273
(presc_reg, scll, sclh, sdadel, scldel)
264274
}};
265275
}
@@ -811,8 +821,8 @@ mod tests {
811821
);
812822

813823
// We must generate a bus frequency less than or equal to that
814-
// specified. Tolerate a 0.5% error
815-
assert!(f_scl <= 1.005 * freq);
824+
// specified. Tolerate a 2% error
825+
assert!(f_scl <= 1.02 * freq);
816826

817827
// But it should not be too much less than specified
818828
assert!(f_scl > 0.8 * freq);
@@ -884,6 +894,7 @@ mod tests {
884894
"T SDA DELAY {:.2e} MINIMUM {:.2e}",
885895
t_sdadel, t_sdadel_minimim
886896
);
897+
assert!(sdadel <= 15);
887898
assert!(t_sdadel >= t_sdadel_minimim);
888899
});
889900
}
@@ -917,6 +928,7 @@ mod tests {
917928
"T SDA DELAY {:.2e} MAXIMUM {:.2e}",
918929
t_sdadel, t_sdadel_maximum
919930
);
931+
assert!(sdadel <= 15);
920932
assert!(t_sdadel <= t_sdadel_maximum);
921933
});
922934
}
@@ -957,6 +969,7 @@ mod tests {
957969
"T SCL DELAY {:.2e} MINIMUM {:.2e}",
958970
t_scldel, t_scldel_minimum
959971
);
972+
assert!(scldel <= 15);
960973
assert!(t_scldel >= t_scldel_minimum);
961974
});
962975
}

0 commit comments

Comments
 (0)