use crate::pac::{AUX, GPIO, UART1};
use core::fmt;
#[cfg(not(feature = "bcm2711"))]
const GPIO_BASE: usize = 0x3f20_0000;
#[cfg(not(feature = "bcm2711"))]
const GPPUD: *mut u32 = (GPIO_BASE + 0x94) as *mut u32;
#[cfg(not(feature = "bcm2711"))]
const GPPUDCLK0: *mut u32 = (GPIO_BASE + 0x98) as *mut u32;
pub const CORE_CLOCK_HZ: u32 = 250_000_000;
#[cfg(not(feature = "bcm2711"))]
fn disable_gpio14_15_pull(_gpio: &GPIO) {
const GPIO14_15_MASK: u32 = (1 << 14) | (1 << 15);
unsafe {
core::ptr::write_volatile(GPPUD, 0);
spin_delay(150);
core::ptr::write_volatile(GPPUDCLK0, GPIO14_15_MASK);
spin_delay(150);
core::ptr::write_volatile(GPPUD, 0);
core::ptr::write_volatile(GPPUDCLK0, 0);
}
}
#[cfg(feature = "bcm2711")]
fn disable_gpio14_15_pull(gpio: &GPIO) {
gpio.gpio_pup_pdn_cntrl_reg0().modify(|_, w| {
w.gpio_pup_pdn_cntrl14()
.none()
.gpio_pup_pdn_cntrl15()
.none()
});
}
#[cfg(not(feature = "bcm2711"))]
fn spin_delay(cycles: u32) {
for _ in 0..cycles {
unsafe { core::arch::asm!("nop") };
}
}
fn baud_to_reg(baud: u32) -> Option<u16> {
if baud == 0 {
return None;
}
let denom = 8 * baud;
let ratio = (CORE_CLOCK_HZ + denom / 2) / denom;
if ratio == 0 {
return None;
}
let reg = ratio - 1;
if reg > u16::MAX as u32 {
return None;
}
Some(reg as u16)
}
pub struct MiniUart {
uart1: UART1,
}
impl MiniUart {
pub fn from_initialized(uart1: UART1) -> Self {
Self { uart1 }
}
pub fn init(gpio: &GPIO, aux: &AUX, uart1: UART1) -> Self {
aux.enables().modify(|_, w| w.uart_1().set_bit());
disable_gpio14_15_pull(gpio);
gpio.gpfsel1()
.modify(|_, w| w.fsel14().txd1().fsel15().rxd1());
uart1
.cntl()
.write(|w| w.tx_enable().clear_bit().rx_enable().clear_bit());
uart1
.ier()
.write(|w| w.data_ready().clear_bit().tx_ready().clear_bit());
uart1.lcr().write(|w| w.data_size()._8bit());
uart1
.iir()
.write(|w| w.data_ready().set_bit().tx_ready().set_bit());
if let Some(reg) = baud_to_reg(115_200) {
uart1.baud().write(|w| unsafe { w.bits(reg) });
}
uart1
.cntl()
.write(|w| w.tx_enable().set_bit().rx_enable().set_bit());
let me = Self { uart1 };
for _ in 0..8 {
if me.try_read_byte().is_none() {
break;
}
}
me
}
pub fn write_byte(&mut self, byte: u8) {
while self.uart1.lsr().read().tx_empty().bit_is_clear() {}
unsafe {
self.uart1.io().write(|w| w.data().bits(byte));
}
}
pub fn flush(&mut self) {
while self.uart1.lsr().read().tx_idle().bit_is_clear() {}
}
#[must_use]
pub fn set_baud(&mut self, baud: u32) -> bool {
let Some(reg) = baud_to_reg(baud) else {
return false;
};
self.uart1
.cntl()
.modify(|_, w| w.tx_enable().clear_bit().rx_enable().clear_bit());
self.uart1.baud().write(|w| unsafe { w.bits(reg) });
self.uart1
.cntl()
.modify(|_, w| w.tx_enable().set_bit().rx_enable().set_bit());
true
}
pub fn read_byte(&mut self) -> u8 {
while self.uart1.lsr().read().data_ready().bit_is_clear() {}
self.uart1.io().read().data().bits()
}
pub fn byte_available(&self) -> bool {
self.uart1.lsr().read().data_ready().bit_is_set()
}
pub fn try_read_byte(&self) -> Option<u8> {
if self.uart1.lsr().read().data_ready().bit_is_clear() {
return None;
}
Some(self.uart1.io().read().data().bits())
}
pub fn enable_rx_irq(&self) {
self.uart1.ier().modify(|_, w| w.data_ready().set_bit());
}
pub fn disable_rx_irq(&self) {
self.uart1.ier().modify(|_, w| w.data_ready().clear_bit());
}
}
impl fmt::Write for MiniUart {
fn write_str(&mut self, s: &str) -> fmt::Result {
for byte in s.bytes() {
if byte == b'\n' {
self.write_byte(b'\r');
}
self.write_byte(byte);
}
Ok(())
}
}
impl embedded_io::ErrorType for MiniUart {
type Error = core::convert::Infallible;
}
impl embedded_io::Read for MiniUart {
fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
if buf.is_empty() {
return Ok(0);
}
buf[0] = self.read_byte();
let mut n = 1;
while n < buf.len() && self.byte_available() {
buf[n] = self.read_byte();
n += 1;
}
Ok(n)
}
}
impl embedded_io::Write for MiniUart {
fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
for &byte in buf {
self.write_byte(byte);
}
Ok(buf.len())
}
fn flush(&mut self) -> Result<(), Self::Error> {
while self.uart1.lsr().read().tx_idle().bit_is_clear() {}
Ok(())
}
}