#![macro_use]
use crate::pac;
use core::fmt::Write;
use pac::{GPIOA, RCU, USART0};
fn round(n: f32) -> f32 {
let int_part: i32 = n as i32; let fraction_part: f32 = n - int_part as f32;
if fraction_part >= 0.5 {
(int_part + 1) as f32
} else {
int_part as f32
}
}
fn init_usart() {
unsafe {
(*USART0::ptr()).ctl0.modify(|r, w| {
w.bits(r.bits()).uen().clear_bit() });
(*RCU::ptr()).apb2en.modify(|r, w| {
w.bits(r.bits())
.usart0en()
.set_bit()
.afen()
.set_bit()
.paen()
.set_bit()
});
(*GPIOA::ptr()).ctl1.modify(|r, w| {
w.bits(r.bits())
.md9()
.bits(0b11) .ctl9()
.bits(0b10) .md10()
.bits(0b00) .ctl10()
.bits(0b01) });
let _baud = 9600f32;
let clk_freq = 8_000_000f32;
let usart_div = clk_freq / (16f32 * 9600f32);
let mut int_div = usart_div as i32; let mut fra_div = round(16.0 * (usart_div - int_div as f32)) as i32;
if fra_div == 16 {
int_div += 1;
fra_div = 0;
}
(*USART0::ptr()).baud.modify(|r, w| {
w.bits(r.bits())
.intdiv()
.bits(int_div as u16)
.fradiv()
.bits(fra_div as u8)
});
(*USART0::ptr()).ctl2.modify(|r, w| {
w.bits(r.bits())
.ctsen()
.clear_bit() .rtsen()
.clear_bit() });
(*USART0::ptr()).ctl1.modify(|r, w| {
w.bits(r.bits())
.stb()
.bits(0b00) .cken()
.clear_bit()
});
(*USART0::ptr()).ctl0.modify(|r, w| {
w.bits(r.bits())
.wl()
.clear_bit() .ten()
.set_bit() .ren()
.set_bit() .pcen()
.clear_bit() .pm()
.clear_bit() .uen()
.set_bit() });
}
}
#[doc(hidden)] pub struct SerialWrapper;
impl core::fmt::Write for SerialWrapper {
fn write_str(&mut self, s: &str) -> core::fmt::Result {
for &byte in s.as_bytes() {
unsafe {
(*USART0::ptr()).data.write(|w| w.data().bits(byte.into()));
while (*USART0::ptr()).stat.read().tbe().bit_is_clear() {}
}
}
Ok(())
}
}
static mut STDOUT: Option<SerialWrapper> = None;
#[allow(unused_variables)]
#[doc(hidden)] pub fn init_stdout(uart: USART0) {
init_usart();
unsafe {
STDOUT.replace(SerialWrapper {});
}
}
#[doc(hidden)] pub fn write_str(s: &str) {
unsafe {
if let Some(stdout) = STDOUT.as_mut() {
let _ = stdout.write_str(s);
} else {
panic!("couldn't get stdout!");
}
}
}
#[doc(hidden)] pub fn write_fmt(args: core::fmt::Arguments) {
unsafe {
if let Some(stdout) = STDOUT.as_mut() {
let _ = stdout.write_fmt(args);
} else {
panic!("couldn't get stdout!");
}
}
}
#[doc(hidden)] #[macro_export]
macro_rules! sprint {
($s:expr) => {
crate::serial::write_str($s)
};
($($tt:tt)*) => {
crate::serial::write_fmt(format_args!($($tt)*))
};
}
use crate::afio::PCF0;
use crate::gpio::gpioa::{PA10, PA11, PA12, PA8, PA9};
use crate::gpio::{Alternate, Floating, Input, PushPull};
use crate::rcu::{Clocks, APB2};
use crate::unit::{Bps, U32Ext};
pub struct Config {
pub baudrate: Bps,
pub parity: Parity,
pub stop_bits: StopBits,
}
impl Default for Config {
fn default() -> Self {
Config {
baudrate: 115200u32.bps(),
parity: Parity::ParityNone,
stop_bits: StopBits::STOP1,
}
}
}
impl Config {
pub fn baudrate(mut self, baudrate: Bps) -> Config {
self.baudrate = baudrate;
self
}
pub fn parity(mut self, parity: Parity) -> Config {
self.parity = parity;
self
}
pub fn stop_bits(mut self, stop_bits: StopBits) -> Config {
self.stop_bits = stop_bits;
self
}
}
pub enum Parity {
ParityNone,
ParityEven,
ParityOdd,
}
impl Parity {
#[inline]
fn config(&self) -> (bool, bool, bool) {
match *self {
Parity::ParityNone => (false, false, false),
Parity::ParityEven => (true, true, false),
Parity::ParityOdd => (true, true, true),
}
}
}
pub enum StopBits {
STOP1,
STOP0P5,
STOP2,
STOP1P5,
}
impl StopBits {
#[inline]
fn config(&self) -> u8 {
match *self {
StopBits::STOP1 => 0b00,
StopBits::STOP0P5 => 0b01,
StopBits::STOP2 => 0b10,
StopBits::STOP1P5 => 0b11,
}
}
}
pub struct Serial<USART, PINS> {
usart: USART,
pins: PINS,
}
impl<PINS> Serial<USART0, PINS> {
pub fn usart0(
usart0: USART0,
pins: PINS,
pcf0: &mut PCF0,
config: Config,
clocks: Clocks,
apb2: &mut APB2,
) -> Self
where
PINS: Bundle<USART0>,
{
let baud_div = {
let baud_div = (clocks.ck_apb2().0 + config.baudrate.0 / 2) / config.baudrate.0;
assert!(baud_div >= 0x0010 && baud_div <= 0xFFFF, "impossible baudrate");
baud_div
};
let (wl, pcen, pm) = config.parity.config();
let stb = config.stop_bits.config();
riscv::interrupt::free(|_| {
apb2.en().modify(|_, w| w.usart0en().set_bit());
apb2.rst().modify(|_, w| w.usart0rst().set_bit());
apb2.rst().modify(|_, w| w.usart0rst().clear_bit());
pcf0.pcf0()
.modify(|_, w| w.usart0_remap().bit(PINS::REMAP == 1));
usart0
.baud
.write(|w| unsafe { w.bits(baud_div) });
usart0.ctl1.modify(|_, w| unsafe { w.stb().bits(stb) });
usart0.ctl0.modify(|_, w| {
w.wl().bit(wl).pcen().bit(pcen).pm().bit(pm);
w.uen().set_bit().ren().set_bit().ten().set_bit()
});
});
Serial {
usart: usart0,
pins,
}
}
pub fn release(self, apb2: &mut APB2) -> (USART0, PINS) {
self.usart
.ctl0
.modify(|_, w| w.uen().clear_bit().ren().clear_bit().ten().clear_bit());
apb2.en().modify(|_, w| w.usart0en().clear_bit());
(self.usart, self.pins)
}
}
#[derive(Debug)]
pub enum Error {
Overrun,
Noise,
Framing,
Parity,
}
impl<PINS> embedded_hal::serial::Read<u8> for Serial<USART0, PINS> {
type Error = Error;
fn try_read(&mut self) -> nb::Result<u8, Self::Error> {
let stat = self.usart.stat.read();
let err = if stat.orerr().bit_is_set() {
Some(Error::Overrun)
} else if stat.nerr().bit_is_set() {
Some(Error::Noise)
} else if stat.ferr().bit_is_set() {
Some(Error::Framing)
} else if stat.perr().bit_is_set() {
Some(Error::Parity)
} else {
None
};
if let Some(err) = err {
unsafe {
core::ptr::read_volatile(&self.usart.stat as *const _ as *const _);
core::ptr::read_volatile(&self.usart.data as *const _ as *const _);
}
Err(nb::Error::Other(err))
} else {
if stat.rbne().bit_is_set() {
Ok(unsafe { core::ptr::read_volatile(&self.usart.data as *const _ as *const _) })
} else {
Err(nb::Error::WouldBlock)
}
}
}
}
impl<PINS> embedded_hal::serial::Write<u8> for Serial<USART0, PINS> {
type Error = core::convert::Infallible;
fn try_write(&mut self, byte: u8) -> nb::Result<(), Self::Error> {
let stat = self.usart.stat.read();
if stat.tbe().bit_is_set() {
unsafe {
core::ptr::write_volatile(&self.usart.data as *const _ as *mut _, byte)
}
Ok(())
} else {
Err(nb::Error::WouldBlock)
}
}
fn try_flush(&mut self) -> nb::Result<(), Self::Error> {
if self.usart.stat.read().tc().bit_is_set() {
Ok(())
} else {
Err(nb::Error::WouldBlock)
}
}
}
impl<PINS> core::fmt::Write for Serial<USART0, PINS> {
fn write_str(&mut self, s: &str) -> core::fmt::Result {
use embedded_hal::serial::Write;
s.as_bytes()
.iter()
.try_for_each(|c| nb::block!(self.try_write(*c)))
.map_err(|_| core::fmt::Error) }
}
pub trait Pins {
#[doc(hidden)]
const REMAP: u8;
type TX;
type RX;
type RTS;
type CTS;
type CK;
}
impl Pins for USART0 {
const REMAP: u8 = 0;
type TX = PA9<Alternate<PushPull>>;
type RX = PA10<Input<Floating>>;
type RTS = PA12<Alternate<PushPull>>;
type CTS = PA11<Alternate<PushPull>>;
type CK = PA8<Alternate<PushPull>>;
}
pub trait Bundle<USART: Pins> {
#[doc(hidden)]
const REMAP: u8 = USART::REMAP;
#[doc(hidden)]
fn enable_ctl0();
#[doc(hidden)]
fn enable_ctl2();
}
impl<USART: Pins> Bundle<USART> for (USART::TX, USART::RX) {
#[inline]
fn enable_ctl0() {
}
#[inline]
fn enable_ctl2() {
}
}
impl<USART: Pins> Bundle<USART> for (USART::TX, USART::RX, USART::RTS, USART::CTS) {
#[inline]
fn enable_ctl0() {
}
#[inline]
fn enable_ctl2() {
}
}