Skip to content

Commit 76a26de

Browse files
authored
Merge pull request #170 from stm32-rs/FMPI2C
Add implementation for Fastmode+ I2C available on select MCUs
2 parents b072300 + a115b66 commit 76a26de

File tree

1 file changed

+325
-2
lines changed

1 file changed

+325
-2
lines changed

src/i2c.rs

+325-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use core::ops::Deref;
2+
use embedded_hal::blocking::i2c::{Read, Write, WriteRead};
23

34
use crate::stm32::i2c1;
45

@@ -42,8 +43,6 @@ use crate::stm32::I2C3;
4243
))]
4344
use crate::stm32::{I2C1, I2C2, RCC};
4445

45-
use embedded_hal::blocking::i2c::{Read, Write, WriteRead};
46-
4746
#[cfg(any(
4847
feature = "stm32f401",
4948
feature = "stm32f405",
@@ -197,6 +196,13 @@ pub struct I2c<I2C, PINS> {
197196
pins: PINS,
198197
}
199198

199+
#[cfg(any(feature = "stm32f413", feature = "stm32f423",))]
200+
/// I2C FastMode+ abstraction
201+
pub struct FMPI2c<I2C, PINS> {
202+
i2c: I2C,
203+
pins: PINS,
204+
}
205+
200206
pub trait Pins<I2c> {}
201207
pub trait PinScl<I2c> {}
202208
pub trait PinSda<I2c> {}
@@ -492,6 +498,54 @@ impl PinScl<I2C3> for PH7<AlternateOD<AF4>> {}
492498
))]
493499
impl PinSda<I2C3> for PH8<AlternateOD<AF4>> {}
494500

501+
#[cfg(any(feature = "stm32f413", feature = "stm32f423",))]
502+
use crate::{
503+
gpio::{
504+
gpiob::{PB13, PB14, PB15},
505+
gpioc::{PC6, PC7},
506+
gpiod::{PD12, PD14, PD15},
507+
gpiof::{PF14, PF15},
508+
},
509+
pac::fmpi2c,
510+
pac::FMPI2C,
511+
};
512+
513+
#[cfg(any(feature = "stm32f413", feature = "stm32f423",))]
514+
impl PinScl<FMPI2C> for PC6<AlternateOD<AF4>> {}
515+
516+
#[cfg(any(feature = "stm32f413", feature = "stm32f423",))]
517+
impl PinSda<FMPI2C> for PC7<AlternateOD<AF4>> {}
518+
519+
#[cfg(any(feature = "stm32f413", feature = "stm32f423",))]
520+
impl PinSda<FMPI2C> for PB3<AlternateOD<AF4>> {}
521+
522+
#[cfg(any(feature = "stm32f413", feature = "stm32f423",))]
523+
impl PinScl<FMPI2C> for PB10<AlternateOD<AF9>> {}
524+
525+
#[cfg(any(feature = "stm32f413", feature = "stm32f423",))]
526+
impl PinSda<FMPI2C> for PB14<AlternateOD<AF4>> {}
527+
528+
#[cfg(any(feature = "stm32f413", feature = "stm32f423",))]
529+
impl PinScl<FMPI2C> for PB15<AlternateOD<AF4>> {}
530+
531+
#[cfg(any(feature = "stm32f413", feature = "stm32f423",))]
532+
impl PinScl<FMPI2C> for PD12<AlternateOD<AF4>> {}
533+
534+
#[cfg(any(feature = "stm32f413", feature = "stm32f423",))]
535+
impl PinScl<FMPI2C> for PB13<AlternateOD<AF4>> {}
536+
537+
#[cfg(any(feature = "stm32f413", feature = "stm32f423",))]
538+
impl PinScl<FMPI2C> for PD14<AlternateOD<AF4>> {}
539+
540+
#[cfg(any(feature = "stm32f413", feature = "stm32f423",))]
541+
impl PinScl<FMPI2C> for PD15<AlternateOD<AF4>> {}
542+
543+
#[cfg(any(feature = "stm32f413", feature = "stm32f423",))]
544+
impl PinScl<FMPI2C> for PF14<AlternateOD<AF4>> {}
545+
546+
#[cfg(any(feature = "stm32f413", feature = "stm32f423",))]
547+
impl PinScl<FMPI2C> for PF15<AlternateOD<AF4>> {}
548+
495549
#[derive(Debug)]
496550
pub enum Error {
497551
OVERRUN,
@@ -617,6 +671,30 @@ impl<PINS> I2c<I2C3, PINS> {
617671
}
618672
}
619673

