Skip to content

Commit 6c995d6

Browse files
authored
Merge pull request #780 from stm32-rs/serial-clean
calculate_brr helper
2 parents 6889afd + 8e35364 commit 6c995d6

File tree

2 files changed

+71
-118
lines changed

2 files changed

+71
-118
lines changed

src/serial/uart_impls.rs

Lines changed: 70 additions & 117 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,10 @@ pub trait RegisterBlockImpl: crate::Sealed {
145145

146146
// PeriAddress
147147
fn peri_address(&self) -> u32;
148+
149+
fn enable_dma(&self, dc: config::DmaConfig);
150+
151+
fn calculate_brr(pclk_freq: u32, baud: u32) -> Result<(bool, u32), config::InvalidConfig>;
148152
}
149153

150154
macro_rules! uartCommon {
@@ -259,6 +263,67 @@ macro_rules! uartCommon {
259263
fn peri_address(&self) -> u32 {
260264
self.dr().as_ptr() as u32
261265
}
266+
267+
fn enable_dma(&self, dc: config::DmaConfig) {
268+
use config::DmaConfig;
269+
match dc {
270+
DmaConfig::Tx => self.cr3().write(|w| w.dmat().enabled()),
271+
DmaConfig::Rx => self.cr3().write(|w| w.dmar().enabled()),
272+
DmaConfig::TxRx => self.cr3().write(|w| w.dmar().enabled().dmat().enabled()),
273+
DmaConfig::None => {}
274+
}
275+
}
276+
277+
fn calculate_brr(pclk_freq: u32, baud: u32) -> Result<(bool, u32), config::InvalidConfig> {
278+
// The frequency to calculate USARTDIV is this:
279+
//
280+
// (Taken from STM32F411xC/E Reference Manual,
281+
// Section 19.3.4, Equation 1)
282+
//
283+
// 16 bit oversample: OVER8 = 0
284+
// 8 bit oversample: OVER8 = 1
285+
//
286+
// USARTDIV = (pclk)
287+
// ------------------------
288+
// 8 x (2 - OVER8) x (baud)
289+
//
290+
// BUT, the USARTDIV has 4 "fractional" bits, which effectively
291+
// means that we need to "correct" the equation as follows:
292+
//
293+
// USARTDIV = (pclk) * 16
294+
// ------------------------
295+
// 8 x (2 - OVER8) x (baud)
296+
//
297+
// When OVER8 is enabled, we can only use the lowest three
298+
// fractional bits, so we'll need to shift those last four bits
299+
// right one bit
300+
301+
// Calculate correct baudrate divisor on the fly
302+
if (pclk_freq / 16) >= baud {
303+
// We have the ability to oversample to 16 bits, take
304+
// advantage of it.
305+
//
306+
// We also add `baud / 2` to the `pclk_freq` to ensure
307+
// rounding of values to the closest scale, rather than the
308+
// floored behavior of normal integer division.
309+
let div = (pclk_freq + (baud / 2)) / baud;
310+
Ok((false, div))
311+
} else if (pclk_freq / 8) >= baud {
312+
// We are close enough to pclk where we can only
313+
// oversample 8.
314+
//
315+
// See note above regarding `baud` and rounding.
316+
let div = ((pclk_freq * 2) + (baud / 2)) / baud;
317+
318+
// Ensure the the fractional bits (only 3) are
319+
// right-aligned.
320+
let frac = div & 0xF;
321+
let div = (div & !0xF) | (frac >> 1);
322+
Ok((true, div))
323+
} else {
324+
Err(config::InvalidConfig)
325+
}
326+
}
262327
};
263328
}
264329

