use ruspiro_gpio::GPIO;
use ruspiro_mmio_register::define_mmio_register;
use ruspiro_register::RegisterFieldValue;
use ruspiro_timer as timer;
use crate::InterruptType;
#[cfg(feature = "ruspiro_pi3")]
const PERIPHERAL_BASE: usize = 0x3F00_0000;
const AUX_BASE: usize = PERIPHERAL_BASE + 0x0021_5000;
pub(crate) fn uart1_init(clock_rate: u32, baud_rate: u32) -> Result<(), &'static str> {
GPIO.with_mut(|gpio| {
let tx = gpio
.get_pin(14)
.map(|pin| pin.into_alt_f5().into_pud_disabled());
let ty = gpio
.get_pin(15)
.map(|pin| pin.into_alt_f5().into_pud_disabled());
Ok((tx, ty))
})
.map(|_| {
AUX_ENABLES::Register.write(AUX_ENABLES::MINIUART_ENABLE, 0x1); AUX_MU_IER_REG::Register.set(0x0); AUX_MU_CNTL_REG::Register.set(0x0); AUX_MU_LCR_REG::Register.write(AUX_MU_LCR_REG::DATASIZE, 0x3); AUX_MU_MCR_REG::Register.set(0x0); AUX_MU_IER_REG::Register.set(0x0); AUX_MU_IIR_REG::Register .write_value(
RegisterFieldValue::<u32>::new(AUX_MU_IIR_REG::IRQID_FIFOCLR, 0b11)
| RegisterFieldValue::<u32>::new(AUX_MU_IIR_REG::FIFO_ENABLES, 0b11),
); AUX_MU_BAUD_REG::Register.set(clock_rate / (8 * baud_rate) - 1);
AUX_MU_CNTL_REG::Register .write_value(
RegisterFieldValue::<u32>::new(AUX_MU_CNTL_REG::RCV_ENABLE, 0x1)
| RegisterFieldValue::<u32>::new(AUX_MU_CNTL_REG::TRANS_ENABLE, 0x1),
); })
}
pub(crate) fn uart1_release() {
GPIO.with_mut(|gpio| {
gpio.free_pin(14);
gpio.free_pin(15);
});
}
pub(crate) fn uart1_send_char(c: char) {
let data: [u8; 1] = [c as u8];
uart1_send_data(&data);
}
pub(crate) fn uart1_send_string(s: &str) {
uart1_send_data(s.as_bytes());
}
pub(crate) fn uart1_send_data(data: &[u8]) {
for byte in data {
while AUX_MU_LSR_REG::Register.read(AUX_MU_LSR_REG::TRANSEMPTY) == 0 {
timer::sleepcycles(10);
}
AUX_MU_IO_REG::Register.set(*byte as u32);
}
}
pub(crate) fn uart1_receive_data(timeout: u32) -> Result<u8, &'static str> {
let mut count = 0;
while AUX_MU_LSR_REG::Register.read(AUX_MU_LSR_REG::DATAREADY) == 0
&& (timeout == 0 || count < timeout)
{
timer::sleepcycles(1000);
count += 1;
}
if timeout != 0 && count >= timeout {
Err("Timeout")
} else {
Ok((AUX_MU_IO_REG::Register.get() & 0xFF) as u8)
}
}
pub(crate) fn uart1_enable_interrupts(i_type: InterruptType) {
match i_type {
InterruptType::Receive => {
AUX_MU_IER_REG::Register.write_value(
RegisterFieldValue::<u32>::new(AUX_MU_IER_REG::RCV_IRQ, 0b11)
| RegisterFieldValue::<u32>::new(AUX_MU_IER_REG::RX_ENABLE, 0x1),
);
}
InterruptType::Transmit => {
AUX_MU_IER_REG::Register.write_value(
RegisterFieldValue::<u32>::new(AUX_MU_IER_REG::RCV_IRQ, 0b11)
| RegisterFieldValue::<u32>::new(AUX_MU_IER_REG::TX_ENABLE, 0x1),
);
}
InterruptType::RecieveTransmit => {
AUX_MU_IER_REG::Register.write_value(
RegisterFieldValue::<u32>::new(AUX_MU_IER_REG::RCV_IRQ, 0b11)
| RegisterFieldValue::<u32>::new(AUX_MU_IER_REG::RX_ENABLE, 0x1)
| RegisterFieldValue::<u32>::new(AUX_MU_IER_REG::TX_ENABLE, 0x1),
);
}
}
}
pub(crate) fn uart1_disable_interrupts(i_type: InterruptType) {
match i_type {
InterruptType::Receive => {
AUX_MU_IER_REG::Register.write(AUX_MU_IER_REG::RX_ENABLE, 0x0);
}
InterruptType::Transmit => {
AUX_MU_IER_REG::Register.write(AUX_MU_IER_REG::TX_ENABLE, 0x0);
}
InterruptType::RecieveTransmit => {
AUX_MU_IER_REG::Register.set(0x0);
}
}
}
pub(crate) fn uart1_get_interrupt_status() -> u32 {
AUX_MU_IIR_REG::Register.read(AUX_MU_IIR_REG::IRQPENDING)
| (AUX_MU_IIR_REG::Register.read(AUX_MU_IIR_REG::IRQID_FIFOCLR) << 1)
}
define_mmio_register! [
AUX_IRQ<ReadOnly<u32>@(AUX_BASE + 0x00)>,
AUX_ENABLES<ReadWrite<u32>@(AUX_BASE + 0x04)> {
MINIUART_ENABLE OFFSET(0),
SPI1_ENABLE OFFSET(1),
SPI2_ENABLE OFFSET(2)
},
AUX_MU_IO_REG<ReadWrite<u32>@(AUX_BASE + 0x40)>,
AUX_MU_IER_REG<ReadWrite<u32>@(AUX_BASE + 0x44)> {
RX_ENABLE OFFSET(0),
TX_ENABLE OFFSET(1),
RCV_IRQ OFFSET(2) BITS(2) },
AUX_MU_IIR_REG<ReadWrite<u32>@(AUX_BASE + 0x48)> {
IRQPENDING OFFSET(0),
IRQID_FIFOCLR OFFSET(1) BITS(2),
FIFO_ENABLES OFFSET(6) BITS(2)
},
AUX_MU_LCR_REG<ReadWrite<u32>@(AUX_BASE + 0x4C)> {
DATASIZE OFFSET(0) BITS(2),
BREAK OFFSET(6),
DLAB OFFSET(7)
},
AUX_MU_MCR_REG<ReadWrite<u32>@(AUX_BASE + 0x50)>,
AUX_MU_LSR_REG<ReadOnly<u32>@(AUX_BASE + 0x54)> {
DATAREADY OFFSET(0),
RCVOVERRUN OFFSET(1),
TRANSEMPTY OFFSET(5),
TRANSIDLE OFFSET(6)
},
AUX_MU_MSR_REG<ReadWrite<u32>@(AUX_BASE + 0x58)>,
AUX_MU_CNTL_REG<ReadWrite<u32>@(AUX_BASE + 0x60)> {
RCV_ENABLE OFFSET(0),
TRANS_ENABLE OFFSET(1),
AUTO_FLOW_RTS OFFSET(2),
AUTO_FLOW_CTS OFFSET(3),
AUTO_RTS_LEVEL OFFSET(4) BITS(2),
RTS_ASSERT OFFSET(6),
CTS_ASSERT OFFSET(7)
},
AUX_MU_STAT_REG<ReadWrite<u32>@(AUX_BASE + 0x64)>,
AUX_MU_BAUD_REG<ReadWrite<u32>@(AUX_BASE + 0x68)>
];