A lightweight and flexible serial driver library that provides register-level access through generic interfaces. By implementing these interfaces, users can create asynchronous serial drivers for various platforms with ease.
- Register-Level Abstraction: Offers low-level register-like control while maintaining usability.
- Asynchronous Read/Write Support: Enables non-blocking data transmission and reception using interrupts and device FIFO.
- Highly Portable: Abstracted hardware layer allows easy adaptation to different MCUs or SoCs.
- Modular Design: Clean architecture suitable for integration into existing embedded projects.
- Full-Duplex Communication: Supports simultaneous sending and receiving, automatically controlling the lifecycle of the transmitter and receiver.
To use this library, implement the following device-specific interface functions:
pub trait Registers: Clone + 'static {
fn can_put(&self) -> bool;
fn put(&self, c: u8) -> Result<(), ErrorKind>;
fn can_get(&self) -> bool;
fn get(&self) -> Result<u8, ErrorKind>;
fn get_irq_event(&self) -> IrqEvent;
fn clean_irq_event(&self, event: IrqEvent);
}
Then you can use it like this:
static HANDLER: OnceCell<IrqHandler> = OnceCell::new();
// Your interrupt handler
fn handle_irq() {
HANDLER.get().unwrap().handle_irq();
}
async fn use() {
let mut serial = Serial::new(your_registers_impl);
let handler = serial.irq_handler.take().unwrap();
HANDLER.set(handler).unwrap();
// If the TX has already been taken, it will fail.
let mut tx = serial.try_take_tx().unwrap();
let mut rx = serial.try_take_rx().unwrap();
tx.write_all(b"hello!").await.unwrap();
// The TX will be given back to serial.
drop(tx);
// Can take tx again.
let mut tx = serial.try_take_tx().unwrap();
}
Contributions are welcome!
This project is licensed under the MIT License.