use core::cell::Cell;
use kernel::deferred_call::{DeferredCall, DeferredCallClient};
use kernel::hil;
use kernel::platform::chip::ClockInterface;
use kernel::utilities::cells::{OptionalCell, TakeCell};
use kernel::utilities::leasable_buffer::SubSliceMut;
use kernel::utilities::registers::interfaces::{ReadWriteable, Readable, Writeable};
use kernel::utilities::registers::{register_bitfields, ReadWrite};
use kernel::utilities::StaticRef;
use kernel::ErrorCode;
use crate::clocks::{phclk, Stm32f4Clocks};
use crate::dma;
#[repr(C)]
pub struct UsartRegisters {
sr: ReadWrite<u32, SR::Register>,
dr: ReadWrite<u32>,
brr: ReadWrite<u32, BRR::Register>,
cr1: ReadWrite<u32, CR1::Register>,
cr2: ReadWrite<u32, CR2::Register>,
cr3: ReadWrite<u32, CR3::Register>,
gtpr: ReadWrite<u32, GTPR::Register>,
}
register_bitfields![u32,
SR [
CTS OFFSET(9) NUMBITS(1) [],
LBD OFFSET(8) NUMBITS(1) [],
TXE OFFSET(7) NUMBITS(1) [],
TC OFFSET(6) NUMBITS(1) [],
RXNE OFFSET(5) NUMBITS(1) [],
IDLE OFFSET(4) NUMBITS(1) [],
ORE OFFSET(3) NUMBITS(1) [],
NF OFFSET(2) NUMBITS(1) [],
FE OFFSET(1) NUMBITS(1) [],
PE OFFSET(0) NUMBITS(1) []
],
BRR [
DIV_Mantissa OFFSET(4) NUMBITS(12) [],
DIV_Fraction OFFSET(0) NUMBITS(4) []
],
CR1 [
OVER8 OFFSET(15) NUMBITS(1) [],
UE OFFSET(13) NUMBITS(1) [],
M OFFSET(12) NUMBITS(1) [],
WAKE OFFSET(11) NUMBITS(1) [],
PCE OFFSET(10) NUMBITS(1) [],
PS OFFSET(9) NUMBITS(1) [],
PEIE OFFSET(8) NUMBITS(1) [],
TXEIE OFFSET(7) NUMBITS(1) [],
TCIE OFFSET(6) NUMBITS(1) [],
RXNEIE OFFSET(5) NUMBITS(1) [],
IDLEIE OFFSET(4) NUMBITS(1) [],
TE OFFSET(3) NUMBITS(1) [],
RE OFFSET(2) NUMBITS(1) [],
RWU OFFSET(1) NUMBITS(1) [],
SBK OFFSET(0) NUMBITS(1) []
],
CR2 [
LINEN OFFSET(14) NUMBITS(1) [],
STOP OFFSET(12) NUMBITS(2) [],
CLKEN OFFSET(11) NUMBITS(1) [],
CPOL OFFSET(10) NUMBITS(1) [],
CPHA OFFSET(9) NUMBITS(1) [],
LBCL OFFSET(8) NUMBITS(1) [],
LBDIE OFFSET(6) NUMBITS(1) [],
LBDL OFFSET(5) NUMBITS(1) [],
ADD OFFSET(0) NUMBITS(4) []
],
CR3 [
ONEBIT OFFSET(11) NUMBITS(1) [],
CTSIE OFFSET(10) NUMBITS(1) [],
CTSE OFFSET(9) NUMBITS(1) [],
RTSE OFFSET(8) NUMBITS(1) [],
DMAT OFFSET(7) NUMBITS(1) [],
DMAR OFFSET(6) NUMBITS(1) [],
SCEN OFFSET(5) NUMBITS(1) [],
NACK OFFSET(4) NUMBITS(1) [],
HDSEL OFFSET(3) NUMBITS(1) [],
IRLP OFFSET(2) NUMBITS(1) [],
IREN OFFSET(1) NUMBITS(1) [],
EIE OFFSET(0) NUMBITS(1) []
],
GTPR [
GT OFFSET(8) NUMBITS(8) [],
PSC OFFSET(0) NUMBITS(8) []
]
];
pub const USART1_BASE: StaticRef<UsartRegisters> =
unsafe { StaticRef::new(0x40011000 as *const UsartRegisters) };
pub const USART2_BASE: StaticRef<UsartRegisters> =
unsafe { StaticRef::new(0x40004400 as *const UsartRegisters) };
pub const USART3_BASE: StaticRef<UsartRegisters> =
unsafe { StaticRef::new(0x40004800 as *const UsartRegisters) };
pub(crate) fn get_address_dr(regs: StaticRef<UsartRegisters>) -> u32 {
core::ptr::addr_of!(regs.dr) as u32
}
#[allow(non_camel_case_types)]
#[derive(Copy, Clone, PartialEq)]
enum USARTStateRX {
Idle,
DMA_Receiving,
Aborted(Result<(), ErrorCode>, hil::uart::Error),
}
#[allow(non_camel_case_types)]
#[derive(Copy, Clone, PartialEq)]
enum USARTStateTX {
Idle,
DMA_Transmitting,
Aborted(Result<(), ErrorCode>),
Transfer_Completing, }
pub struct Usart<'a, DMA: dma::StreamServer<'a>> {
registers: StaticRef<UsartRegisters>,
clock: UsartClock<'a>,
tx_client: OptionalCell<&'a dyn hil::uart::TransmitClient>,
rx_client: OptionalCell<&'a dyn hil::uart::ReceiveClient>,
tx_dma: OptionalCell<&'a dma::Stream<'a, DMA>>,
tx_dma_pid: DMA::Peripheral,
rx_dma: OptionalCell<&'a dma::Stream<'a, DMA>>,
rx_dma_pid: DMA::Peripheral,
tx_len: Cell<usize>,
rx_len: Cell<usize>,
usart_tx_state: Cell<USARTStateTX>,
usart_rx_state: Cell<USARTStateRX>,
partial_tx_buffer: TakeCell<'static, [u8]>,
partial_tx_len: Cell<usize>,
partial_rx_buffer: TakeCell<'static, [u8]>,
partial_rx_len: Cell<usize>,
deferred_call: DeferredCall,
}
pub struct TxDMA<'a, DMA: dma::StreamServer<'a>>(pub &'a dma::Stream<'a, DMA>);
pub struct RxDMA<'a, DMA: dma::StreamServer<'a>>(pub &'a dma::Stream<'a, DMA>);
impl<'a> Usart<'a, dma::Dma1<'a>> {
pub fn new_usart2(clocks: &'a dyn Stm32f4Clocks) -> Self {
Self::new(
USART2_BASE,
UsartClock(phclk::PeripheralClock::new(
phclk::PeripheralClockType::APB1(phclk::PCLK1::USART2),
clocks,
)),
dma::Dma1Peripheral::USART2_TX,
dma::Dma1Peripheral::USART2_RX,
)
}
pub fn new_usart3(clocks: &'a dyn Stm32f4Clocks) -> Self {
Self::new(
USART3_BASE,
UsartClock(phclk::PeripheralClock::new(
phclk::PeripheralClockType::APB1(phclk::PCLK1::USART3),
clocks,
)),
dma::Dma1Peripheral::USART3_TX,
dma::Dma1Peripheral::USART3_RX,
)
}
}
impl<'a> Usart<'a, dma::Dma2<'a>> {
pub fn new_usart1(clocks: &'a dyn Stm32f4Clocks) -> Self {
Self::new(
USART1_BASE,
UsartClock(phclk::PeripheralClock::new(
phclk::PeripheralClockType::APB2(phclk::PCLK2::USART1),
clocks,
)),
dma::Dma2Peripheral::USART1_TX,
dma::Dma2Peripheral::USART1_RX,
)
}
}
impl<'a, DMA: dma::StreamServer<'a>> Usart<'a, DMA> {
fn new(
base_addr: StaticRef<UsartRegisters>,
clock: UsartClock<'a>,
tx_dma_pid: DMA::Peripheral,
rx_dma_pid: DMA::Peripheral,
) -> Usart<'a, DMA> {
Usart {
registers: base_addr,
clock,
tx_client: OptionalCell::empty(),
rx_client: OptionalCell::empty(),
tx_dma: OptionalCell::empty(),
tx_dma_pid,
rx_dma: OptionalCell::empty(),
rx_dma_pid,
tx_len: Cell::new(0),
rx_len: Cell::new(0),
usart_tx_state: Cell::new(USARTStateTX::Idle),
usart_rx_state: Cell::new(USARTStateRX::Idle),
partial_tx_buffer: TakeCell::empty(),
partial_tx_len: Cell::new(0),
partial_rx_buffer: TakeCell::empty(),
partial_rx_len: Cell::new(0),
deferred_call: DeferredCall::new(),
}
}
pub fn is_enabled_clock(&self) -> bool {
self.clock.is_enabled()
}
pub fn enable_clock(&self) {
self.clock.enable();
}
pub fn disable_clock(&self) {
self.clock.disable();
}
pub fn set_dma(&self, tx_dma: TxDMA<'a, DMA>, rx_dma: RxDMA<'a, DMA>) {
self.tx_dma.set(tx_dma.0);
self.rx_dma.set(rx_dma.0);
}
pub fn handle_interrupt(&self) {
if self.registers.sr.is_set(SR::TC) {
self.clear_transmit_complete();
self.disable_transmit_complete_interrupt();
if self.usart_tx_state.get() == USARTStateTX::Transfer_Completing {
self.disable_tx();
self.usart_tx_state.set(USARTStateTX::Idle);
let buffer = self.tx_dma.map_or(None, |tx_dma| tx_dma.return_buffer());
let len = self.tx_len.get();
self.tx_len.set(0);
self.tx_client.map(|client| {
buffer.map(|buf| {
let buf = buf.take();
client.transmitted_buffer(buf, len, Ok(()));
});
});
}
}
if self.is_enabled_error_interrupt() && self.registers.sr.is_set(SR::ORE) {
let _ = self.registers.dr.get(); if self.usart_rx_state.get() == USARTStateRX::DMA_Receiving {
self.usart_rx_state.set(USARTStateRX::Idle);
self.disable_rx();
self.disable_error_interrupt();
let (buffer, len) = self.rx_dma.map_or((None, 0), |rx_dma| {
rx_dma.abort_transfer()
});
let count = self.rx_len.get() - len as usize;
self.rx_len.set(0);
self.rx_client.map(|client| {
buffer.map(|buf| {
let buf = buf.take();
client.received_buffer(
buf,
count,
Err(ErrorCode::CANCEL),
hil::uart::Error::OverrunError,
);
})
});
}
}
}
pub fn send_byte(&self, byte: u8) {
while !self.registers.sr.is_set(SR::TXE) {}
self.registers.dr.set(byte.into());
}
fn enable_tx(&self) {
self.registers.cr3.modify(CR3::DMAT::SET);
}
fn disable_tx(&self) {
self.registers.cr3.modify(CR3::DMAT::CLEAR);
}
fn enable_rx(&self) {
self.registers.cr3.modify(CR3::DMAR::SET);
}
fn disable_rx(&self) {
self.registers.cr3.modify(CR3::DMAR::CLEAR);
}
fn enable_error_interrupt(&self) {
self.registers.cr3.modify(CR3::EIE::SET);
}
fn disable_error_interrupt(&self) {
self.registers.cr3.modify(CR3::EIE::CLEAR);
}
fn is_enabled_error_interrupt(&self) -> bool {
self.registers.cr3.is_set(CR3::EIE)
}
fn abort_tx(&self, rcode: Result<(), ErrorCode>) {
self.disable_tx();
let (mut buffer, len) = self.tx_dma.map_or((None, 0), |tx_dma| {
tx_dma.abort_transfer()
});
let count = self.tx_len.get() - len as usize;
self.tx_len.set(0);
if let Some(buf) = buffer.take() {
let buf = buf.take();
self.partial_tx_buffer.replace(buf);
self.partial_tx_len.set(count);
self.usart_tx_state.set(USARTStateTX::Aborted(rcode));
self.deferred_call.set();
} else {
self.usart_tx_state.set(USARTStateTX::Idle);
}
}
fn abort_rx(&self, rcode: Result<(), ErrorCode>, error: hil::uart::Error) {
self.disable_rx();
self.disable_error_interrupt();
let (mut buffer, len) = self.rx_dma.map_or((None, 0), |rx_dma| {
rx_dma.abort_transfer()
});
let count = self.rx_len.get() - len as usize;
self.rx_len.set(0);
if let Some(buf) = buffer.take() {
let buf = buf.take();
self.partial_rx_buffer.replace(buf);
self.partial_rx_len.set(count);
self.usart_rx_state.set(USARTStateRX::Aborted(rcode, error));
self.deferred_call.set();
} else {
self.usart_rx_state.set(USARTStateRX::Idle);
}
}
fn enable_transmit_complete_interrupt(&self) {
self.registers.cr1.modify(CR1::TCIE::SET);
}
fn disable_transmit_complete_interrupt(&self) {
self.registers.cr1.modify(CR1::TCIE::CLEAR);
}
fn clear_transmit_complete(&self) {
self.registers.sr.modify(SR::TC::CLEAR);
}
fn transfer_done(&self, pid: DMA::Peripheral) {
if pid == self.tx_dma_pid {
self.usart_tx_state.set(USARTStateTX::Transfer_Completing);
self.enable_transmit_complete_interrupt();
} else if pid == self.rx_dma_pid {
if self.usart_rx_state.get() == USARTStateRX::DMA_Receiving {
self.disable_rx();
self.disable_error_interrupt();
self.usart_rx_state.set(USARTStateRX::Idle);
let buffer = self.rx_dma.map_or(None, |rx_dma| rx_dma.return_buffer());
let length = self.rx_len.get();
self.rx_len.set(0);
self.rx_client.map(|client| {
buffer.map(|buf| {
let buf = buf.take();
client.received_buffer(buf, length, Ok(()), hil::uart::Error::None);
});
});
}
}
}
fn set_baud_rate(&self, baud_rate: u32) -> Result<(), ErrorCode> {
let pclk_freq = self.clock.0.get_frequency();
let (mantissa, fraction) = if (pclk_freq / 16) >= baud_rate {
let div = (pclk_freq + (baud_rate / 2)) / baud_rate;
self.registers.cr1.modify(CR1::OVER8::CLEAR);
(div >> 4, div & 0x0F)
} else if (pclk_freq / 8) >= baud_rate {
let div = ((pclk_freq * 2) + (baud_rate / 2)) / baud_rate;
self.registers.cr1.modify(CR1::OVER8::SET);
(div >> 4, (div & 0x0F) >> 1)
} else {
return Err(ErrorCode::INVAL);
};
self.registers.brr.modify(BRR::DIV_Mantissa.val(mantissa));
self.registers.brr.modify(BRR::DIV_Fraction.val(fraction));
Ok(())
}
}
impl<'a, DMA: dma::StreamServer<'a>> DeferredCallClient for Usart<'a, DMA> {
fn register(&'static self) {
self.deferred_call.register(self);
}
fn handle_deferred_call(&self) {
if let USARTStateTX::Aborted(rcode) = self.usart_tx_state.get() {
self.tx_client.map(|client| {
self.partial_tx_buffer.take().map(|buf| {
client.transmitted_buffer(buf, self.partial_tx_len.get(), rcode);
});
});
self.usart_tx_state.set(USARTStateTX::Idle);
}
if let USARTStateRX::Aborted(rcode, error) = self.usart_rx_state.get() {
self.rx_client.map(|client| {
self.partial_rx_buffer.take().map(|buf| {
client.received_buffer(buf, self.partial_rx_len.get(), rcode, error);
});
});
self.usart_rx_state.set(USARTStateRX::Idle);
}
}
}
impl<'a, DMA: dma::StreamServer<'a>> hil::uart::Transmit<'a> for Usart<'a, DMA> {
fn set_transmit_client(&self, client: &'a dyn hil::uart::TransmitClient) {
self.tx_client.set(client);
}
fn transmit_buffer(
&self,
tx_data: &'static mut [u8],
tx_len: usize,
) -> Result<(), (ErrorCode, &'static mut [u8])> {
if self.usart_tx_state.get() != USARTStateTX::Idle {
return Err((ErrorCode::BUSY, tx_data));
}
self.tx_dma.map(move |dma| {
self.tx_len.set(tx_len);
let mut tx_data: SubSliceMut<u8> = tx_data.into();
tx_data.slice(..tx_len);
dma.do_transfer(tx_data);
});
self.usart_tx_state.set(USARTStateTX::DMA_Transmitting);
self.enable_tx();
Ok(())
}
fn transmit_word(&self, _word: u32) -> Result<(), ErrorCode> {
Err(ErrorCode::FAIL)
}
fn transmit_abort(&self) -> Result<(), ErrorCode> {
if self.usart_tx_state.get() != USARTStateTX::Idle {
self.abort_tx(Err(ErrorCode::CANCEL));
Err(ErrorCode::BUSY)
} else {
Ok(())
}
}
}
impl<'a, DMA: dma::StreamServer<'a>> hil::uart::Configure for Usart<'a, DMA> {
fn configure(&self, params: hil::uart::Parameters) -> Result<(), ErrorCode> {
if params.stop_bits != hil::uart::StopBits::One
|| params.parity != hil::uart::Parity::None
|| params.hw_flow_control
|| params.width != hil::uart::Width::Eight
{
panic!("Currently we only support uart setting of 8N1, no hardware flow control");
}
self.registers.cr1.modify(CR1::M::CLEAR);
self.registers.cr2.modify(CR2::STOP.val(0b00_u32));
self.registers.cr1.modify(CR1::PCE::CLEAR);
self.set_baud_rate(params.baud_rate)?;
self.registers.cr1.modify(CR1::TE::SET);
self.registers.cr1.modify(CR1::RE::SET);
self.registers.cr1.modify(CR1::UE::SET);
Ok(())
}
}
impl<'a, DMA: dma::StreamServer<'a>> hil::uart::Receive<'a> for Usart<'a, DMA> {
fn set_receive_client(&self, client: &'a dyn hil::uart::ReceiveClient) {
self.rx_client.set(client);
}
fn receive_buffer(
&self,
rx_buffer: &'static mut [u8],
rx_len: usize,
) -> Result<(), (ErrorCode, &'static mut [u8])> {
if self.usart_rx_state.get() != USARTStateRX::Idle {
return Err((ErrorCode::BUSY, rx_buffer));
}
if rx_len > rx_buffer.len() {
return Err((ErrorCode::SIZE, rx_buffer));
}
self.rx_dma.map(move |dma| {
self.rx_len.set(rx_len);
let mut rx_buffer: SubSliceMut<u8> = rx_buffer.into();
rx_buffer.slice(..rx_len);
dma.do_transfer(rx_buffer);
});
self.usart_rx_state.set(USARTStateRX::DMA_Receiving);
self.enable_error_interrupt();
self.enable_rx();
Ok(())
}
fn receive_word(&self) -> Result<(), ErrorCode> {
Err(ErrorCode::FAIL)
}
fn receive_abort(&self) -> Result<(), ErrorCode> {
self.abort_rx(Err(ErrorCode::CANCEL), hil::uart::Error::Aborted);
Err(ErrorCode::BUSY)
}
}
impl<'a> dma::StreamClient<'a, dma::Dma1<'a>> for Usart<'a, dma::Dma1<'a>> {
fn transfer_done(&self, pid: dma::Dma1Peripheral) {
self.transfer_done(pid);
}
}
impl<'a> dma::StreamClient<'a, dma::Dma2<'a>> for Usart<'a, dma::Dma2<'a>> {
fn transfer_done(&self, pid: dma::Dma2Peripheral) {
self.transfer_done(pid);
}
}
struct UsartClock<'a>(phclk::PeripheralClock<'a>);
impl ClockInterface for UsartClock<'_> {
fn is_enabled(&self) -> bool {
self.0.is_enabled()
}
fn enable(&self) {
self.0.enable();
}
fn disable(&self) {
self.0.disable();
}
}