674+
#[cfg(any(feature = "stm32f413", feature = "stm32f423",))]
675+
impl<PINS> FMPI2c<FMPI2C, PINS> {
676+
pub fn fmpi2c(i2c: FMPI2C, pins: PINS, speed: KiloHertz) -> Self
677+
where
678+
PINS: Pins<FMPI2C>,
679+
{
680+
// NOTE(unsafe) This executes only during initialisation
681+
let rcc = unsafe { &(*RCC::ptr()) };
682+
683+
// Enable clock for FMPI2C
684+
rcc.apb1enr.modify(|_, w| w.i2c4en().set_bit());
685+
686+
// Reset FMPI2C
687+
rcc.apb1rstr.modify(|_, w| w.i2c4rst().set_bit());
688+
rcc.apb1rstr.modify(|_, w| w.i2c4rst().clear_bit());
689+
690+
rcc.dckcfgr2.modify(|_, w| w.i2cfmp1sel().hsi());
691+
692+
let i2c = FMPI2c { i2c, pins };
693+
i2c.i2c_init(speed);
694+
i2c
695+
}
696+
}
697+
620698
impl<I2C, PINS> I2c<I2C, PINS>
621699
where
622700
I2C: Deref<Target = i2c1::RegisterBlock>,
@@ -852,3 +930,248 @@ where
852930
}
853931
}
854932
}
933+
934+
#[cfg(any(feature = "stm32f413", feature = "stm32f423",))]
935+
impl<I2C, PINS> FMPI2c<I2C, PINS>
936+
where
937+
I2C: Deref<Target = fmpi2c::RegisterBlock>,
938+
{
939+
fn i2c_init(&self, speed: KiloHertz) {
940+
use core::cmp;
941+
942+
// Make sure the I2C unit is disabled so we can configure it
943+
self.i2c.cr1.modify(|_, w| w.pe().clear_bit());
944+
945+
// Calculate settings for I2C speed modes
946+
let presc;
947+
let scldel;
948+
let sdadel;
949+
let sclh;
950+
let scll;
951+
952+
// We're using the HSI clock to keep things simple so this is going to be always 16 MHz
953+
const FREQ: u32 = 16_000_000;
954+
955+
// Normal I2C speeds use a different scaling than fast mode below and fast mode+ even more
956+
// below
957+
if speed <= 100.khz() {
958+
presc = 3;
959+
scll = cmp::max((((FREQ >> presc) >> 1) / speed.0) - 1, 255) as u8;
960+
sclh = scll - 4;
961+
sdadel = 2;
962+
scldel = 4;
963+
} else if speed <= 400.khz() {
964+
presc = 1;
965+
scll = cmp::max((((FREQ >> presc) >> 1) / speed.0) - 1, 255) as u8;
966+
sclh = scll - 6;
967+
sdadel = 2;
968+
scldel = 3;
969+
} else {
970+
presc = 0;
971+
scll = cmp::max((((FREQ >> presc) >> 1) / speed.0) - 4, 255) as u8;
972+
sclh = scll - 2;
973+
sdadel = 0;
974+
scldel = 2;
975+
}
976+
977+
// Enable I2C signal generator, and configure I2C for configured speed
978+
self.i2c.timingr.write(|w| unsafe {
979+
w.presc()
980+
.bits(presc)
981+
.scldel()
982+
.bits(scldel)
983+
.sdadel()
984+
.bits(sdadel)
985+
.sclh()
986+
.bits(sclh)
987+
.scll()
988+
.bits(scll)
989+
});
990+
991+
// Enable the I2C processing
992+
self.i2c.cr1.modify(|_, w| w.pe().set_bit());
993+
}
994+
995+
pub fn release(self) -> (I2C, PINS) {
996+
(self.i2c, self.pins)
997+
}
998+
999+
fn check_and_clear_error_flags(&self, isr: &fmpi2c::isr::R) -> Result<(), Error> {
1000+
// If we received a NACK, then this is an error
1001+
if isr.nackf().bit_is_set() {
1002+
self.i2c
1003+
.icr
1004+
.write(|w| w.stopcf().set_bit().nackcf().set_bit());
1005+
return Err(Error::NACK);
1006+
}
1007+
1008+
Ok(())
1009+
}
1010+
1011+
fn send_byte(&self, byte: u8) -> Result<(), Error> {
1012+
// Wait until we're ready for sending
1013+
while {
1014+
let isr = self.i2c.isr.read();
1015+
self.check_and_clear_error_flags(&isr)?;
1016+
isr.txis().bit_is_clear()
1017+
} {}
1018+
1019+
// Push out a byte of data
1020+
self.i2c.txdr.write(|w| unsafe { w.bits(u32::from(byte)) });
1021+
1022+
self.check_and_clear_error_flags(&self.i2c.isr.read())?;
1023+
Ok(())
1024+
}
1025+
1026+
fn recv_byte(&self) -> Result<u8, Error> {
1027+
while {
1028+
let isr = self.i2c.isr.read();
1029+
self.check_and_clear_error_flags(&isr)?;
1030+
isr.rxne().bit_is_clear()
1031+
} {}
1032+
1033+
let value = self.i2c.rxdr.read().bits() as u8;
1034+
Ok(value)
1035+
}
1036+
}
1037+
1038+
#[cfg(any(feature = "stm32f413", feature = "stm32f423",))]
1039+
impl<I2C, PINS> WriteRead for FMPI2c<I2C, PINS>
1040+
where
1041+
I2C: Deref<Target = fmpi2c::RegisterBlock>,
1042+
{
1043+
type Error = Error;
1044+
1045+
fn write_read(&mut self, addr: u8, bytes: &[u8], buffer: &mut [u8]) -> Result<(), Error> {
1046+
// Set up current slave address for writing and disable autoending
1047+
self.i2c.cr2.modify(|_, w| unsafe {
1048+
w.sadd1_7()
1049+
.bits(addr)
1050+
.nbytes()
1051+
.bits(bytes.len() as u8)
1052+
.rd_wrn()
1053+
.clear_bit()
1054+
.autoend()
1055+
.clear_bit()
1056+
});
1057+
1058+
// Send a START condition
1059+
self.i2c.cr2.modify(|_, w| w.start().set_bit());
1060+
1061+
// Wait until the transmit buffer is empty and there hasn't been any error condition
1062+
while {
1063+
let isr = self.i2c.isr.read();
1064+
self.check_and_clear_error_flags(&isr)?;
1065+
isr.txis().bit_is_clear() && isr.tc().bit_is_clear()
1066+
} {}
1067+
1068+
// Send out all individual bytes
1069+
for c in bytes {
1070+
self.send_byte(*c)?;
1071+
}
1072+
1073+
// Wait until data was sent
1074+
while {
1075+
let isr = self.i2c.isr.read();
1076+
self.check_and_clear_error_flags(&isr)?;
1077+
isr.tc().bit_is_clear()
1078+
} {}
1079+
1080+
// Set up current address for reading
1081+
self.i2c.cr2.modify(|_, w| unsafe {
1082+
w.sadd1_7()
1083+
.bits(addr)
1084+
.nbytes()
1085+
.bits(buffer.len() as u8)
1086+
.rd_wrn()
1087+
.set_bit()
1088+
});
1089+
1090+
// Send another START condition
1091+
self.i2c.cr2.modify(|_, w| w.start().set_bit());
1092+
1093+
// Send the autoend after setting the start to get a restart
1094+
self.i2c.cr2.modify(|_, w| w.autoend().set_bit());
1095+
1096+
// Now read in all bytes
1097+
for c in buffer.iter_mut() {
1098+
*c = self.recv_byte()?;
1099+
}
1100+
1101+
// Check and clear flags if they somehow ended up set
1102+
self.check_and_clear_error_flags(&self.i2c.isr.read())?;
1103+
1104+
Ok(())
1105+
}
1106+
}
1107+
1108+
#[cfg(any(feature = "stm32f413", feature = "stm32f423",))]
1109+
impl<I2C, PINS> Read for FMPI2c<I2C, PINS>
1110+
where
1111+
I2C: Deref<Target = fmpi2c::RegisterBlock>,
1112+
{
1113+
type Error = Error;
1114+
1115+
fn read(&mut self, addr: u8, buffer: &mut [u8]) -> Result<(), Error> {
1116+
// Set up current address for reading
1117+
self.i2c.cr2.modify(|_, w| unsafe {
1118+
w.sadd1_7()
1119+
.bits(addr)
1120+
.nbytes()
1121+
.bits(buffer.len() as u8)
1122+
.rd_wrn()
1123+
.set_bit()
1124+
});
1125+
1126+
// Send a START condition
1127+
self.i2c.cr2.modify(|_, w| w.start().set_bit());
1128+
1129+
// Send the autoend after setting the start to get a restart
1130+
self.i2c.cr2.modify(|_, w| w.autoend().set_bit());
1131+
1132+
// Now read in all bytes
1133+
for c in buffer.iter_mut() {
1134+
*c = self.recv_byte()?;
1135+
}
1136+
1137+
// Check and clear flags if they somehow ended up set
1138+
self.check_and_clear_error_flags(&self.i2c.isr.read())?;
1139+
1140+
Ok(())
1141+
}
1142+
}
1143+
1144+
#[cfg(any(feature = "stm32f413", feature = "stm32f423",))]
1145+
impl<I2C, PINS> Write for FMPI2c<I2C, PINS>
1146+
where
1147+
I2C: Deref<Target = fmpi2c::RegisterBlock>,
1148+
{
1149+
type Error = Error;
1150+
1151+
fn write(&mut self, addr: u8, bytes: &[u8]) -> Result<(), Error> {
1152+
// Set up current slave address for writing and enable autoending
1153+
self.i2c.cr2.modify(|_, w| unsafe {
1154+
w.sadd1_7()
1155+
.bits(addr)
1156+
.nbytes()
1157+
.bits(bytes.len() as u8)
1158+
.rd_wrn()
1159+
.clear_bit()
1160+
.autoend()
1161+
.set_bit()
1162+
});
1163+
1164+
// Send a START condition
1165+
self.i2c.cr2.modify(|_, w| w.start().set_bit());
1166+
1167+
// Send out all individual bytes
1168+
for c in bytes {
1169+
self.send_byte(*c)?;
1170+
}
1171+
1172+
// Check and clear flags if they somehow ended up set
1173+
self.check_and_clear_error_flags(&self.i2c.isr.read())?;
1174+
1175+
Ok(())
1176+
}
1177+
}

0 commit comments

Comments
 (0)