204 lines
4.7 KiB
Rust
204 lines
4.7 KiB
Rust
//! SPI register module.
|
|
use arbitrary_int::{u2, u6, u10};
|
|
|
|
pub const I2C_0_BASE_ADDR: usize = 0xE000_4000;
|
|
pub const I2C_1_BASE_ADDR: usize = 0xE000_5000;
|
|
|
|
#[bitbybit::bitenum(u1, exhaustive = true)]
|
|
#[derive(Debug)]
|
|
pub enum Direction {
|
|
Receiver = 0b1,
|
|
Transmitter = 0b0,
|
|
}
|
|
|
|
#[bitbybit::bitenum(u1, exhaustive = true)]
|
|
#[derive(Debug)]
|
|
pub enum Mode {
|
|
Slave = 0b0,
|
|
Master = 0b1,
|
|
}
|
|
|
|
#[bitbybit::bitfield(u32, default = 0x0)]
|
|
pub struct Control {
|
|
/// Divides the input PCLK frequency by this value + 1
|
|
#[bits(14..=15, rw)]
|
|
div_a: u2,
|
|
/// Divides the output from divisor A by this value + 1
|
|
#[bits(8..=13, rw)]
|
|
div_b: u6,
|
|
#[bit(6, rw)]
|
|
clear_fifo: bool,
|
|
#[bit(5, rw)]
|
|
slv_mon: bool,
|
|
/// 0: Allow transfer to terminate as soon as all data has been transmitted or received.
|
|
/// 1: When no more data is avilable for transmit or no more data can be received, hold
|
|
/// the SCK line low until services by the host.
|
|
#[bit(4, rw)]
|
|
hold_bus: bool,
|
|
/// Should be set to 1. 0: Disabled, NACK transmitted. 1: Enabled, ACK transmitted.
|
|
#[bit(3, rw)]
|
|
acken: bool,
|
|
/// Only used in master mode. 0: Reserved. 1: Normal 7-bit address.
|
|
#[bit(2, rw)]
|
|
addressing: bool,
|
|
#[bit(1, rw)]
|
|
mode: Mode,
|
|
#[bit(0, rw)]
|
|
dir: Direction,
|
|
}
|
|
|
|
#[bitbybit::bitfield(u32)]
|
|
pub struct Status {
|
|
#[bit(8, r)]
|
|
bus_active: bool,
|
|
/// FIFO is full and new byte was received. The new byte is not acknowledged and the contents
|
|
/// of the FIFO remain unchanged.
|
|
#[bit(6, r)]
|
|
rx_overflow: bool,
|
|
/// 1: There is still a byte of data to be transmitted by the interface.
|
|
#[bit(6, r)]
|
|
tx_busy: bool,
|
|
/// Receiver data valid, ca be read from the interface.
|
|
#[bit(5, r)]
|
|
rx_valid: bool,
|
|
#[bit(3, r)]
|
|
rx_rw: bool,
|
|
}
|
|
|
|
#[bitbybit::bitfield(u32)]
|
|
pub struct Addr {
|
|
#[bits(0..=9, rw)]
|
|
addr: u10,
|
|
}
|
|
|
|
#[bitbybit::bitfield(u32)]
|
|
pub struct Fifo {
|
|
#[bits(0..=7, rw)]
|
|
data: u8,
|
|
}
|
|
|
|
#[bitbybit::bitfield(u32)]
|
|
pub struct InterruptStatus {
|
|
#[bit(9, rw)]
|
|
arbitration_lost: bool,
|
|
#[bit(7, rw)]
|
|
rx_underflow: bool,
|
|
#[bit(6, rw)]
|
|
tx_overflow: bool,
|
|
#[bit(5, rw)]
|
|
rx_overflow: bool,
|
|
#[bit(4, rw)]
|
|
slave_ready: bool,
|
|
#[bit(3, rw)]
|
|
timeout: bool,
|
|
#[bit(2, rw)]
|
|
nack: bool,
|
|
#[bit(1, rw)]
|
|
data: bool,
|
|
#[bit(0, rw)]
|
|
complete: bool,
|
|
}
|
|
|
|
#[bitbybit::bitfield(u32)]
|
|
pub struct InterruptMask {
|
|
#[bit(9, r)]
|
|
arbitration_lost: bool,
|
|
#[bit(7, r)]
|
|
rx_underflow: bool,
|
|
#[bit(6, r)]
|
|
tx_overflow: bool,
|
|
#[bit(5, r)]
|
|
rx_overflow: bool,
|
|
#[bit(4, r)]
|
|
slave_ready: bool,
|
|
#[bit(3, r)]
|
|
timeout: bool,
|
|
#[bit(2, r)]
|
|
nack: bool,
|
|
#[bit(1, r)]
|
|
data: bool,
|
|
#[bit(0, r)]
|
|
complete: bool,
|
|
}
|
|
|
|
#[bitbybit::bitfield(u32)]
|
|
pub struct InterruptControl {
|
|
#[bit(9, w)]
|
|
arbitration_lost: bool,
|
|
#[bit(7, w)]
|
|
rx_underflow: bool,
|
|
#[bit(6, w)]
|
|
tx_overflow: bool,
|
|
#[bit(5, w)]
|
|
rx_overflow: bool,
|
|
#[bit(4, w)]
|
|
slave_ready: bool,
|
|
#[bit(3, w)]
|
|
timeout: bool,
|
|
#[bit(2, w)]
|
|
nack: bool,
|
|
#[bit(1, w)]
|
|
data: bool,
|
|
#[bit(0, w)]
|
|
complete: bool,
|
|
}
|
|
|
|
#[bitbybit::bitfield(u32)]
|
|
pub struct Timeout {
|
|
/// Reset value: 0x1F.
|
|
#[bits(0..=7, rw)]
|
|
timeout: u8,
|
|
}
|
|
|
|
#[bitbybit::bitfield(u32, default = 0x0)]
|
|
pub struct TransferSize {
|
|
#[bits(0..=7, rw)]
|
|
size: u8,
|
|
}
|
|
|
|
#[derive(derive_mmio::Mmio)]
|
|
#[repr(C)]
|
|
pub struct I2c {
|
|
cr: Control,
|
|
#[mmio(PureRead)]
|
|
sr: Status,
|
|
addr: Addr,
|
|
#[mmio(Read, Write)]
|
|
data: Fifo,
|
|
#[mmio(PureRead, Write, Modify)]
|
|
isr: InterruptStatus,
|
|
transfer_size: TransferSize,
|
|
slave_pause: u32,
|
|
timeout: Timeout,
|
|
#[mmio(PureRead)]
|
|
imr: InterruptMask,
|
|
#[mmio(Write)]
|
|
ier: InterruptControl,
|
|
#[mmio(Write)]
|
|
idr: InterruptControl,
|
|
}
|
|
|
|
impl I2c {
|
|
/// Create a new I2C MMIO instance for I2C0 at address [I2C_0_BASE_ADDR].
|
|
///
|
|
/// # Safety
|
|
///
|
|
/// This API can be used to potentially create a driver to the same peripheral structure
|
|
/// from multiple threads. The user must ensure that concurrent accesses are safe and do not
|
|
/// interfere with each other.
|
|
pub const unsafe fn new_mmio_fixed_0() -> MmioI2c<'static> {
|
|
unsafe { Self::new_mmio_at(I2C_0_BASE_ADDR) }
|
|
}
|
|
|
|
/// Create a new I2C MMIO instance for I2C1 at address [I2C_1_BASE_ADDR].
|
|
///
|
|
/// # Safety
|
|
///
|
|
/// This API can be used to potentially create a driver to the same peripheral structure
|
|
/// from multiple threads. The user must ensure that concurrent accesses are safe and do not
|
|
/// interfere with each other.
|
|
pub const unsafe fn new_mmio_fixed_1() -> MmioI2c<'static> {
|
|
unsafe { Self::new_mmio_at(I2C_1_BASE_ADDR) }
|
|
}
|
|
}
|