Course contentsShow
← Rust
Lesson 1887 of 1,91016. Specialized Runtime TargetsFree lesson

Power-Domain Isolation

Design software architectures that remain stable during partial system power-down cycles.

In this lesson, you will learn how to design software architectures that maintain state integrity and prevent system hangs when specific hardware power domains are cycled or powered down.

The Challenge of Partial Power-Downs

In advanced embedded systems, we often cut power to specific peripherals—like radio modules or secondary sensors—to conserve energy. However, if your software assumes these devices are always available, accessing their Memory-Mapped I/O (MMIO) registers while the power domain is offline will trigger a hardware fault or bus hang.

To handle this, we must enforce a strict separation between "always-on" orchestration logic and "transient" domain-specific logic.

Architecting for Isolation

We achieve this in Rust by using the type system to represent the power state of a peripheral. Rather than using a global static that might be accessed while a device is unpowered, we encapsulate the device driver behind a state-aware wrapper.

pub struct PoweredOff;
pub struct PoweredOn {
    // Peripheral registers are only accessible here
}

pub struct RadioDomain<State> {
    state: core::marker::PhantomData<State>,
}

impl RadioDomain<PoweredOff> {
    pub fn power_up(self) -> RadioDomain<PoweredOn> {
        // Trigger hardware PMIC/Register sequence
        RadioDomain { state: core::marker::PhantomData }
    }
}

impl RadioDomain<PoweredOn> {
    pub fn send_packet(&mut self, data: &[u8]) {
        // Safe to access MMIO here
    }
    
    pub fn power_down(self) -> RadioDomain<PoweredOff> {
        // Power down sequence
        RadioDomain { state: core::marker::PhantomData }
    }
}

Ensuring Stability

By tying the availability of the driver methods to the PoweredOn state, you move the risk of hardware access violations from runtime crashes to compile-time errors.

When designing your architecture:

  1. Represent the State in the Type: Never allow a RadioDomain to be accessed in the PoweredOff state.
  2. Handle Initialization Glitches: Use the "Hardware Watchdog" concepts we discussed earlier to ensure the power-up sequence completes within a deterministic timeframe.
  3. Implicit Dependencies: If an "always-on" component relies on data from a "transient" domain, implement an asynchronous "Ready" signal or a buffered mailbox. This ensures the always-on component doesn't block waiting for an unpowered domain, which would defeat the purpose of power-domain isolation.

Key Takeaway: Use Rust’s type system to enforce power-state transitions, ensuring that peripheral MMIO access is physically impossible while the corresponding power domain is offline.