pub struct Lilka {
pub peripherals: Peripherals,
pub delay: LilkaDelay,
pub controller: ControllerState,
pub adc_battery: Adcbattery<'static>,
pub display: LilkaDisplay,
pub sd: Option<SD<Bus<SdSpi<'static>, Output<'static>, SdClock>>>,
pub i2s_tx: I2sTx<'static>,
pub buzzer: Buzzer,
}Expand description
The top-level handle to all Lilka console hardware subsystems.
Created by calling Lilka::init with a LilkaConfiguration. All fields are
pub so you can borrow them independently in your game loop.
§Field overview
| Field | Type | Purpose |
|---|---|---|
peripherals | [esp_hal::peripherals::Peripherals] | Raw peripheral singleton (already consumed during init; kept for future use). |
delay | LilkaDelay | embedded-hal delay implementation — Delay for blocking, embassy_time::Delay for async. |
controller | ControllerState | D-pad + action buttons (A/B/C/D), Select, Start. |
adc_battery | Adcbattery | Battery voltage ADC on GPIO3 via ADC1. |
display | LilkaDisplay | 240×280 ST7789 TFT display via SPI2. |
sd | Option<SdVolMgr> | SD card volume manager; None if no card was detected. |
i2s_tx | I2sTx | I2S transmitter for audio output (default 44 100 Hz stereo). |
buzzer | Buzzer | PWM buzzer driven by the LEDC peripheral (GPIO11). |
§Example — reading a button
use lilkaoxide::prelude::*;
// Buttons use pull-up resistors: low = pressed
if lilka.controller.a.is_low() {
defmt::info!("A pressed!");
}§Example — reading battery voltage
use lilkaoxide::prelude::*;
let mv = lilka.adc_battery.read_voltage_mv();
defmt::info!("Battery: {} mV", mv);Fields§
§peripherals: Peripherals§delay: LilkaDelay§controller: ControllerState§adc_battery: Adcbattery<'static>§display: LilkaDisplay§sd: Option<SD<Bus<SdSpi<'static>, Output<'static>, SdClock>>>§i2s_tx: I2sTx<'static>§buzzer: BuzzerImplementations§
Source§impl Lilka
impl Lilka
Sourcepub fn init(config: Configuration) -> Result<Self, InitError>
pub fn init(config: Configuration) -> Result<Self, InitError>
Initialises all Lilka console hardware subsystems in a fixed order.
This is the only correct entry-point to the SDK. Call it once at the
beginning of main (or your embassy task) with a Configuration and
receive a fully-initialised Lilka handle.
§Initialisation order
esp_hal::init— set CPU clock fromconfig.cpu_clock.RtosRuntime::start— start embassy executor (asynconly).init_spi_master— SPI2 atconfig.spi_frequency(GPIO18 SCK, GPIO17 MOSI, GPIO8 MISO).init_bus— wrap the raw SPI bus in the selected sharing wrapper (RefCell/CriticalSection/ …).display::init_display— ST7789 240×280 on GPIO46 (power), GPIO15 (DC), GPIO7 (CS).sd::init_sd— SD card on GPIO16 (CS), shared SPI bus.ControllerState::init_controller— GPIO5/6/10/9/38/41/39/40/0/4 pulled-up inputs.adcbattery::init_adcbattery— ADC1, GPIO3, configured attenuation.i2s::init_i2s_tx— I2S0 DMA TX on GPIO42 (BCLK), GPIO2 (DOUT), GPIO1 (LRCK).buzzer::init_buzzer— LEDC on GPIO11.
Steps 3–5, 9, and 10 are fatal: failure returns immediately via InitError.
Step 6 (SD) is non-fatal: an absent or unreadable card sets Lilka::sd to None.
§Parameters
config— aConfiguration(useConfiguration::defaultfor sensible defaults).
§Returns
Ok(Lilka) with all subsystems initialised, or Err(InitError) on the first
fatal failure. Regardless of the outcome the init status is printed via defmt.
§Note on async vs blocking
The function signature is async fn but the deasync proc-macro generates a
synchronous wrapper when the blocking feature is active. You call Lilka::init
the same way in both modes — just omit .await in blocking code.
§Examples
Blocking (features = ["blocking", "RefCellBus", "display_buffer_8192"]):
#![no_std]
#![no_main]
use lilkaoxide::prelude::*;
#[esp_hal::entry]
fn main() -> ! {
let lilka = Lilka::init(LilkaConfiguration::default())
.expect("hardware init failed");
defmt::info!("Display ready, battery: {} mV",
// Note: need mut borrow for ADC reads
// lilka.adc_battery.read_voltage_mv()
);
loop {}
}Async (features = ["async", "AsyncBus", "display_buffer_8192"]):
#![no_std]
#![no_main]
use lilkaoxide::prelude::*;
#[embassy_executor::main]
async fn main(_spawner: embassy_executor::Spawner) {
let lilka = Lilka::init(LilkaConfiguration::default())
.await
.expect("hardware init failed");
assert!(lilka.rtos.is_started());
}