Expand description
Board support for the M5Stack Cardputer ADV (ESP32-S3FN8, Stamp-S3A).
#[esp_rtos::main]
async fn main(_spawner: Spawner) -> ! {
let mut board = oxstack_cardputer::init(oxstack_cardputer::default_config());
let _backlight = board.backlight.init();
let i2c = board.sys_i2c.into_bus();
let mut display = board.display.init().await.unwrap();
let mut keyboard = board.keyboard.init(i2c).await.unwrap();
let fb = oxstack_cardputer::display::framebuffer();
loop {
let ev = keyboard.next_event().await.unwrap();
// draw into `fb`, then:
display.flush(fb).await.unwrap();
}
}§Model
Board splits the chip’s peripherals into one resource group per
board function: display, keyboard, audio, spi_bus and so on. Each
group owns exactly the pins and peripherals that function is wired to, so
the compiler rules out two drivers fighting over a pin. Groups you never
init cost nothing.
Every group has an init that borrows the group (&mut self) and
returns a driver tied to that borrow. Drop the driver and the group is
free again, so one firmware can start the same driver twice, or the
microphone after the speaker, without rebooting:
let mut mic = board.audio.recorder(i2c, rate, gain).await?;
// ... record ...
drop(mic);
let mut speaker = board.audio.player(i2c, rate, volume).await?; // same hardwareGroups are plain structs of esp-hal peripherals with a 'd lifetime.
Destructure one to drive the pins yourself, or reborrow() it to lend a
shorter-lived copy to a function, exactly as with esp-hal peripherals.
Three things are one-per-boot by nature and keep a consuming API: the
shared I²C bus (i2c::SysI2cResources::into_bus), the framebuffer
(display::framebuffer) and the Wi-Fi station (net::start_station).
§Project setup
The quickest start is the template in the repository:
cargo install cargo-generate espup espflash --locked
espup install && source ~/export-esp.sh
cargo generate --git https://github.com/theashraf/oxstack templates/cardputer-appBy hand, a firmware crate needs:
- Dependencies at the versions this crate pins. The ones you use in
types are re-exported here ([
esp_hal], [esp_rtos], [embassy_executor], [embassy_time], [embassy_sync], [embassy_futures], [esp_bootloader_esp_idf]). Addesp-backtrace(panic handler) andesp-printlnwithdefmt-espflash+jtag-serial(log transport) yourself; a library must not pull in a panic handler.#[esp_rtos::main]expands to paths inesp_rtosandembassy_executor, so list those two as direct dependencies too. rust-toolchain.tomlselecting theespchannel (espup install)..cargo/config.toml: targetxtensa-esp32s3-none-elf,build-std = ["core", "alloc"],rustflags = ["-C", "link-arg=-nostartfiles"]and anespflash flash --monitor --log-format defmtrunner.build.rsemitting-Tdefmt.xand, last,-Tlinkall.x.esp_bootloader_esp_idf::esp_app_desc!();once inmain.rs.
API docs are built for the ESP32-S3 and hosted at https://theashraf.github.io/oxstack/oxstack_cardputer/; docs.rs cannot build for Xtensa.
Re-exports§
pub use oxstack_audio as dsp;pub use oxstack_drivers as drivers;pub use oxstack_gfx as gfx;pub use oxstack_input as input;pub use embassy_executor;pub use embassy_futures;pub use embassy_sync;pub use embassy_time;pub use esp_bootloader_esp_idf;pub use esp_hal;pub use esp_rtos;
Modules§
- audio
- Audio: ES8311 codec on I²S0 (DMA channel 1) and the internal I²C bus, driving an NS4150B speaker amplifier and fed by an analog MEMS mic.
- backlight
- LCD backlight on GPIO38, dimmed with LEDC PWM.
- battery
- Battery voltage on GPIO10 (ADC1) through a 100 kΩ / 100 kΩ divider.
- ble
- Bluetooth LE: Espressif’s controller (via
esp-radio) under the pure-Rusttroublehost stack. Requires theblefeature. - display
- The 1.14“ 240×135 ST7789V2 LCD, in landscape with the keyboard below.
- i2c
- The internal I²C bus (GPIO8/9), shared by the TCA8418 keyboard scanner, ES8311 codec and BMI270 IMU.
- imu
- BMI270 IMU on the internal I²C bus (0x69).
- ir
- IR transmitter on GPIO44 (LED driven directly through 22 Ω), using an
RMT channel with hardware 38 kHz carrier modulation. Get it from
crate::rmt::RmtResources::init. - keyboard
- The 56-key keyboard, scanned by a TCA8418 on the internal I²C bus.
- led
- The WS2812-class RGB LED on GPIO21, driven by an RMT channel. Get it
from
crate::rmt::RmtResources::init. - net
- Wi-Fi: scanning, and station networking (connect, DHCP, DNS, UDP/TCP via
embassy-net) plus network time. Requires thewififeature. - pins
- Cardputer ADV pin assignment, for reference and for code that drives
pins directly. The typed equivalents live in
Board. - radio
- Wi-Fi and Bluetooth LE through Espressif’s
esp-radio. - rmt
- The RMT pulse generator and the two LEDs it drives: the WS2812-class RGB LED (GPIO21) and the IR transmitter (GPIO44).
- sd
- microSD card on the shared SPI bus (SPI2: SCK 40, MOSI 14, MISO 39,
CS 12), with FAT through
embedded-sdmmc(re-exported as [fs]).
Structs§
- Board
- Every peripheral of the chip, grouped by what the Cardputer ADV wires it
to. Create it with
crate::initorBoard::new. - ExtResources
- EXT header lines other than SPI and I²C.
- Grove
Resources - Grove port signal lines.
- RawResources
- Peripherals that are mostly register blocks, for low-level code.
- Rtos
Resources - What the
esp-rtosscheduler needs.crate::initconsumes it. - Spare
Resources - Pins the Cardputer ADV schematic does not route to any connector, plus UART0. Kept rather than dropped so nothing is lost for good.
- SpiBus
Resources - The shared SPI bus and both of its chip selects.
sdis incrate::sd. - System
Resources - Chip peripherals with no fixed board role.
Functions§
- default_
config - The configuration
initshould normally be given: CPU at 240 MHz. - init
- Initialises the chip, starts the
esp-rtosscheduler (required for Embassy timers), and returns the board. With theradiofeature it also adds the reclaimed-RAM heap thatesp-radioneeds.