-
Notifications
You must be signed in to change notification settings - Fork 182
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add more configuration options to UART #63
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
//! Serial interface loopback test | ||
//! | ||
//! You have to short the TX and RX pins to make this program work | ||
|
||
#![deny(unsafe_code)] | ||
#![no_main] | ||
#![no_std] | ||
|
||
use panic_halt as _; | ||
|
||
use cortex_m::asm; | ||
|
||
use nb::block; | ||
|
||
use stm32f1xx_hal::{ | ||
prelude::*, | ||
pac, | ||
serial::{self, Serial}, | ||
timer::Timer, | ||
}; | ||
use cortex_m_rt::entry; | ||
|
||
#[entry] | ||
fn main() -> ! { | ||
// Get access to the device specific peripherals from the peripheral access crate | ||
let p = pac::Peripherals::take().unwrap(); | ||
|
||
// Take ownership over the raw flash and rcc devices and convert them into the corresponding | ||
// HAL structs | ||
let mut flash = p.FLASH.constrain(); | ||
let mut rcc = p.RCC.constrain(); | ||
|
||
// Freeze the configuration of all the clocks in the system and store the frozen frequencies in | ||
// `clocks` | ||
let clocks = rcc.cfgr.freeze(&mut flash.acr); | ||
|
||
// Prepare the alternate function I/O registers | ||
let mut afio = p.AFIO.constrain(&mut rcc.apb2); | ||
|
||
// Prepare the GPIOB peripheral | ||
let mut gpiob = p.GPIOB.split(&mut rcc.apb2); | ||
|
||
// USART1 | ||
// let tx = gpioa.pa9.into_alternate_push_pull(&mut gpioa.crh); | ||
// let rx = gpioa.pa10; | ||
|
||
// USART1 | ||
// let tx = gpiob.pb6.into_alternate_push_pull(&mut gpiob.crl); | ||
// let rx = gpiob.pb7; | ||
|
||
// USART2 | ||
// let tx = gpioa.pa2.into_alternate_push_pull(&mut gpioa.crl); | ||
// let rx = gpioa.pa3; | ||
|
||
// USART3 | ||
// Configure pb10 as a push_pull output, this will be the tx pin | ||
let tx = gpiob.pb10.into_alternate_push_pull(&mut gpiob.crh); | ||
// Take ownership over pb11 | ||
let rx = gpiob.pb11; | ||
|
||
// Set up the usart device. Taks ownership over the USART register and tx/rx pins. The rest of | ||
// the registers are used to enable and configure the device. | ||
let serial = Serial::usart3( | ||
p.USART3, | ||
(tx, rx), | ||
&mut afio.mapr, | ||
serial::Config::default() | ||
.baudrate(9600.bps()) | ||
.stopbits(serial::StopBits::STOP2) | ||
.parity_odd(), | ||
clocks, | ||
&mut rcc.apb1, | ||
); | ||
|
||
// Split the serial struct into a receiving and a transmitting part | ||
let (mut tx, mut rx) = serial.split(); | ||
|
||
let mut timer = Timer::tim2(p.TIM2, 1000.hz(), clocks, &mut rcc.apb1); | ||
|
||
let sent = b'U'; | ||
block!(tx.write(sent)).ok(); | ||
// block!(timer.wait()); | ||
// timer.start(1000.hz()); | ||
// block!(timer.wait()); | ||
block!(tx.write(sent)).ok(); | ||
|
||
|
||
loop {} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -50,7 +50,7 @@ use crate::gpio::gpioa::{PA10, PA2, PA3, PA9}; | |
use crate::gpio::gpiob::{PB10, PB11, PB6, PB7}; | ||
use crate::gpio::{Alternate, Floating, Input, PushPull}; | ||
use crate::rcc::{Clocks, APB1, APB2}; | ||
use crate::time::Bps; | ||
use crate::time::{U32Ext, Bps}; | ||
|
||
/// Interrupt event | ||
pub enum Event { | ||
|
@@ -107,6 +107,67 @@ impl Pins<USART3> for (PB10<Alternate<PushPull>>, PB11<Input<Floating>>) { | |
// const REMAP: u8 = 0b11; | ||
// } | ||
|
||
pub enum Parity { | ||
ParityNone, | ||
ParityEven, | ||
ParityOdd, | ||
} | ||
|
||
pub enum StopBits { | ||
#[doc = "1 stop bit"] | ||
STOP1, | ||
#[doc = "0.5 stop bits"] | ||
STOP0P5, | ||
#[doc = "2 stop bits"] | ||
STOP2, | ||
#[doc = "1.5 stop bits"] | ||
STOP1P5, | ||
} | ||
|
||
pub struct Config { | ||
pub baudrate: Bps, | ||
pub parity: Parity, | ||
pub stopbits: StopBits, | ||
} | ||
|
||
impl Config { | ||
pub fn baudrate(mut self, baudrate: Bps) -> Self { | ||
self.baudrate = baudrate; | ||
self | ||
} | ||
|
||
pub fn parity_none(mut self) -> Self { | ||
self.parity = Parity::ParityNone; | ||
self | ||
} | ||
|
||
pub fn parity_even(mut self) -> Self { | ||
self.parity = Parity::ParityEven; | ||
self | ||
} | ||
|
||
pub fn parity_odd(mut self) -> Self { | ||
self.parity = Parity::ParityOdd; | ||
self | ||
} | ||
|
||
pub fn stopbits(mut self, stopbits: StopBits) -> Self { | ||
self.stopbits = stopbits; | ||
self | ||
} | ||
} | ||
|
||
impl Default for Config { | ||
fn default() -> Config { | ||
let baudrate = 19_200_u32.bps(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 19200 baud is kind of an odd choice, I haven't seen that in common use since the age of the acoustic coupler. Maybe either use 9600 or 115200 baud instead which are the two common default baud rates used nowadays (with a slight preference for the latter). There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You're absolutely right, I have no idea what made me chose 19200. 115200 makes sense to me. |
||
Config { | ||
baudrate, | ||
parity: Parity::ParityNone, | ||
stopbits: StopBits::STOP1, | ||
} | ||
} | ||
} | ||
|
||
/// Serial abstraction | ||
pub struct Serial<USART, PINS> { | ||
usart: USART, | ||
|
@@ -162,7 +223,7 @@ macro_rules! hal { | |
usart: $USARTX, | ||
pins: PINS, | ||
mapr: &mut MAPR, | ||
baud_rate: Bps, | ||
config: Config, | ||
clocks: Clocks, | ||
apb: &mut $APB, | ||
) -> Self | ||
|
@@ -183,16 +244,45 @@ macro_rules! hal { | |
// enable DMA transfers | ||
usart.cr3.write(|w| w.dmat().set_bit().dmar().set_bit()); | ||
|
||
let brr = clocks.$pclk().0 / baud_rate.0; | ||
// Configure baud rate | ||
let brr = clocks.$pclk().0 / config.baudrate.0; | ||
assert!(brr >= 16, "impossible baud rate"); | ||
usart.brr.write(|w| unsafe { w.bits(brr) }); | ||
|
||
// Configure parity and word length | ||
// Unlike most uart devices, the "word length" of this usart device refers to | ||
// the size of the data plus the parity bit. I.e. "word length"=8, parity=even | ||
// results in 7 bits of data. Therefore, in order to get 8 bits and one parity | ||
// bit, we need to set the "word" length to 9 when using parity bits. | ||
let (word_length, parity_control_enable, parity) = match config.parity { | ||
Parity::ParityNone => (false, false, false), | ||
Parity::ParityEven => (true, true, false), | ||
Parity::ParityOdd => (true, true, true), | ||
}; | ||
usart.cr1.modify(|_r, w| { | ||
w | ||
.m().bit(word_length) | ||
.ps().bit(parity) | ||
.pce().bit(parity_control_enable) | ||
}); | ||
|
||
// Configure stop bits | ||
let stop_bits = match config.stopbits { | ||
StopBits::STOP1 => 0b00, | ||
StopBits::STOP0P5 => 0b01, | ||
StopBits::STOP2 => 0b10, | ||
StopBits::STOP1P5 => 0b11, | ||
}; | ||
usart.cr2.modify(|_r, w| { | ||
w.stop().bits(stop_bits) | ||
}); | ||
|
||
// UE: enable USART | ||
// RE: enable receiver | ||
// TE: enable transceiver | ||
usart | ||
.cr1 | ||
.write(|w| w.ue().set_bit().re().set_bit().te().set_bit()); | ||
.modify(|_r, w| w.ue().set_bit().re().set_bit().te().set_bit()); | ||
|
||
Serial { usart, pins } | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What's the purpose of these commented out lines?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also if we're not going to use the timer, why initialise it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good catch, I'll remove the comments and timer