Module kernel::common::peripherals[][src]

Peripheral Management

Most peripherals are implemented as memory mapped I/O (MMIO). Intrinsically, this means that accessing a peripheral requires dereferencing a raw pointer that points to the peripheral's memory.

Generally, Tock peripherals are modeled by two structures, such as:

/// The MMIO Structure.
#[repr(C)]
#[allow(dead_code)]
pub struct PeripheralRegisters {
    control: VolatileCell<u32>,
    interrupt_mask: VolatileCell<u32>,
}

/// The Tock object that holds all information for this peripheral.
pub struct PeripheralHardware {
    mmio_address: StaticRef<PeripheralRegisters>,
    clock: &ChipSpecificPeripheralClock,
}

The first structure mirrors the MMIO specification. The second structure holds a pointer to the actual address in memory. It also holds other information for the peripheral. Kernel traits will be implemented for this peripheral hardware structure. As the peripheral cannot derefence the raw MMIO pointer safely, Tock provides the PeripheralManager interface:

impl hil::uart::UART for PeripheralHardware {
   fn init(&self, params: hil::uart::UARTParams) {
       let peripheral = &PeripheralManager::new(self);
       peripheral.registers.control.set(0x0);
       //         ^^^^^^^^^-- This is type &PeripheralRegisters

Each peripheral must tell the kernel where its registers live in memory:

/// Teaching the kernel how to create PeripheralRegisters.
impl PeripheralManagement<pm::Clock> for PeripheralHardware {
    type RegisterType = PeripheralRegisters;

    fn get_registers(&self) -> &PeripheralRegisters {
        &*self.mmio_address
    }
}

Note, this example kept the mmio_address in the PeripheralHardware structure, which is useful when there are multiple copies of the same peripheral (e.g. multiple UARTs). For single-instance peripherals, it's fine to simply return the address directly from get_registers.

Peripheral Clocks

To facilitate low-power operation, PeripheralManager captures the peripheral's clock upon instantiation. The intention is to exploit Ownership Based Resource Management to capture peripheral power state.

To enable this, peripherals must inform the kernel which clock they use, and when the clock should be enabled and disabled. Implementations of the before/after_mmio_access methods must take care to not access hardware without enabling clocks if needed if they use hardware for bookkeeping.

/// Teaching the kernel which clock controls SpiHw.
impl PeripheralManagement<pm::Clock> for SpiHw {
    fn get_clock(&self) -> &pm::Clock {
        &pm::Clock::PBA(pm::PBAClock::SPI)
    }

    fn before_mmio_access(&self, clock: &pm::Clock, _registers: &SpiRegisters) {
        clock.enable();
    }

    fn after_mmio_access(&self, clock: &pm::Clock, _registers: &SpiRegisters) {
        if !self.is_busy() {
            clock.disable();
        }
    }
}

Re-exports

use ClockInterface;

Structs

PeripheralManager

Structures encapsulating periphal hardware (those implementing the PeripheralManagement trait) should instantiate an instance of this method to accesss memory mapped registers.

Traits

PeripheralManagement

A structure encapsulating a peripheral should implement this trait.