Skip to content

Commit fb66f6b

Browse files
Merge #245 #252
245: Implement DMA TargetAddress for I2C[123] r=richardeoin a=richardeoin 252: Clamp scldel/sdadel to 4-bit and update divider calculations r=richardeoin a=richardeoin 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 Co-authored-by: Richard Meadows <962920+richardeoin@users.noreply.github.com>
3 parents 04df62f + 122f987 + 1b1205e commit fb66f6b

File tree

4 files changed

+90
-49
lines changed

4 files changed

+90
-49
lines changed

src/dma/bdma.rs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -672,10 +672,8 @@ peripheral_target_address!(
672672
DMAReq::SPI6_RX_DMA,
673673
DMAReq::SPI6_TX_DMA
674674
),
675-
(pac::I2C4, rxdr, u8, P2M, DMAReq::I2C4_RX_DMA),
676-
(pac::I2C4, txdr, u8, M2P, DMAReq::I2C4_TX_DMA),
677-
(INNER: I2c<pac::I2C4>, rxdr, u8, P2M, DMAReq::I2C4_RX_DMA),
678-
(INNER: I2c<pac::I2C4>, txdr, u8, M2P, DMAReq::I2C4_TX_DMA),
675+
(HAL: I2c<pac::I2C4>, rxdr, u8, P2M, DMAReq::I2C4_RX_DMA),
676+
(HAL: I2c<pac::I2C4>, txdr, u8, M2P, DMAReq::I2C4_TX_DMA),
679677
);
680678

681679
#[cfg(not(feature = "rm0455"))]

src/dma/dma.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ use super::{
1010
use core::marker::PhantomData;
1111

1212
use crate::{
13+
i2c::I2c,
1314
pac::{self, DMA1, DMA2, DMAMUX1},
1415
rcc::{rec, rec::ResetEnable},
1516
serial, spi,
@@ -923,6 +924,15 @@ peripheral_target_address!(
923924
),
924925
);
925926

927+
peripheral_target_address!(
928+
(HAL: I2c<pac::I2C1>, rxdr, u8, P2M, DMAReq::I2C1_RX_DMA),
929+
(HAL: I2c<pac::I2C1>, txdr, u8, M2P, DMAReq::I2C1_TX_DMA),
930+
(HAL: I2c<pac::I2C2>, rxdr, u8, P2M, DMAReq::I2C2_RX_DMA),
931+
(HAL: I2c<pac::I2C2>, txdr, u8, M2P, DMAReq::I2C2_TX_DMA),
932+
(HAL: I2c<pac::I2C3>, rxdr, u8, P2M, DMAReq::I2C3_RX_DMA),
933+
(HAL: I2c<pac::I2C3>, txdr, u8, M2P, DMAReq::I2C3_TX_DMA),
934+
);
935+
926936
peripheral_target_address!(
927937
(pac::SAI1, cha.dr, u32, M2P, DMAReq::SAI1A_DMA),
928938
(pac::SAI1, chb.dr, u32, P2M, DMAReq::SAI1B_DMA),

src/dma/macros.rs

Lines changed: 55 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ macro_rules! peripheral_target_address {
1111
};
1212
}
1313
macro_rules! peripheral_target_instance {
14+
// PAC target
1415
(($peripheral:ty, $register:ident, $size:ty,
1516
$dir:ty $(, $mux:expr)*)) => {
1617
unsafe impl TargetAddress<$dir> for $peripheral {
@@ -26,8 +27,59 @@ macro_rules! peripheral_target_instance {
2627
}
2728
};
2829

29-
((SPI: $peripheral:ty, $rxreg:ident, $txreg:ident, [$($size:ty),+], $rxmux:expr, $txmux:expr)) => {
30-
// Access via PAC peripheral structures implies u8 sizing, as the sizing is unknown.
30+
// PAC target where register is within a channel
31+
(($peripheral:ty, $channel:ident.$register:ident, $size:ty,
32+
$dir:ty $(, $mux:expr)*)) => {
33+
unsafe impl TargetAddress<$dir> for $peripheral {
34+
#[inline(always)]
35+
fn address(&self) -> usize {
36+
&self.$channel.$register as *const _ as usize
37+
}
38+
39+
type MemSize = $size;
40+
$(
41+
const REQUEST_LINE: Option<u8> = Some($mux as u8);
42+
)*
43+
}
44+
};
45+
46+
// PAC and HAL targets, generic
47+
((HAL: $hal:ident<$peripheral:ty>, $register:ident, $size:ty,
48+
$dir:ty $(, $mux:expr)*)) => {
49+
50+
// PAC implementation
51+
unsafe impl TargetAddress<$dir> for $peripheral {
52+
#[inline(always)]
53+
fn address(&self) -> usize {
54+
&self.$register as *const _ as usize
55+
}
56+
57+
type MemSize = $size;
58+
$(
59+
const REQUEST_LINE: Option<u8> = Some($mux as u8);
60+
)*
61+
}
62+
63+
// HAL implementation
64+
unsafe impl TargetAddress<$dir> for $hal<$peripheral> {
65+
#[inline(always)]
66+
fn address(&self) -> usize {
67+
&self.inner().$register as *const _ as usize
68+
}
69+
70+
type MemSize = $size;
71+
$(
72+
const REQUEST_LINE: Option<u8> = Some($mux as u8);
73+
)*
74+
}
75+
};
76+
77+
// PAC and HAL targets for SPI peripheral
78+
((SPI: $peripheral:ty, $rxreg:ident, $txreg:ident, [$($size:ty),+],
79+
$rxmux:expr, $txmux:expr)) => {
80+
81+
// Access via PAC peripheral structures implies u8 sizing, as the sizing
82+
// is unknown.
3183
unsafe impl TargetAddress<M2P> for $peripheral {
3284
#[inline(always)]
3385
fn address(&self) -> usize {
@@ -76,6 +128,7 @@ macro_rules! peripheral_target_instance {
76128
)+
77129
};
78130

131+
// PAC and HAL targets for Serial Peripherals
79132
((SERIAL: $peripheral:ty, $rxreg:ident, $txreg:ident, $rxmux:expr, $txmux:expr)) => {
80133
unsafe impl TargetAddress<M2P> for $peripheral {
81134
#[inline(always)]
@@ -151,37 +204,4 @@ macro_rules! peripheral_target_instance {
151204
const TRBUFF: bool = true;
152205
}
153206
};
154-
155-
((INNER: $peripheral:ty, $register:ident $(($TRBUFF:ident))*, $size:ty,
156-
$dir:ty $(, $mux:expr)*)) => {
157-
unsafe impl TargetAddress<$dir> for $peripheral {
158-
#[inline(always)]
159-
fn address(&self) -> usize {
160-
&self.inner().$register as *const _ as usize
161-
}
162-
163-
type MemSize = $size;
164-
$(
165-
const REQUEST_LINE: Option<u8> = Some($mux as u8);
166-
)*
167-
$(
168-
const $TRBUFF: bool = true;
169-
)*
170-
}
171-
};
172-
173-
(($peripheral:ty, $channel:ident.$register:ident, $size:ty,
174-
$dir:ty $(, $mux:expr)*)) => {
175-
unsafe impl TargetAddress<$dir> for $peripheral {
176-
#[inline(always)]
177-
fn address(&self) -> usize {
178-
&self.$channel.$register as *const _ as usize
179-
}
180-
181-
type MemSize = $size;
182-
$(
183-
const REQUEST_LINE: Option<u8> = Some($mux as u8);
184-
)*
185-
}
186-
};
187207
}

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)