use core::marker::PhantomData;
use core::ops::Deref;
use crate::gpio::{Alternate, Pin};
use crate::pac;
use crate::rcu::{Clocks, Enable, Rcu, Reset};
use crate::time::Hertz;
const DATA_7BIT_MASK: u8 = 0x7F;
const DATA_9BIT_MASK: u32 = 0x1FF;
pub trait TxPin<USART> {}
pub trait RxPin<USART> {}
macro_rules! usart_pins {
( $( $USART:ty: TX: [ $($tx_p:literal $tx_n:literal : $tx_af:literal),* $(,)? ] RX: [ $($rx_p:literal $rx_n:literal : $rx_af:literal),* $(,)? ] ),* $(,)? ) => {
$(
$( impl TxPin<$USART> for Pin<$tx_p, $tx_n, Alternate<$tx_af>> {} )*
$( impl RxPin<$USART> for Pin<$rx_p, $rx_n, Alternate<$rx_af>> {} )*
)*
};
}
usart_pins! {
pac::Usart0:
TX: [ 'A' 9:1, 'B' 6:0 ]
RX: [ 'A' 10:1, 'B' 7:0 ],
}
#[cfg(feature = "gd32e230x4")]
usart_pins! {
pac::Usart0:
TX: [ 'A' 2:1, 'A' 14:1 ]
RX: [ 'A' 3:1, 'A' 15:1 ],
}
#[cfg(any(feature = "gd32e230x6", feature = "gd32e230x8"))]
usart_pins! {
pac::Usart1:
TX: [ 'A' 2:1, 'A' 8:4, 'A' 14:1 ]
RX: [ 'A' 3:1, 'A' 15:1, 'B' 0:4 ],
}
pub trait BusClocks {
fn clock(clocks: &Clocks) -> Hertz;
}
impl BusClocks for pac::Usart0 {
fn clock(clocks: &Clocks) -> Hertz {
clocks.usart0()
}
}
impl BusClocks for pac::Usart1 {
fn clock(clocks: &Clocks) -> Hertz {
clocks.pclk1()
}
}
#[allow(missing_docs)]
pub mod baud {
pub const B110: u32 = 110;
pub const B300: u32 = 300;
pub const B600: u32 = 600;
pub const B1200: u32 = 1_200;
pub const B2400: u32 = 2_400;
pub const B4800: u32 = 4_800;
pub const B9600: u32 = 9_600;
pub const B14400: u32 = 14_400;
pub const B19200: u32 = 19_200;
pub const B38400: u32 = 38_400;
pub const B57600: u32 = 57_600;
pub const B115200: u32 = 115_200;
pub const B230400: u32 = 230_400;
pub const B460800: u32 = 460_800;
pub const B921600: u32 = 921_600;
}
#[derive(Clone, Copy)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum Oversampling {
X8,
X16,
}
#[derive(Clone, Copy)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum FrameFormat {
N8,
E8,
O8,
E7,
O7,
}
pub struct UsartConfig {
baud: u32,
oversampling: Oversampling,
frame_format: FrameFormat,
}
impl UsartConfig {
pub fn baud(mut self, baud: u32) -> Self {
self.baud = baud;
self
}
pub fn oversampling(mut self, oversampling: Oversampling) -> Self {
self.oversampling = oversampling;
self
}
pub fn frame_format(mut self, frame_format: FrameFormat) -> Self {
self.frame_format = frame_format;
self
}
}
impl Default for UsartConfig {
fn default() -> Self {
Self {
baud: baud::B115200,
oversampling: Oversampling::X16,
frame_format: FrameFormat::N8,
}
}
}
pub struct UsartConfig9 {
baud: u32,
oversampling: Oversampling,
}
impl UsartConfig9 {
pub fn baud(mut self, baud: u32) -> Self {
self.baud = baud;
self
}
pub fn oversampling(mut self, oversampling: Oversampling) -> Self {
self.oversampling = oversampling;
self
}
}
impl Default for UsartConfig9 {
fn default() -> Self {
Self {
baud: baud::B115200,
oversampling: Oversampling::X16,
}
}
}
fn configure<USARTX>(
rcu: &mut Rcu,
usart: &USARTX,
clocks: &Clocks,
baud: u32,
oversampling: Oversampling,
) where
USARTX: Deref<Target = pac::usart0::RegisterBlock> + Enable + Reset + BusClocks,
{
USARTX::enable(rcu);
USARTX::reset(rcu);
let pclk = USARTX::clock(clocks).to_Hz();
let usartdiv = (pclk + baud / 2) / baud;
usart.baud().write(|w| unsafe {
match oversampling {
Oversampling::X16 => w.bits(usartdiv),
Oversampling::X8 => {
let intdiv = usartdiv / 8;
let fradiv_8 = usartdiv % 8;
w.bits((intdiv << 4) | (fradiv_8 & 0x7))
}
}
});
usart.ctl0().modify(|_, w| {
let w = w.ten().enabled().ren().enabled();
match oversampling {
Oversampling::X16 => w.ovsmod().oversampling16(),
Oversampling::X8 => w.ovsmod().oversampling8(),
}
});
}
pub struct Byte;
pub struct Word;
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[non_exhaustive]
pub enum Error {
Overrun,
Noise,
Framing,
Parity,
}
impl core::fmt::Display for Error {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self {
Self::Overrun => write!(f, "receive overrun, a frame was lost"),
Self::Noise => write!(f, "noise detected on the line"),
Self::Framing => write!(f, "framing error, no stop bit where expected"),
Self::Parity => write!(f, "parity check failed"),
}
}
}
impl core::error::Error for Error {}
impl embedded_io::Error for Error {
fn kind(&self) -> embedded_io::ErrorKind {
match self {
Self::Framing | Self::Noise | Self::Parity => embedded_io::ErrorKind::InvalidData,
Self::Overrun => embedded_io::ErrorKind::Other,
}
}
}
impl embedded_hal_nb::serial::Error for Error {
fn kind(&self) -> embedded_hal_nb::serial::ErrorKind {
match self {
Self::Overrun => embedded_hal_nb::serial::ErrorKind::Overrun,
Self::Noise => embedded_hal_nb::serial::ErrorKind::Noise,
Self::Framing => embedded_hal_nb::serial::ErrorKind::FrameFormat,
Self::Parity => embedded_hal_nb::serial::ErrorKind::Parity,
}
}
}
pub struct Usart<USARTX, TX, RX, WORD = Byte> {
usart: USARTX,
tx_pin: TX,
rx_pin: RX,
frame_format: FrameFormat,
_word: PhantomData<WORD>,
}
impl<USARTX, TX, RX, WORD> Usart<USARTX, TX, RX, WORD>
where
USARTX: Deref<Target = pac::usart0::RegisterBlock>,
{
fn take_error(&self) -> Option<Error> {
let stat = self.usart.stat().read();
let error = if stat.orerr().bit_is_set() {
self.usart.intc().write(|w| w.orec().clear());
Some(Error::Overrun)
} else if stat.nerr().bit_is_set() {
self.usart.intc().write(|w| w.nec().clear());
Some(Error::Noise)
} else if stat.ferr().bit_is_set() {
self.usart.intc().write(|w| w.fec().clear());
Some(Error::Framing)
} else if stat.perr().bit_is_set() {
self.usart.intc().write(|w| w.pec().clear());
Some(Error::Parity)
} else {
None
};
if error.is_some() {
self.usart.rdata().read();
}
error
}
fn rbne(&self) -> bool {
self.usart.stat().read().rbne().bit_is_set()
}
fn tbe(&self) -> bool {
self.usart.stat().read().tbe().bit_is_set()
}
fn wait_tc(&self) {
while self.usart.stat().read().tc().bit_is_clear() {}
}
pub fn read_ready(&self) -> bool {
self.rbne()
}
pub fn write_ready(&self) -> bool {
self.tbe()
}
pub fn flush(&self) {
self.wait_tc();
}
pub fn release(self) -> (USARTX, TX, RX) {
self.usart.ctl0().modify(|_, w| w.uen().disabled());
(self.usart, self.tx_pin, self.rx_pin)
}
}
impl<USARTX, TX, RX> Usart<USARTX, TX, RX, Byte>
where
USARTX: Deref<Target = pac::usart0::RegisterBlock>,
{
fn received_byte(&self) -> u8 {
let raw = self.usart.rdata().read().bits() as u8;
match self.frame_format {
FrameFormat::E7 | FrameFormat::O7 => raw & DATA_7BIT_MASK,
FrameFormat::N8 | FrameFormat::E8 | FrameFormat::O8 => raw,
}
}
pub fn write_byte(&self, byte: u8) {
while !self.tbe() {}
self.usart.tdata().write(|w| unsafe { w.bits(byte as u32) });
}
pub fn write_bytes(&self, buf: &[u8]) {
for &byte in buf {
self.write_byte(byte);
}
}
pub fn read_byte(&self) -> Result<u8, Error> {
while !self.rbne() {}
if let Some(e) = self.take_error() {
Err(e)
} else {
Ok(self.received_byte())
}
}
pub fn read_bytes(&self, buf: &mut [u8]) -> Result<usize, Error> {
if buf.is_empty() {
return Ok(0);
}
let mut index = 0;
while !self.rbne() {}
while index < buf.len() && self.rbne() {
buf[index] = self.read_byte()?;
index += 1;
}
Ok(index)
}
}
impl<USARTX, TX, RX> Usart<USARTX, TX, RX, Byte>
where
USARTX: Deref<Target = pac::usart0::RegisterBlock> + Enable + Reset + BusClocks,
TX: TxPin<USARTX>,
RX: RxPin<USARTX>,
{
pub fn new(
rcu: &mut Rcu,
usart: USARTX,
tx_pin: TX,
rx_pin: RX,
clocks: &Clocks,
config: UsartConfig,
) -> Self {
configure(rcu, &usart, &clocks, config.baud, config.oversampling);
usart.ctl0().modify(|_, w| match config.frame_format {
FrameFormat::N8 => w.pcen().disabled().wl().bit8(),
FrameFormat::E8 => w.pcen().enabled().pm().even().wl().bit9(),
FrameFormat::O8 => w.pcen().enabled().pm().odd().wl().bit9(),
FrameFormat::E7 => w.pcen().enabled().pm().even().wl().bit8(),
FrameFormat::O7 => w.pcen().enabled().pm().odd().wl().bit8(),
});
usart.ctl0().modify(|_, w| w.uen().enabled());
Self {
usart,
tx_pin,
rx_pin,
frame_format: config.frame_format,
_word: PhantomData,
}
}
}
impl<USARTX, TX, RX> Usart<USARTX, TX, RX, Word>
where
USARTX: Deref<Target = pac::usart0::RegisterBlock>,
{
pub fn write_word(&self, word: u16) {
while !self.tbe() {}
self.usart
.tdata()
.write(|w| unsafe { w.bits(word as u32 & DATA_9BIT_MASK) });
}
pub fn write_words(&self, buf: &[u16]) {
for &word in buf {
self.write_word(word);
}
}
pub fn read_word(&self) -> Result<u16, Error> {
while !self.rbne() {}
if let Some(e) = self.take_error() {
Err(e)
} else {
Ok((self.usart.rdata().read().bits() & DATA_9BIT_MASK) as u16)
}
}
pub fn read_words(&self, buf: &mut [u16]) -> Result<usize, Error> {
if buf.is_empty() {
return Ok(0);
}
let mut index = 0;
while !self.rbne() {}
while index < buf.len() && self.rbne() {
buf[index] = self.read_word()?;
index += 1;
}
Ok(index)
}
}
impl<USARTX, TX, RX> Usart<USARTX, TX, RX, Word>
where
USARTX: Deref<Target = pac::usart0::RegisterBlock> + Enable + Reset + BusClocks,
TX: TxPin<USARTX>,
RX: RxPin<USARTX>,
{
pub fn new_word(
rcu: &mut Rcu,
usart: USARTX,
tx_pin: TX,
rx_pin: RX,
clocks: &Clocks,
config: UsartConfig9,
) -> Self {
configure(rcu, &usart, &clocks, config.baud, config.oversampling);
usart.ctl0().modify(|_, w| w.pcen().disabled().wl().bit9());
usart.ctl0().modify(|_, w| w.uen().enabled());
Self {
usart,
tx_pin,
rx_pin,
frame_format: FrameFormat::N8,
_word: PhantomData,
}
}
}
impl<USARTX, TX, RX, WORD> embedded_hal_nb::serial::ErrorType for Usart<USARTX, TX, RX, WORD> {
type Error = Error;
}
impl<USARTX, TX, RX, WORD> embedded_io::ErrorType for Usart<USARTX, TX, RX, WORD> {
type Error = Error;
}
impl<USARTX, TX, RX> embedded_hal_nb::serial::Read<u8> for Usart<USARTX, TX, RX, Byte>
where
USARTX: Deref<Target = pac::usart0::RegisterBlock>,
{
fn read(&mut self) -> nb::Result<u8, Self::Error> {
if !self.rbne() {
return Err(nb::Error::WouldBlock);
}
if let Some(e) = self.take_error() {
Err(nb::Error::Other(e))
} else {
Ok(self.received_byte())
}
}
}
impl<USARTX, TX, RX> embedded_io::Read for Usart<USARTX, TX, RX, Byte>
where
USARTX: Deref<Target = pac::usart0::RegisterBlock>,
{
fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
self.read_bytes(buf)
}
}
impl<USARTX, TX, RX> embedded_hal_nb::serial::Write<u8> for Usart<USARTX, TX, RX, Byte>
where
USARTX: Deref<Target = pac::usart0::RegisterBlock>,
{
fn write(&mut self, byte: u8) -> nb::Result<(), Self::Error> {
if !self.tbe() {
Err(nb::Error::WouldBlock)
} else {
self.usart.tdata().write(|w| unsafe { w.bits(byte as u32) });
Ok(())
}
}
fn flush(&mut self) -> nb::Result<(), Self::Error> {
if self.usart.stat().read().tc().bit_is_clear() {
Err(nb::Error::WouldBlock)
} else {
Ok(())
}
}
}
impl<USARTX, TX, RX> embedded_io::Write for Usart<USARTX, TX, RX, Byte>
where
USARTX: Deref<Target = pac::usart0::RegisterBlock>,
{
fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
match buf.first() {
Some(&b) => {
self.write_byte(b);
Ok(1usize)
}
None => Ok(0usize),
}
}
fn flush(&mut self) -> Result<(), Self::Error> {
self.wait_tc();
Ok(())
}
}
impl<USARTX, TX, RX> embedded_io::ReadReady for Usart<USARTX, TX, RX, Byte>
where
USARTX: Deref<Target = pac::usart0::RegisterBlock>,
{
fn read_ready(&mut self) -> Result<bool, Self::Error> {
Ok(self.rbne())
}
}
impl<USARTX, TX, RX> embedded_io::WriteReady for Usart<USARTX, TX, RX, Byte>
where
USARTX: Deref<Target = pac::usart0::RegisterBlock>,
{
fn write_ready(&mut self) -> Result<bool, Self::Error> {
Ok(self.tbe())
}
}