Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
  • Loading branch information
David-OConnor committed Dec 19, 2024
2 parents ac80bad + 39aef4e commit 1a2a01c
Show file tree
Hide file tree
Showing 4 changed files with 126 additions and 88 deletions.
15 changes: 13 additions & 2 deletions src/clocks/f.rs
Original file line number Diff line number Diff line change
Expand Up @@ -505,7 +505,9 @@ impl Clocks {
w.pllsrc().bit(pll_src.bits() != 0);
w.plln().bits(self.plln);
w.pllm().bits(self.pllm);
w.pllp().bits(self.pllp as u8)
w.pllp().bits(self.pllp as u8);
w.pllq().bits(self.pllq.value());
w
});
}
}
Expand Down Expand Up @@ -645,7 +647,16 @@ impl Clocks {
#[cfg(feature = "f3")]
return self.sysclk() / self.usb_pre.value() as u32;
#[cfg(feature = "f4")]
return 0; // todo
match self.input_src {
InputSrc::Pll(pll_src) => {
let input_freq = match pll_src {
PllSrc::Hsi => 16_000_000,
PllSrc::Hse(freq) => freq,
};
input_freq / self.pllm as u32 * self.plln as u32 / self.pllq.value() as u32
}
_ => 0
}
}

pub fn apb1(&self) -> u32 {
Expand Down
7 changes: 7 additions & 0 deletions src/dma.rs
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,13 @@ pub enum DmaInput {
Usart2Tx = 44,
Usart3Rx = 45,
Usart3Tx = 46,
Tim8Ch1 = 47,
Tim8Ch2 = 48,
Tim8Ch3 = 49,
Tim8Ch4 = 50,
Tim8Up = 51,
Tim8Trig = 52,
Tim8Com = 53,
Tim5Ch1 = 55,
Tim5Ch2 = 56,
Tim5Ch3 = 57,
Expand Down
184 changes: 102 additions & 82 deletions src/i2c_f4.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
use core::ops::Deref;

#[cfg(feature = "embedded_hal")]
use embedded_hal::blocking::i2c::{Read, Write, WriteRead};
use embedded_hal::i2c::{ErrorKind, NoAcknowledgeSource, Operation, SevenBitAddress};
use paste::paste;

use crate::{
Expand Down Expand Up @@ -37,6 +37,20 @@ pub enum Error {
ARBITRATION,
}

#[cfg(feature = "embedded_hal")]
#[cfg_attr(docsrs, doc(cfg(feature = "embedded_hal")))]
impl embedded_hal::i2c::Error for Error {
fn kind(&self) -> ErrorKind {
match self {
Error::OVERRUN => ErrorKind::Overrun,
Error::NACK => ErrorKind::NoAcknowledge(NoAcknowledgeSource::Unknown),
Error::TIMEOUT | Error::CRC => ErrorKind::Other,
Error::BUS => ErrorKind::Bus,
Error::ARBITRATION => ErrorKind::ArbitrationLoss,
}
}
}

/// Represents an Inter-Integrated Circuit (I2C) peripheral.
pub struct I2c<R> {
pub regs: R,
Expand Down Expand Up @@ -249,100 +263,106 @@ where

#[cfg(feature = "embedded_hal")]
#[cfg_attr(docsrs, doc(cfg(feature = "embedded_hal")))]
impl<R> WriteRead for I2c<R>
impl<R> embedded_hal::i2c::ErrorType for I2c<R>
where
R: Deref<Target = i2c1::RegisterBlock>,
{
type Error = Error;

fn write_read(&mut self, addr: u8, bytes: &[u8], buffer: &mut [u8]) -> Result<(), Self::Error> {
self.write_bytes(addr, bytes)?;
self.read(addr, buffer)?;

Ok(())
}
}

#[cfg(feature = "embedded_hal")]
#[cfg_attr(docsrs, doc(cfg(feature = "embedded_hal")))]
impl<R> Write for I2c<R>
impl<R> embedded_hal::i2c::I2c<SevenBitAddress> for I2c<R>
where
R: Deref<Target = i2c1::RegisterBlock>,
{
type Error = Error;

fn write(&mut self, addr: u8, bytes: &[u8]) -> Result<(), Self::Error> {
self.write_bytes(addr, bytes)?;

// Send a STOP condition
self.regs.cr1.modify(|_, w| w.stop().set_bit());

// Wait for STOP condition to transmit.
while self.regs.cr1.read().stop().bit_is_set() {}

// Fallthrough is success
Ok(())
}
}

#[cfg(feature = "embedded_hal")]
#[cfg_attr(docsrs, doc(cfg(feature = "embedded_hal")))]
impl<R> Read for I2c<R>
where
R: Deref<Target = i2c1::RegisterBlock>,
{
type Error = Error;
fn transaction(
&mut self,
address: SevenBitAddress,
operations: &mut [Operation<'_>],
) -> Result<(), Self::Error> {
/*
embedded_hal Operation Contract:
1 - Before executing the first operation an ST is sent automatically. This is followed by SAD+R/W as appropriate.
2 - Data from adjacent operations of the same type are sent after each other without an SP or SR.
3 - Between adjacent operations of a different type an SR and SAD+R/W is sent.
4 - After executing the last operation an SP is sent automatically.
5 - If the last operation is a Read the master does not send an acknowledge for the last byte.
- ST = start condition
- SAD+R/W = slave address followed by bit 1 to indicate reading or 0 to indicate writing
- SR = repeated start condition
- SP = stop condition
Note: This hasn't been implemented! I assume 1 and 3 will be, but for 2 we start/stop after each operation
*/

for op in operations {
match op {
Operation::Write(buffer) => {
self.write_bytes(address, buffer)?;

// Send a STOP condition
self.regs.cr1.modify(|_, w| w.stop().set_bit());

// Wait for STOP condition to transmit.
while self.regs.cr1.read().stop().bit_is_set() {}
}

fn read(&mut self, addr: u8, buffer: &mut [u8]) -> Result<(), Self::Error> {
if let Some((last, buffer)) = buffer.split_last_mut() {
// Send a START condition and set ACK bit
self.regs
.cr1
.modify(|_, w| w.start().set_bit().ack().set_bit());

// Wait until START condition was generated
while self.regs.sr1.read().sb().bit_is_clear() {}

// Also wait until signalled we're master and everything is waiting for us
while {
let sr2 = self.regs.sr2.read();
sr2.msl().bit_is_clear() && sr2.busy().bit_is_clear()
} {}

// Set up current address, we're trying to talk to
self.regs
.dr
.write(|w| unsafe { w.bits((u32::from(addr) << 1) + 1) });

// Wait until address was sent
while {
self.check_and_clear_error_flags()?;
self.regs.sr1.read().addr().bit_is_clear()
} {}

// Clear condition by reading SR2
self.regs.sr2.read();

// Receive bytes into buffer
for c in buffer {
*c = self.recv_byte()?;
Operation::Read(buffer) => {
if let Some((last, buffer)) = buffer.split_last_mut() {
// Send a START condition and set ACK bit
self.regs
.cr1
.modify(|_, w| w.start().set_bit().ack().set_bit());

// Wait until START condition was generated
while self.regs.sr1.read().sb().bit_is_clear() {}

// Also wait until signalled we're master and everything is waiting for us
while {
let sr2 = self.regs.sr2.read();
sr2.msl().bit_is_clear() && sr2.busy().bit_is_clear()
} {}

// Set up current address, we're trying to talk to
self.regs
.dr
.write(|w| unsafe { w.bits((u32::from(address) << 1) + 1) });

// Wait until address was sent
while {
self.check_and_clear_error_flags()?;
self.regs.sr1.read().addr().bit_is_clear()
} {}

// Clear condition by reading SR2
self.regs.sr2.read();

// Receive bytes into buffer
for c in buffer {
*c = self.recv_byte()?;
}

// Prepare to send NACK then STOP after next byte
self.regs
.cr1
.modify(|_, w| w.ack().clear_bit().stop().set_bit());

// Receive last byte
*last = self.recv_byte()?;

// Wait for the STOP to be sent.
while self.regs.cr1.read().stop().bit_is_set() {}

} else {
return Err(Error::OVERRUN);
}
}
}

// Prepare to send NACK then STOP after next byte
self.regs
.cr1
.modify(|_, w| w.ack().clear_bit().stop().set_bit());

// Receive last byte
*last = self.recv_byte()?;

// Wait for the STOP to be sent.
while self.regs.cr1.read().stop().bit_is_set() {}

// Fallthrough is success
Ok(())
} else {
Err(Error::OVERRUN)
}

Ok(())
}
}
8 changes: 4 additions & 4 deletions src/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@ impl BaudPeriph for pac::USART3 {
}

cfg_if! {
if #[cfg(any(feature = "l4x6", feature = "h7"))] {
if #[cfg(any(feature = "l4x6", feature = "h7", feature = "f401", feature = "f407"))] {
impl BaudPeriph for pac::UART4 {
fn baud(clock_cfg: &Clocks) -> u32 {
clock_cfg.apb1()
Expand All @@ -182,7 +182,7 @@ cfg_if! {
}
}

#[cfg(any(feature = "h7", feature = "f401"))]
#[cfg(any(feature = "h7", feature = "f401", feature = "f407"))]
impl BaudPeriph for pac::USART6 {
fn baud(clock_cfg: &Clocks) -> u32 {
clock_cfg.apb2()
Expand Down Expand Up @@ -791,7 +791,7 @@ impl RccPeriph for pac::USART3 {
}

cfg_if! {
if #[cfg(any(feature = "l4x6", feature = "g473", feature = "g474", feature = "g483", feature = "g484", feature = "h7"))] {
if #[cfg(any(feature = "l4x6", feature = "g473", feature = "g474", feature = "g483", feature = "g484", feature = "h7", feature = "f401", feature = "f407"))] {
impl RccPeriph for pac::UART4 {
fn en_reset(rcc: &RegisterBlock) {
rcc_en_reset!(apb1, uart4, rcc);
Expand Down Expand Up @@ -844,7 +844,7 @@ cfg_if! {
}
}

#[cfg(any(feature = "h7", feature = "f401"))]
#[cfg(any(feature = "h7", feature = "f401", feature = "f407"))]
impl RccPeriph for pac::USART6 {
fn en_reset(rcc: &RegisterBlock) {
rcc_en_reset!(apb2, usart6, rcc);
Expand Down

0 comments on commit 1a2a01c

Please sign in to comment.