thomson

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs

commit 92aef158c7ce5ff33bcbdd8aec863bd2d4a64cfb
parent 593bc482e2fd56b9a9077fd38ca35de4a7490e10
Author: Daniel Barlow <dan@telent.net>
Date:   Thu, 18 Jun 2026 22:14:09 +0100

result of running esp-generate

Diffstat:
A.cargo/config.toml | 17+++++++++++++++++
A.clippy.toml | 1+
A.gitignore | 26++++++++++++++++++++++++++
ACargo.toml | 95+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
AHACKING.md | 10++++++++++
Abuild.rs | 72++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mrust-toolchain.toml | 4+++-
Asrc/bin/main.rs | 63+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/lib.rs | 1+
Atests/hello_test.rs | 34++++++++++++++++++++++++++++++++++
10 files changed, 322 insertions(+), 1 deletion(-)

diff --git a/.cargo/config.toml b/.cargo/config.toml @@ -0,0 +1,17 @@ +[target.riscv32imc-unknown-none-elf] +runner = "probe-rs run --chip=esp32c3 --preverify --always-print-stacktrace --no-location" + +[env] +DEFMT_LOG="info" + +[build] +rustflags = [ + # Required to obtain backtraces (e.g. when using the "esp-backtrace" crate.) + # NOTE: May negatively impact performance of produced code + "-C", "force-frame-pointers", +] + +target = "riscv32imc-unknown-none-elf" + +[unstable] +build-std = ["alloc", "core"] diff --git a/.clippy.toml b/.clippy.toml @@ -0,0 +1 @@ +stack-size-threshold = 1024 diff --git a/.gitignore b/.gitignore @@ -0,0 +1,26 @@ +# will have compiled files and executables +debug/ +target/ + +# Editor configuration +.vscode/ +.zed/ +.helix/ +.nvim.lua + +# These are backup files generated by rustfmt +**/*.rs.bk + +# MSVC Windows builds of rustc generate these, which store debugging information +*.pdb + +# RustRover +# JetBrains specific template is maintained in a separate JetBrains.gitignore that can +# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore +# and can be added to the global gitignore or merged into this file. For a more nuclear +# option (not recommended) you can uncomment the following to ignore the entire idea folder. +#.idea/ + + +# Ignore .DS_Store file in mac +**/.DS_Store diff --git a/Cargo.toml b/Cargo.toml @@ -0,0 +1,95 @@ +[package] +edition = "2024" +name = "thomson" +rust-version = "1.88" +version = "0.1.0" + +[[bin]] +name = "thomson" +path = "./src/bin/main.rs" +test = false + +[[test]] +harness = false +name = "hello_test" + +[lib] +test = false + +[dependencies] +esp-hal = { version = "~1.1.0", features = ["defmt", "esp32c3", "unstable"] } + +esp-rtos = { version = "0.3.0", features = [ + "defmt", + "embassy", + "esp-alloc", + "esp-radio", + "esp32c3", +] } + +defmt = "1.0.1" +esp-bootloader-esp-idf = { version = "0.5.0", features = ["defmt", "esp32c3"] } + +embassy-net = { version = "0.9.1", features = [ + "defmt", + "dhcpv4", + "medium-ethernet", + "tcp", + "udp", +] } +embedded-io = { version = "0.7.1", features = ["defmt"] } +embedded-io-async = { version = "0.7.0", features = ["defmt"] } +esp-alloc = { version = "0.10.0", features = ["defmt"] } +panic-rtt-target = { version = "0.2.0", features = ["defmt"] } +rtt-target = { version = "0.6.2", features = ["defmt"] } +# for more networking protocol support see https://crates.io/crates/edge-net +bleps = { git = "https://github.com/bjoernQ/bleps", package = "bleps", rev = "a5148d8ae679e021b78f53fd33afb8bb35d0b62e", features = [ + "async", + "macros", +] } +embassy-executor = { version = "0.10.0", features = ["defmt"] } +embassy-time = { version = "0.5.0", features = ["defmt"] } +esp-radio = { version = "0.18.0", features = [ + "ble", + "coex", + "defmt", + "esp-alloc", + "esp32c3", + "unstable", + "wifi", +] } +smoltcp = { version = "0.13.0", default-features = false, features = [ + "defmt", + "medium-ethernet", + "multicast", + "proto-dhcpv4", + "proto-dns", + "proto-ipv4", + "socket-dns", + "socket-icmp", + "socket-raw", + "socket-tcp", + "socket-udp", +] } + +critical-section = "1.2.0" +static_cell = "2.1.1" + +[dev-dependencies] +embedded-test = { version = "0.7.1", features = [ + "defmt", + "embassy-010", + "external-executor", +] } + +# For fine tuning these settings, please refer to https://doc.rust-lang.org/cargo/reference/profiles.html +[profile.dev] +# The default debug profile is too slow and too big for resource-constrained devices. +# Always build with some optimizations enabled. +opt-level = "s" + +[profile.release] +codegen-units = 1 # LLVM can perform better optimizations using a single thread +debug = 2 # prefer slower builds but better debugging experience +lto = 'fat' +opt-level = 's' diff --git a/HACKING.md b/HACKING.md @@ -0,0 +1,10 @@ +per https://docs.espressif.com/projects/rust/book/getting-started/toolchain.html + +1. get rustup (I use `nix-shell -p rustup.nix`) +2. rustup toolchain install stable --component rust-src +3. rustup target add riscv32imc-unknown-none-elf + +cargo install esp-generate --locked +cargo install espflash --locked +cargo install probe-rs-tools --locked +esp-generate diff --git a/build.rs b/build.rs @@ -0,0 +1,72 @@ +fn main() { + linker_be_nice(); + println!("cargo:rustc-link-arg-tests=-Tembedded-test.x"); + println!("cargo:rustc-link-arg=-Tdefmt.x"); + // make sure linkall.x is the last linker script (otherwise might cause problems with flip-link) + println!("cargo:rustc-link-arg=-Tlinkall.x"); +} + +fn linker_be_nice() { + let args: Vec<String> = std::env::args().collect(); + if args.len() > 1 { + let kind = &args[1]; + let what = &args[2]; + + match kind.as_str() { + "undefined-symbol" => match what.as_str() { + what if what.starts_with("_defmt_") => { + eprintln!(); + eprintln!( + "💡 `defmt` not found - make sure `defmt.x` is added as a linker script and you have included `use defmt_rtt as _;`" + ); + eprintln!(); + } + "_stack_start" => { + eprintln!(); + eprintln!("💡 Is the linker script `linkall.x` missing?"); + eprintln!(); + } + what if what.starts_with("esp_rtos_") => { + eprintln!(); + eprintln!( + "💡 `esp-radio` has no scheduler enabled. Make sure you have initialized `esp-rtos` or provided an external scheduler." + ); + eprintln!(); + } + "embedded_test_linker_file_not_added_to_rustflags" => { + eprintln!(); + eprintln!( + "💡 `embedded-test` not found - make sure `embedded-test.x` is added as a linker script for tests" + ); + eprintln!(); + } + "free" + | "malloc" + | "calloc" + | "get_free_internal_heap_size" + | "malloc_internal" + | "realloc_internal" + | "calloc_internal" + | "free_internal" => { + eprintln!(); + eprintln!( + "💡 Did you forget the `esp-alloc` dependency or didn't enable the `compat` feature on it?" + ); + eprintln!(); + } + _ => (), + }, + // we don't have anything helpful for "missing-lib" yet + _ => { + std::process::exit(1); + } + } + + std::process::exit(0); + } + + println!( + "cargo:rustc-link-arg=--error-handling-script={}", + std::env::current_exe().unwrap().display() + ); +} diff --git a/rust-toolchain.toml b/rust-toolchain.toml @@ -1,2 +1,4 @@ [toolchain] -channel = "stable" +channel = "stable" +components = ["rust-src"] +targets = ["riscv32imc-unknown-none-elf"] diff --git a/src/bin/main.rs b/src/bin/main.rs @@ -0,0 +1,63 @@ +#![no_std] +#![no_main] +#![deny( + clippy::mem_forget, + reason = "mem::forget is generally not safe to do with esp_hal types, especially those \ + holding buffers for the duration of a data transfer." +)] +#![deny(clippy::large_stack_frames)] + +use defmt::info; +use embassy_executor::Spawner; +use embassy_time::{Duration, Timer}; +use esp_hal::clock::CpuClock; +use esp_hal::timer::timg::TimerGroup; +use esp_radio::ble::controller::BleConnector; +use panic_rtt_target as _; + +extern crate alloc; + +// This creates a default app-descriptor required by the esp-idf bootloader. +// For more information see: <https://docs.espressif.com/projects/esp-idf/en/stable/esp32/api-reference/system/app_image_format.html#application-description> +esp_bootloader_esp_idf::esp_app_desc!(); + +#[allow( + clippy::large_stack_frames, + reason = "it's not unusual to allocate larger buffers etc. in main" +)] +#[esp_rtos::main] +async fn main(spawner: Spawner) -> ! { + // generator version: 1.3.0 + // generator parameters: --chip esp32c3 -o alloc -o unstable-hal -o wifi -o ble-bleps -o embassy -o probe-rs -o defmt -o panic-rtt-target -o embedded-test + + rtt_target::rtt_init_defmt!(); + + let config = esp_hal::Config::default().with_cpu_clock(CpuClock::max()); + let peripherals = esp_hal::init(config); + + esp_alloc::heap_allocator!(#[esp_hal::ram(reclaimed)] size: 66320); + // COEX needs more RAM - so we've added some more + esp_alloc::heap_allocator!(size: 64 * 1024); + + let timg0 = TimerGroup::new(peripherals.TIMG0); + let sw_interrupt = + esp_hal::interrupt::software::SoftwareInterruptControl::new(peripherals.SW_INTERRUPT); + esp_rtos::start(timg0.timer0, sw_interrupt.software_interrupt0); + + info!("Embassy initialized!"); + + let (mut _wifi_controller, _interfaces) = + esp_radio::wifi::new(peripherals.WIFI, Default::default()) + .expect("Failed to initialize Wi-Fi controller"); + let _connector = BleConnector::new(peripherals.BT, Default::default()); + + // TODO: Spawn some tasks + let _ = spawner; + + loop { + info!("Hello world!"); + Timer::after(Duration::from_secs(1)).await; + } + + // for inspiration have a look at the examples at https://github.com/esp-rs/esp-hal/tree/esp-hal-v1.1.0/examples +} diff --git a/src/lib.rs b/src/lib.rs @@ -0,0 +1 @@ +#![no_std] diff --git a/tests/hello_test.rs b/tests/hello_test.rs @@ -0,0 +1,34 @@ +//! Demo test suite using embedded-test +//! +//! You can run this using `cargo test` as usual. + +#![no_std] +#![no_main] + +esp_bootloader_esp_idf::esp_app_desc!(); + +#[cfg(test)] +#[embedded_test::tests(executor = esp_rtos::embassy::Executor::new())] +mod tests { + use defmt::assert_eq; + + #[init] + fn init() { + let peripherals = esp_hal::init(esp_hal::Config::default()); + + let timg0 = esp_hal::timer::timg::TimerGroup::new(peripherals.TIMG0); + let sw_interrupt = + esp_hal::interrupt::software::SoftwareInterruptControl::new(peripherals.SW_INTERRUPT); + esp_rtos::start(timg0.timer0, sw_interrupt.software_interrupt0); + + rtt_target::rtt_init_defmt!(); + } + + #[test] + async fn hello_test() { + defmt::info!("Running test!"); + + embassy_time::Timer::after(embassy_time::Duration::from_millis(100)).await; + assert_eq!(1 + 1, 2); + } +}