@@ -282,66 +347,11 @@ where {
282347
let pclk_freq = UART::clock(clocks).raw();
283348
let baud = config.baudrate.0;
284349

285-
// The frequency to calculate USARTDIV is this:
286-
//
287-
// (Taken from STM32F411xC/E Reference Manual,
288-
// Section 19.3.4, Equation 1)
289-
//
290-
// 16 bit oversample: OVER8 = 0
291-
// 8 bit oversample: OVER8 = 1
292-
//
293-
// USARTDIV = (pclk)
294-
// ------------------------
295-
// 8 x (2 - OVER8) x (baud)
296-
//
297-
// BUT, the USARTDIV has 4 "fractional" bits, which effectively
298-
// means that we need to "correct" the equation as follows:
299-
//
300-
// USARTDIV = (pclk) * 16
301-
// ------------------------
302-
// 8 x (2 - OVER8) x (baud)
303-
//
304-
// When OVER8 is enabled, we can only use the lowest three
305-
// fractional bits, so we'll need to shift those last four bits
306-
// right one bit
307-
//
308-
// In IrDA Smartcard, LIN, and IrDA modes, OVER8 is always disabled.
309-
//
310-
// (Taken from STM32F411xC/E Reference Manual,
311-
// Section 19.3.4, Equation 2)
312-
//
313-
// USARTDIV = pclk
314-
// ---------
315-
// 16 x baud
316-
//
317-
// With reference to the above, OVER8 == 0 when in Smartcard, LIN, and
318-
// IrDA modes, so the register value needed for USARTDIV is the same
319-
// as for 16 bit oversampling.
320-
321-
// Calculate correct baudrate divisor on the fly
322-
let (over8, div) = if (pclk_freq / 16) >= baud || config.irda != IrdaMode::None {
323-
// We have the ability to oversample to 16 bits, take
324-
// advantage of it.
325-
//
326-
// We also add `baud / 2` to the `pclk_freq` to ensure
327-
// rounding of values to the closest scale, rather than the
328-
// floored behavior of normal integer division.
350+
let (over8, div) = if config.irda != IrdaMode::None {
329351
let div = (pclk_freq + (baud / 2)) / baud;
330352
(false, div)
331-
} else if (pclk_freq / 8) >= baud {
332-
// We are close enough to pclk where we can only
333-
// oversample 8.
334-
//
335-
// See note above regarding `baud` and rounding.
336-
let div = ((pclk_freq * 2) + (baud / 2)) / baud;
337-
338-
// Ensure the the fractional bits (only 3) are
339-
// right-aligned.
340-
let frac = div & 0xF;
341-
let div = (div & !0xF) | (frac >> 1);
342-
(true, div)
343353
} else {
344-
return Err(config::InvalidConfig);
354+
Self::calculate_brr(pclk_freq, baud)?
345355
};
346356

347357
uart.brr().write(|w| unsafe { w.bits(div) });
@@ -384,12 +394,7 @@ where {
384394
w.ps().bit(config.parity == Parity::ParityOdd)
385395
});
386396

387-
match config.dma {
388-
DmaConfig::Tx => uart.cr3().write(|w| w.dmat().enabled()),
389-
DmaConfig::Rx => uart.cr3().write(|w| w.dmar().enabled()),
390-
DmaConfig::TxRx => uart.cr3().write(|w| w.dmar().enabled().dmat().enabled()),
391-
DmaConfig::None => {}
392-
}
397+
uart.enable_dma(config.dma);
393398

394399
let serial = Serial {
395400
tx: Tx::new(uart, pins.0.into()),
@@ -423,54 +428,7 @@ where {
423428
let pclk_freq = UART::clock(clocks).raw();
424429
let baud = config.baudrate.0;
425430

426-
// The frequency to calculate USARTDIV is this:
427-
//
428-
// (Taken from STM32F411xC/E Reference Manual,
429-
// Section 19.3.4, Equation 1)
430-
//
431-
// 16 bit oversample: OVER8 = 0
432-
// 8 bit oversample: OVER8 = 1
433-
//
434-
// USARTDIV = (pclk)
435-
// ------------------------
436-
// 8 x (2 - OVER8) x (baud)
437-
//
438-
// BUT, the USARTDIV has 4 "fractional" bits, which effectively
439-
// means that we need to "correct" the equation as follows:
440-
//
441-
// USARTDIV = (pclk) * 16
442-
// ------------------------
443-
// 8 x (2 - OVER8) x (baud)
444-
//
445-
// When OVER8 is enabled, we can only use the lowest three
446-
// fractional bits, so we'll need to shift those last four bits
447-
// right one bit
448-
449-
// Calculate correct baudrate divisor on the fly
450-
let (over8, div) = if (pclk_freq / 16) >= baud {
451-
// We have the ability to oversample to 16 bits, take
452-
// advantage of it.
453-
//
454-
// We also add `baud / 2` to the `pclk_freq` to ensure
455-
// rounding of values to the closest scale, rather than the
456-
// floored behavior of normal integer division.
457-
let div = (pclk_freq + (baud / 2)) / baud;
458-
(false, div)
459-
} else if (pclk_freq / 8) >= baud {
460-
// We are close enough to pclk where we can only
461-
// oversample 8.
462-
//
463-
// See note above regarding `baud` and rounding.
464-
let div = ((pclk_freq * 2) + (baud / 2)) / baud;
465-
466-
// Ensure the the fractional bits (only 3) are
467-
// right-aligned.
468-
let frac = div & 0xF;
469-
let div = (div & !0xF) | (frac >> 1);
470-
(true, div)
471-
} else {
472-
return Err(config::InvalidConfig);
473-
};
431+
let (over8, div) = Self::calculate_brr(pclk_freq, baud)?;
474432

475433
uart.brr().write(|w| unsafe { w.bits(div) });
476434

@@ -491,12 +449,7 @@ where {
491449
w.ps().bit(config.parity == Parity::ParityOdd)
492450
});
493451

494-
match config.dma {
495-
DmaConfig::Tx => uart.cr3().write(|w| w.dmat().enabled()),
496-
DmaConfig::Rx => uart.cr3().write(|w| w.dmar().enabled()),
497-
DmaConfig::TxRx => uart.cr3().write(|w| w.dmar().enabled().dmat().enabled()),
498-
DmaConfig::None => {}
499-
}
452+
uart.enable_dma(config.dma);
500453

501454
let serial = Serial {
502455
tx: Tx::new(uart, pins.0.into()),

src/spi.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ pub enum CFlag {
121121
/// Normal mode - RX and TX pins are independent
122122
#[allow(non_upper_case_globals)]
123123
pub const TransferModeNormal: bool = false;
124-
/// BIDI mode - use TX pin as RX then spi receive data
124+
/// Bidirectional (Half-Duplex) mode - use TX pin as RX then spi receive data
125125
#[allow(non_upper_case_globals)]
126126
pub const TransferModeBidi: bool = true;
127127

0 commit comments

Comments
 (0)