feat(boards): LilyGo T-Beam (classic) support
First classic-ESP32 (non-S3) board in the firmware, and first SX127x radio. ESP32 + SX1276 + SSD1306 OLED + AXP192 PMIC, CP2102 USB-UART bridge. Pin map verified from MeshCore variants/lilygo_tbeam_SX1276. The AXP192 gates power to the LoRa chip and OLED. Its I²C bus is shared with the display, so the firmware builds I²C0 in blocking mode first for the PMIC init, then converts the same handle to async and hands it to the display task — avoids double-consuming the peripheral. Lora-phy's Sx127x support drives DIO0 as the sole IRQ (SX127x has no BUSY line); the chip runs from a crystal, tx_boost routes +20 dBm through PA_BOOST. The `esp-hal` / `esp-rtos` / `esp-backtrace` / `esp-println` deps have been restructured so the chip flavour (esp32 vs esp32s3) is selected at the per-board feature level instead of baked into the dep lines. This keeps the existing S3 boards building on esp32s3 while the new T-Beam feature selects classic esp32 via the same dependency set. LoRaBoard gains supported_sf_bitmap() / supported_bw_bitmap() methods (with SX126x defaults) so the T-Beam can report SF6–SF12 via GET_INFO — the SX1276 has no SF5. radio_chip_id() reports 0x0011 per donglora-protocol RadioChipId::Sx1276. freq_range_hz widens to the SX1276 datasheet span of 137 MHz–1020 MHz. New modules: - src/hal/esp32.rs — classic-ESP32 MCU primitives - src/board/esp32.rs — Sx127x radio + SSD1306 display pipe - src/board/lilygo_tbeam.rs — the board file - src/driver/axp.rs — AXP192 init added alongside AXP2101
This commit is contained in:
15 files changed
+534
-43
No files matched your search
@@ -0,0 +1,80 @@
|
||||
//! ESP32 (classic / non-S3) MCU initialization primitives.
|
||||
//!
|
||||
//! Mirror of `hal::esp32s3` with a single delta: the classic ESP32 uses a
|
||||
//! peripheral-bound DMA (`DMA_SPI2`) rather than the S3's channel-addressed
|
||||
//! GDMA (`DMA_CH0`). Timer, I²C, and eFuse access are otherwise identical
|
||||
//! between the two Xtensa parts in this esp-hal vintage.
|
||||
|
||||
use embassy_sync::blocking_mutex::raw::NoopRawMutex;
|
||||
use esp_hal::dma::{DmaRxBuf, DmaTxBuf};
|
||||
use esp_hal::gpio::interconnect::{PeripheralInput, PeripheralOutput};
|
||||
use esp_hal::i2c::master::I2c;
|
||||
use esp_hal::spi::master::{Config as SpiConfig, Spi, SpiDmaBus};
|
||||
use esp_hal::spi::Mode as SpiMode;
|
||||
use esp_hal::time::Rate;
|
||||
use esp_hal::timer::timg::TimerGroup;
|
||||
use static_cell::StaticCell;
|
||||
|
||||
// ── MCU-level types ─────────────────────────────────────────────────
|
||||
|
||||
pub type SpiBus = SpiDmaBus<'static, esp_hal::Async>;
|
||||
pub type I2cBus = I2c<'static, esp_hal::Async>;
|
||||
|
||||
// ── Timer ───────────────────────────────────────────────────────────
|
||||
|
||||
/// Start the ESP-RTOS scheduler and Embassy time driver.
|
||||
pub fn start_timer(
|
||||
timg0: esp_hal::peripherals::TIMG0<'static>,
|
||||
sw_int: esp_hal::peripherals::SW_INTERRUPT<'static>,
|
||||
) {
|
||||
let timg0 = TimerGroup::new(timg0);
|
||||
let sw_ints = esp_hal::interrupt::software::SoftwareInterruptControl::new(sw_int);
|
||||
esp_rtos::start(timg0.timer0, sw_ints.software_interrupt0);
|
||||
}
|
||||
|
||||
// ── SPI bus ─────────────────────────────────────────────────────────
|
||||
|
||||
/// Initialize SPI2 with peripheral-bound DMA and wrap in a shared bus
|
||||
/// (`StaticCell` + `Mutex`).
|
||||
///
|
||||
/// Generic over pin type. The classic ESP32's matrix of GPIO → peripheral
|
||||
/// routes lets any GPIO serve as any SPI signal — same as the S3.
|
||||
pub fn init_spi(
|
||||
spi2: esp_hal::peripherals::SPI2<'static>,
|
||||
dma_spi2: esp_hal::peripherals::DMA_SPI2<'static>,
|
||||
sck: impl PeripheralOutput<'static>,
|
||||
mosi: impl PeripheralOutput<'static>,
|
||||
miso: impl PeripheralInput<'static>,
|
||||
) -> &'static embassy_sync::mutex::Mutex<NoopRawMutex, SpiBus> {
|
||||
let spi = Spi::new(
|
||||
spi2,
|
||||
SpiConfig::default()
|
||||
.with_frequency(Rate::from_mhz(1))
|
||||
.with_mode(SpiMode::_0),
|
||||
)
|
||||
.expect("SPI init")
|
||||
.with_sck(sck)
|
||||
.with_mosi(mosi)
|
||||
.with_miso(miso)
|
||||
.with_dma(dma_spi2);
|
||||
|
||||
let (rx_buf, rx_desc, tx_buf, tx_desc) = esp_hal::dma_buffers!(256);
|
||||
let dma_rx = DmaRxBuf::new(rx_desc, rx_buf).expect("DMA RX buf");
|
||||
let dma_tx = DmaTxBuf::new(tx_desc, tx_buf).expect("DMA TX buf");
|
||||
|
||||
let spi = spi.with_buffers(dma_rx, dma_tx).into_async();
|
||||
|
||||
static SPI_BUS: StaticCell<embassy_sync::mutex::Mutex<NoopRawMutex, SpiBus>> =
|
||||
StaticCell::new();
|
||||
SPI_BUS.init(embassy_sync::mutex::Mutex::new(spi))
|
||||
}
|
||||
|
||||
// ── MAC address ─────────────────────────────────────────────────────
|
||||
|
||||
/// Read the factory-programmed MAC address from eFuse.
|
||||
pub fn mac_address() -> [u8; 6] {
|
||||
esp_hal::efuse::base_mac_address()
|
||||
.as_bytes()
|
||||
.try_into()
|
||||
.expect("MAC is 6 bytes")
|
||||
}
|
||||
@@ -12,6 +12,9 @@
|
||||
))]
|
||||
pub mod esp32s3;
|
||||
|
||||
#[cfg(feature = "lilygo_tbeam")]
|
||||
pub mod esp32;
|
||||
|
||||
#[cfg(any(feature = "rak_wisblock_4631", feature = "wio_tracker_l1"))]
|
||||
pub mod nrf52840;
|
||||
|
||||
|
||||
Reference in new issue
Block a user