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::registers::interfaces::{ReadWriteable, Readable, Writeable};
use kernel::utilities::registers::{register_bitfields, ReadOnly, ReadWrite};
use kernel::utilities::StaticRef;
use kernel::ErrorCode;
use crate::rcc;
#[repr(C)]
struct UsartRegisters {
cr1: ReadWrite<u32, CR1::Register>,
cr2: ReadWrite<u32, CR2::Register>,
cr3: ReadWrite<u32, CR3::Register>,
brr: ReadWrite<u32, BRR::Register>,
gtpr: ReadWrite<u32, GTPR::Register>,
rtor: ReadWrite<u32, RTOR::Register>,
rqr: ReadWrite<u32, RTOR::Register>,
isr: ReadWrite<u32, ISR::Register>,
icr: ReadWrite<u32, ICR::Register>,
rdr: ReadOnly<u32>,
tdr: ReadWrite<u32>,
}
register_bitfields![u32,
CR1 [
M1 OFFSET(28) NUMBITS(1) [],
EOBIE OFFSET(15) NUMBITS(1) [],
RTOIE OFFSET(26) NUMBITS(1) [],
DEAT OFFSET(21) NUMBITS(5) [],
DEDT OFFSET(16) NUMBITS(5) [],
OVER8 OFFSET(15) NUMBITS(1) [],
CMIE OFFSET(14) NUMBITS(1) [],
MME OFFSET(13) NUMBITS(1) [],
M0 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) [],
UESM OFFSET(1) NUMBITS(1) [],
UE OFFSET(0) NUMBITS(1) []
],
CR2 [
ADD1 OFFSET(28) NUMBITS(1) [],
ADD0 OFFSET(24) NUMBITS(4) [],
RTOEN OFFSET(23) NUMBITS(1) [],
ABRMOD OFFSET(21) NUMBITS(2) [],
ABREN OFFSET(20) NUMBITS(1) [],
MSBFIRST OFFSET(19) NUMBITS(1) [],
DATAINV OFFSET(18) NUMBITS(1) [],
TXINV OFFSET(17) NUMBITS(1) [],
RXINV OFFSET(16) NUMBITS(1) [],
SWAP OFFSET(15) NUMBITS(1) [],
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) [],
ADDM7 OFFSET(4) NUMBITS(1) []
],
CR3 [
WUFIE OFFSET(22) NUMBITS(1) [],
WUS OFFSET(20) NUMBITS(2) [],
SCARCNT OFFSET(17) NUMBITS(2) [],
DEP OFFSET(15) NUMBITS(1) [],
DEM OFFSET(14) NUMBITS(1) [],
DDRE OFFSET(13) NUMBITS(1) [],
OVRDIS OFFSET(12) NUMBITS(1) [],
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) []
],
BRR [
DIV_Mantissa OFFSET(4) NUMBITS(12) [],
DIV_Fraction OFFSET(0) NUMBITS(4) []
],
GTPR [
GT OFFSET(8) NUMBITS(8) [],
PSC OFFSET(0) NUMBITS(8) []
],
RTOR [
BLEN OFFSET(24) NUMBITS(8) [],
RTO OFFSET(0) NUMBITS(24) []
],
RQR [
TXFRQ OFFSET(0) NUMBITS(1) [],
RXFRQ OFFSET(3) NUMBITS(1) [],
MMRQ OFFSET(2) NUMBITS(1) [],
SBKRQ OFFSET(1) NUMBITS(1) [],
ABRRQ OFFSET(0) NUMBITS(1) []
],
ISR [
REACK OFFSET(22) NUMBITS(1) [],
TEACK OFFSET(21) NUMBITS(1) [],
WUF OFFSET(20) NUMBITS(1) [],
RWU OFFSET(19) NUMBITS(1) [],
SBKF OFFSET(18) NUMBITS(1) [],
CMF OFFSET(17) NUMBITS(1) [],
BUSY OFFSET(16) NUMBITS(1) [],
ABRF OFFSET(15) NUMBITS(1) [],
ABRE OFFSET(14) NUMBITS(1) [],
EOBF OFFSET(12) NUMBITS(1) [],
RTOF OFFSET(11) NUMBITS(1) [],
CTS OFFSET(10) NUMBITS(1) [],
CTSIF OFFSET(9) NUMBITS(1) [],
LBDF 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) []
],
ICR [
WUCF OFFSET(20) NUMBITS(1) [],
CMCF OFFSET(17) NUMBITS(1) [],
EOBCF OFFSET(12) NUMBITS(1) [],
RTOCF OFFSET(11) NUMBITS(1) [],
CTSCF OFFSET(9) NUMBITS(1) [],
LBDCF OFFSET(8) NUMBITS(1) [],
TCCF OFFSET(6) NUMBITS(1) [],
IDLECF OFFSET(4) NUMBITS(1) [],
ORECF OFFSET(3) NUMBITS(1) [],
NCF OFFSET(2) NUMBITS(1) [],
FECF OFFSET(1) NUMBITS(1) [],
PECF OFFSET(0) NUMBITS(1) []
]
];
const USART1_BASE: StaticRef<UsartRegisters> =
unsafe { StaticRef::new(0x40013800 as *const UsartRegisters) };
const USART2_BASE: StaticRef<UsartRegisters> =
unsafe { StaticRef::new(0x40004400 as *const UsartRegisters) };
const USART3_BASE: StaticRef<UsartRegisters> =
unsafe { StaticRef::new(0x40004800 as *const UsartRegisters) };
#[allow(non_camel_case_types)]
#[derive(Copy, Clone, PartialEq)]
enum USARTStateTX {
Idle,
Transmitting,
AbortRequested,
}
#[allow(non_camel_case_types)]
#[derive(Copy, Clone, PartialEq)]
enum USARTStateRX {
Idle,
Receiving,
AbortRequested,
}
pub struct Usart<'a> {
registers: StaticRef<UsartRegisters>,
clock: UsartClock<'a>,
tx_client: OptionalCell<&'a dyn hil::uart::TransmitClient>,
rx_client: OptionalCell<&'a dyn hil::uart::ReceiveClient>,
tx_buffer: TakeCell<'static, [u8]>,
tx_position: Cell<usize>,
tx_len: Cell<usize>,
tx_status: Cell<USARTStateTX>,
rx_buffer: TakeCell<'static, [u8]>,
rx_position: Cell<usize>,
rx_len: Cell<usize>,
rx_status: Cell<USARTStateRX>,
deferred_call: DeferredCall,
}
impl<'a> Usart<'a> {
fn new(base_addr: StaticRef<UsartRegisters>, clock: UsartClock<'a>) -> Self {
Self {
registers: base_addr,
clock,
tx_client: OptionalCell::empty(),
rx_client: OptionalCell::empty(),
tx_buffer: TakeCell::empty(),
tx_position: Cell::new(0),
tx_len: Cell::new(0),
tx_status: Cell::new(USARTStateTX::Idle),
rx_buffer: TakeCell::empty(),
rx_position: Cell::new(0),
rx_len: Cell::new(0),
rx_status: Cell::new(USARTStateRX::Idle),
deferred_call: DeferredCall::new(),
}
}
pub fn new_usart1(rcc: &'a rcc::Rcc) -> Self {
Self::new(
USART1_BASE,
UsartClock(rcc::PeripheralClock::new(
rcc::PeripheralClockType::APB2(rcc::PCLK2::USART1),
rcc,
)),
)
}
pub fn new_usart2(rcc: &'a rcc::Rcc) -> Self {
Self::new(
USART2_BASE,
UsartClock(rcc::PeripheralClock::new(
rcc::PeripheralClockType::APB1(rcc::PCLK1::USART2),
rcc,
)),
)
}
pub fn new_usart3(rcc: &'a rcc::Rcc) -> Self {
Self::new(
USART3_BASE,
UsartClock(rcc::PeripheralClock::new(
rcc::PeripheralClockType::APB1(rcc::PCLK1::USART3),
rcc,
)),
)
}
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 send_byte(&self, byte: u8) {
while !self.registers.isr.is_set(ISR::TXE) {}
self.registers.tdr.set(byte.into());
}
fn enable_transmit_interrupt(&self) {
self.registers.cr1.modify(CR1::TXEIE::SET);
}
fn disable_transmit_interrupt(&self) {
self.registers.cr1.modify(CR1::TXEIE::CLEAR);
}
fn enable_receive_interrupt(&self) {
self.registers.cr1.modify(CR1::RXNEIE::SET);
}
fn disable_receive_interrupt(&self) {
self.registers.cr1.modify(CR1::RXNEIE::CLEAR);
}
fn clear_overrun(&self) {
self.registers.icr.modify(ICR::ORECF::SET);
}
pub fn handle_interrupt(&self) {
if self.registers.isr.is_set(ISR::TXE) {
self.disable_transmit_interrupt();
if self.tx_status.get() == USARTStateTX::Transmitting {
if self.tx_position.get() < self.tx_len.get() {
self.tx_buffer.map(|buf| {
self.registers.tdr.set(buf[self.tx_position.get()].into());
self.tx_position.replace(self.tx_position.get() + 1);
});
}
if self.tx_position.get() == self.tx_len.get() {
self.tx_status.replace(USARTStateTX::Idle);
} else {
self.enable_transmit_interrupt();
}
if self.tx_status.get() == USARTStateTX::Idle {
self.tx_client.map(|client| {
if let Some(buf) = self.tx_buffer.take() {
client.transmitted_buffer(buf, self.tx_len.get(), Ok(()));
}
});
}
}
}
if self.registers.isr.is_set(ISR::RXNE) {
let byte = self.registers.rdr.get() as u8;
self.disable_receive_interrupt();
if self.rx_status.get() == USARTStateRX::Receiving {
if self.rx_position.get() < self.rx_len.get() {
self.rx_buffer.map(|buf| {
buf[self.rx_position.get()] = byte;
self.rx_position.replace(self.rx_position.get() + 1);
});
}
if self.rx_position.get() == self.rx_len.get() {
self.rx_status.replace(USARTStateRX::Idle);
} else {
self.enable_receive_interrupt();
}
if self.rx_status.get() == USARTStateRX::Idle {
self.rx_client.map(|client| {
if let Some(buf) = self.rx_buffer.take() {
client.received_buffer(
buf,
self.rx_len.get(),
Ok(()),
hil::uart::Error::None,
);
}
});
}
}
}
if self.registers.isr.is_set(ISR::ORE) {
self.clear_overrun();
self.rx_status.replace(USARTStateRX::Idle);
self.rx_client.map(|client| {
if let Some(buf) = self.rx_buffer.take() {
client.received_buffer(
buf,
self.rx_position.get(),
Err(ErrorCode::CANCEL),
hil::uart::Error::OverrunError,
);
}
});
}
}
}
impl DeferredCallClient for Usart<'_> {
fn register(&'static self) {
self.deferred_call.register(self);
}
fn handle_deferred_call(&self) {
if self.tx_status.get() == USARTStateTX::AbortRequested {
self.tx_client.map(|client| {
self.tx_buffer.take().map(|buf| {
client.transmitted_buffer(buf, self.tx_position.get(), Err(ErrorCode::CANCEL));
});
});
self.tx_status.set(USARTStateTX::Idle);
}
if self.rx_status.get() == USARTStateRX::AbortRequested {
self.rx_client.map(|client| {
self.rx_buffer.take().map(|buf| {
client.received_buffer(
buf,
self.rx_position.get(),
Err(ErrorCode::CANCEL),
hil::uart::Error::Aborted,
);
});
});
self.rx_status.set(USARTStateRX::Idle);
}
}
}
impl<'a> hil::uart::Transmit<'a> for Usart<'a> {
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.tx_status.get() == USARTStateTX::Idle {
if tx_len <= tx_data.len() {
self.tx_buffer.put(Some(tx_data));
self.tx_position.set(0);
self.tx_len.set(tx_len);
self.tx_status.set(USARTStateTX::Transmitting);
self.enable_transmit_interrupt();
Ok(())
} else {
Err((ErrorCode::SIZE, tx_data))
}
} else {
Err((ErrorCode::BUSY, tx_data))
}
}
fn transmit_word(&self, _word: u32) -> Result<(), ErrorCode> {
Err(ErrorCode::FAIL)
}
fn transmit_abort(&self) -> Result<(), ErrorCode> {
if self.tx_status.get() != USARTStateTX::Idle {
self.disable_transmit_interrupt();
self.tx_status.set(USARTStateTX::AbortRequested);
self.deferred_call.set();
Err(ErrorCode::BUSY)
} else {
Ok(())
}
}
}
impl hil::uart::Configure for Usart<'_> {
fn configure(&self, params: hil::uart::Parameters) -> Result<(), ErrorCode> {
if params.baud_rate != 115200
|| 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 115200bps 8N1, no hardware flow control"
);
}
self.registers.cr1.modify(CR1::M0::CLEAR);
self.registers.cr1.modify(CR1::M1::CLEAR);
self.registers.cr2.modify(CR2::STOP.val(0b00_u32));
self.registers.cr1.modify(CR1::PCE::CLEAR);
self.registers.brr.modify(BRR::DIV_Fraction.val(0x5_u32));
self.registers.brr.modify(BRR::DIV_Mantissa.val(0x4_u32));
self.registers.cr1.modify(CR1::TE::SET);
self.registers.cr1.modify(CR1::RE::SET);
self.registers.cr1.modify(CR1::UE::SET);
Ok(())
}
}
impl<'a> hil::uart::Receive<'a> for Usart<'a> {
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.rx_status.get() == USARTStateRX::Idle {
if rx_len <= rx_buffer.len() {
self.rx_buffer.put(Some(rx_buffer));
self.rx_position.set(0);
self.rx_len.set(rx_len);
self.rx_status.set(USARTStateRX::Receiving);
self.enable_receive_interrupt();
Ok(())
} else {
Err((ErrorCode::SIZE, rx_buffer))
}
} else {
Err((ErrorCode::BUSY, rx_buffer))
}
}
fn receive_word(&self) -> Result<(), ErrorCode> {
Err(ErrorCode::FAIL)
}
fn receive_abort(&self) -> Result<(), ErrorCode> {
if self.rx_status.get() != USARTStateRX::Idle {
self.disable_receive_interrupt();
self.rx_status.set(USARTStateRX::AbortRequested);
self.deferred_call.set();
Err(ErrorCode::BUSY)
} else {
Ok(())
}
}
}
struct UsartClock<'a>(rcc::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();
}
}