From 6aadd9ec04cf20c252c373ff2a46900e177912ae Mon Sep 17 00:00:00 2001 From: bjoernQ Date: Thu, 5 Sep 2024 17:51:06 +0200 Subject: [PATCH 1/8] esp-wifi uses global allocator, esp-alloc supports multiple regions --- esp-alloc/CHANGELOG.md | 2 + esp-alloc/Cargo.toml | 3 +- esp-alloc/src/lib.rs | 252 ++++++++++++++---- esp-alloc/src/macros.rs | 26 +- esp-hal/src/soc/esp32s2/psram.rs | 1 + esp-hal/src/soc/esp32s3/psram.rs | 1 + esp-wifi/CHANGELOG.md | 1 + esp-wifi/Cargo.toml | 3 - esp-wifi/MIGRATING-0.9.md | 29 +- esp-wifi/src/compat/malloc.rs | 19 +- esp-wifi/src/lib.rs | 29 +- esp-wifi/src/wifi/os_adapter.rs | 6 +- esp-wifi/tuning.md | 1 - examples/src/bin/dma_extmem2mem.rs | 9 +- examples/src/bin/psram_octal.rs | 10 +- examples/src/bin/psram_quad.rs | 10 +- examples/src/bin/wifi_80211_tx.rs | 3 + examples/src/bin/wifi_access_point.rs | 3 + .../src/bin/wifi_access_point_with_sta.rs | 3 + examples/src/bin/wifi_bench.rs | 3 + examples/src/bin/wifi_ble.rs | 3 + examples/src/bin/wifi_coex.rs | 3 + examples/src/bin/wifi_dhcp.rs | 5 + examples/src/bin/wifi_embassy_access_point.rs | 3 + .../bin/wifi_embassy_access_point_with_sta.rs | 3 + examples/src/bin/wifi_embassy_bench.rs | 3 + examples/src/bin/wifi_embassy_ble.rs | 3 + examples/src/bin/wifi_embassy_dhcp.rs | 3 + examples/src/bin/wifi_embassy_esp_now.rs | 3 + .../src/bin/wifi_embassy_esp_now_duplex.rs | 3 + examples/src/bin/wifi_esp_now.rs | 3 + examples/src/bin/wifi_sniffer.rs | 4 +- examples/src/bin/wifi_static_ip.rs | 3 + 33 files changed, 326 insertions(+), 130 deletions(-) diff --git a/esp-alloc/CHANGELOG.md b/esp-alloc/CHANGELOG.md index 85894f3a362..e2701d9f103 100644 --- a/esp-alloc/CHANGELOG.md +++ b/esp-alloc/CHANGELOG.md @@ -11,6 +11,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed +- a global allocator is created in esp-alloc, now you need to add individual memory regions (up to 3) to the allocator + ### Fixed ### Removed diff --git a/esp-alloc/Cargo.toml b/esp-alloc/Cargo.toml index d6beab49b8a..09d1bd2f238 100644 --- a/esp-alloc/Cargo.toml +++ b/esp-alloc/Cargo.toml @@ -23,7 +23,8 @@ default-target = "riscv32imc-unknown-none-elf" features = ["nightly"] [dependencies] -critical-section = "1.1.2" +critical-section = "1.1.3" +enumset = "1.1.5" linked_list_allocator = { version = "0.10.5", default-features = false, features = ["const_mut_refs"] } [features] diff --git a/esp-alloc/src/lib.rs b/esp-alloc/src/lib.rs index 3d4bce93961..70f1677cb40 100644 --- a/esp-alloc/src/lib.rs +++ b/esp-alloc/src/lib.rs @@ -1,33 +1,35 @@ -//! A simple `no_std` heap allocator for RISC-V and Xtensa processors from +//! A `no_std` heap allocator for RISC-V and Xtensa processors from //! Espressif. Supports all currently available ESP32 devices. //! //! **NOTE:** using this as your global allocator requires using Rust 1.68 or //! greater, or the `nightly` release channel. //! //! # Using this as your Global Allocator -//! To use EspHeap as your global allocator, you need at least Rust 1.68 or -//! nightly. //! //! ```rust -//! #[global_allocator] -//! static ALLOCATOR: esp_alloc::EspHeap = esp_alloc::EspHeap::empty(); +//! use esp_alloc as _; //! //! fn init_heap() { //! const HEAP_SIZE: usize = 32 * 1024; //! static mut HEAP: MaybeUninit<[u8; HEAP_SIZE]> = MaybeUninit::uninit(); //! //! unsafe { -//! ALLOCATOR.init(HEAP.as_mut_ptr() as *mut u8, HEAP_SIZE); +//! esp_alloc::INSTANCE.add_region(esp_alloc::HeapRegion::new( +//! HEAP.as_mut_ptr() as *mut u8, +//! HEAP_SIZE, +//! esp_alloc::MemoryCapability::Internal.into(), +//! )); //! } //! } //! ``` //! //! # Using this with the nightly `allocator_api`-feature -//! Sometimes you want to have single allocations in PSRAM, instead of an esp's -//! DRAM. For that, it's convenient to use the nightly `allocator_api`-feature, +//! Sometimes you want to have more control over allocations. +//! +//! For that, it's convenient to use the nightly `allocator_api`-feature, //! which allows you to specify an allocator for single allocations. //! -//! **NOTE:** To use this, you have to enable the create's `nightly` feature +//! **NOTE:** To use this, you have to enable the crate's `nightly` feature //! flag. //! //! Create and initialize an allocator to use in single allocations: @@ -36,7 +38,11 @@ //! //! fn init_psram_heap() { //! unsafe { -//! PSRAM_ALLOCATOR.init(psram::psram_vaddr_start() as *mut u8, psram::PSRAM_BYTES); +//! PSRAM_ALLOCATOR.add_region(esp_alloc::HeapRegion::new( +//! psram::psram_vaddr_start() as *mut u8, +//! psram::PSRAM_BYTES, +//! esp_alloc::MemoryCapability::Internal.into(), +//! )); //! } //! } //! ``` @@ -50,7 +56,7 @@ #![cfg_attr(feature = "nightly", feature(allocator_api))] #![doc(html_logo_url = "https://avatars.githubusercontent.com/u/46717278")] -pub mod macros; +mod macros; #[cfg(feature = "nightly")] use core::alloc::{AllocError, Allocator}; @@ -61,35 +67,92 @@ use core::{ }; use critical_section::Mutex; +use enumset::{EnumSet, EnumSetType}; use linked_list_allocator::Heap; +/// The global allocator instance +#[global_allocator] +pub static INSTANCE: EspHeap = EspHeap::empty(); + +const NON_REGION: Option = None; + +#[derive(EnumSetType)] +/// Describes the properties of a memory region +pub enum MemoryCapability { + /// Memory must be internal; specifically it should not disappear when + /// flash/spiram cache is switched off + Internal, + /// Memory must be in SPI RAM + External, +} + +/// A memory region to be used as heap memory +pub struct HeapRegion { + heap: Heap, + capabilities: EnumSet, +} + +impl HeapRegion { + /// Create a new [HeapRegion] with the given capabilities + pub unsafe fn new( + heap_bottom: *mut u8, + size: usize, + capabilities: EnumSet, + ) -> Self { + let mut heap = Heap::empty(); + heap.init(heap_bottom, size); + + Self { heap, capabilities } + } +} + +/// For esp-wifi +#[doc(hidden)] +#[no_mangle] +pub extern "C" fn free_internal_heap() -> usize { + INSTANCE.free_caps(MemoryCapability::Internal.into()) +} + +/// For esp-wifi +#[doc(hidden)] +#[no_mangle] +pub extern "C" fn allocate_from_internal_ram(size: usize) -> *mut u8 { + unsafe { + INSTANCE.alloc_caps( + MemoryCapability::Internal.into(), + Layout::from_size_align_unchecked(size, 4), + ) + } +} + +/// A memory allocator +/// +/// In addition to what Rust's memory allocator can do it allows to allocate +/// memory in regions satisfying specific needs. pub struct EspHeap { - heap: Mutex>, + heap: Mutex; 3]>>, } impl EspHeap { /// Crate a new UNINITIALIZED heap allocator - /// - /// You must initialize this heap using the - /// [`init`](struct.EspHeap.html#method.init) method before using the - /// allocator. - pub const fn empty() -> EspHeap { + pub const fn empty() -> Self { EspHeap { - heap: Mutex::new(RefCell::new(Heap::empty())), + heap: Mutex::new(RefCell::new([NON_REGION; 3])), } } - /// Initializes the heap - /// - /// This function must be called BEFORE you run any code that makes use of - /// the allocator. + /// Add a memory region to the heap /// /// `heap_bottom` is a pointer to the location of the bottom of the heap. /// /// `size` is the size of the heap in bytes. /// + /// You can add up to three regions per allocator. + /// /// Note that: /// + /// - Memory is allocated from the first suitable memory region first + /// /// - The heap grows "upwards", towards larger addresses. Thus `end_addr` /// must be larger than `start_addr` /// @@ -102,59 +165,144 @@ impl EspHeap { /// `'static` lifetime). /// - The supplied memory region must be exclusively available to the heap /// only, no aliasing. - /// - This function must be called exactly ONCE. /// - `size > 0`. - pub unsafe fn init(&self, heap_bottom: *mut u8, size: usize) { - critical_section::with(|cs| self.heap.borrow(cs).borrow_mut().init(heap_bottom, size)); + pub unsafe fn add_region(&self, region: HeapRegion) { + critical_section::with(|cs| { + let mut regions = INSTANCE.heap.borrow_ref_mut(cs); + let free = regions + .iter() + .enumerate() + .find(|v| v.1.is_none()) + .map(|v| v.0); + + if let Some(free) = free { + regions[free] = Some(region); + } else { + panic!( + "Exceeded the maximum of {} heap memory regions", + regions.len() + ); + } + }); } - /// Returns an estimate of the amount of bytes in use. + /// Returns an estimate of the amount of bytes in use in all memory regions. pub fn used(&self) -> usize { - critical_section::with(|cs| self.heap.borrow(cs).borrow_mut().used()) + critical_section::with(|cs| { + let regions = self.heap.borrow_ref(cs); + let mut used = 0; + for region in regions.iter() { + if let Some(region) = region.as_ref() { + used += region.heap.used(); + } + } + used + }) } /// Returns an estimate of the amount of bytes available. pub fn free(&self) -> usize { - critical_section::with(|cs| self.heap.borrow(cs).borrow_mut().free()) + self.free_caps(EnumSet::empty()) + } + + /// The free heap satisfying the given requirements + pub fn free_caps(&self, capabilities: EnumSet) -> usize { + critical_section::with(|cs| { + let regions = self.heap.borrow_ref(cs); + let mut free = 0; + for region in regions.iter().filter(|region| { + if region.is_some() { + region + .as_ref() + .unwrap() + .capabilities + .is_superset(capabilities) + } else { + false + } + }) { + if let Some(region) = region.as_ref() { + free += region.heap.free(); + } + } + free + }) + } + + /// Allocate memory in a region satisfying the given requirements. + pub unsafe fn alloc_caps( + &self, + capabilities: EnumSet, + layout: Layout, + ) -> *mut u8 { + critical_section::with(|cs| { + let mut regions = self.heap.borrow_ref_mut(cs); + let mut iter = (*regions).iter_mut().filter(|region| { + if region.is_some() { + region + .as_ref() + .unwrap() + .capabilities + .is_superset(capabilities) + } else { + false + } + }); + + let res = loop { + if let Some(Some(region)) = iter.next() { + let res = region.heap.allocate_first_fit(layout); + if let Ok(res) = res { + break Some(res); + } + } else { + break None; + } + }; + + res.map_or(ptr::null_mut(), |allocation| allocation.as_ptr()) + }) } } unsafe impl GlobalAlloc for EspHeap { unsafe fn alloc(&self, layout: Layout) -> *mut u8 { - critical_section::with(|cs| { - self.heap - .borrow(cs) - .borrow_mut() - .allocate_first_fit(layout) - .ok() - .map_or(ptr::null_mut(), |allocation| allocation.as_ptr()) - }) + self.alloc_caps(EnumSet::empty(), layout) } unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) { + if ptr.is_null() { + return; + } + critical_section::with(|cs| { - self.heap - .borrow(cs) - .borrow_mut() - .deallocate(NonNull::new_unchecked(ptr), layout) - }); + let mut regions = self.heap.borrow_ref_mut(cs); + let mut iter = (*regions).iter_mut(); + + loop { + if let Some(Some(region)) = iter.next() { + if region.heap.bottom() <= ptr && region.heap.top() >= ptr { + region.heap.deallocate(NonNull::new_unchecked(ptr), layout); + } + } else { + break; + } + } + }) } } #[cfg(feature = "nightly")] unsafe impl Allocator for EspHeap { fn allocate(&self, layout: Layout) -> Result, AllocError> { - critical_section::with(|cs| { - let raw_ptr = self - .heap - .borrow(cs) - .borrow_mut() - .allocate_first_fit(layout) - .map_err(|_| AllocError)? - .as_ptr(); - let ptr = NonNull::new(raw_ptr).ok_or(AllocError)?; - Ok(NonNull::slice_from_raw_parts(ptr, layout.size())) - }) + let raw_ptr = unsafe { self.alloc(layout) }; + + if raw_ptr.is_null() { + return Err(AllocError); + } + + let ptr = NonNull::new(raw_ptr).ok_or(AllocError)?; + Ok(NonNull::slice_from_raw_parts(ptr, layout.size())) } unsafe fn deallocate(&self, ptr: NonNull, layout: Layout) { diff --git a/esp-alloc/src/macros.rs b/esp-alloc/src/macros.rs index 17eec9662b9..e53be94e6cb 100644 --- a/esp-alloc/src/macros.rs +++ b/esp-alloc/src/macros.rs @@ -1,24 +1,25 @@ //! Macros provided for convenience -/// Create a heap allocator providing a heap of the given size in bytes -/// -/// You can only have ONE allocator at most +/// Initialize a global heap allocator providing a heap of the given size in +/// bytes #[macro_export] macro_rules! heap_allocator { ($size:expr) => {{ - #[global_allocator] - static ALLOCATOR: $crate::EspHeap = $crate::EspHeap::empty(); static mut HEAP: core::mem::MaybeUninit<[u8; $size]> = core::mem::MaybeUninit::uninit(); unsafe { - ALLOCATOR.init(HEAP.as_mut_ptr() as *mut u8, $size); + $crate::INSTANCE.add_region($crate::HeapRegion::new( + HEAP.as_mut_ptr() as *mut u8, + $size, + $crate::MemoryCapability::Internal.into(), + )); } }}; } -/// Create a heap allocator backed by PSRAM +/// Initialize a global heap allocator backed by PSRAM /// -/// You can only have ONE allocator at most. You need a SoC which supports PSRAM +/// You need a SoC which supports PSRAM /// and activate the feature to enable it. You need to pass the PSRAM peripheral /// and the psram module path. /// @@ -29,13 +30,14 @@ macro_rules! heap_allocator { #[macro_export] macro_rules! psram_allocator { ($peripheral:expr,$psram_module:path) => {{ - #[global_allocator] - static ALLOCATOR: $crate::EspHeap = $crate::EspHeap::empty(); - use $psram_module as _psram; _psram::init_psram($peripheral); unsafe { - ALLOCATOR.init(_psram::psram_vaddr_start() as *mut u8, _psram::PSRAM_BYTES); + $crate::INSTANCE.add_region($crate::HeapRegion::new( + _psram::psram_vaddr_start() as *mut u8, + _psram::PSRAM_BYTES, + $crate::MemoryCapability::External.into(), + )); } }}; } diff --git a/esp-hal/src/soc/esp32s2/psram.rs b/esp-hal/src/soc/esp32s2/psram.rs index 54fbb2ec2e0..a02b059f6e5 100644 --- a/esp-hal/src/soc/esp32s2/psram.rs +++ b/esp-hal/src/soc/esp32s2/psram.rs @@ -43,6 +43,7 @@ pub const PSRAM_VADDR_START: usize = PSRAM_VADDR as usize; /// Initialize PSRAM to be used for data. #[cfg(any(feature = "psram-2m", feature = "psram-4m", feature = "psram-8m"))] +#[procmacros::ram] pub fn init_psram(_peripheral: impl crate::peripheral::Peripheral

) { #[allow(unused)] enum CacheLayout { diff --git a/esp-hal/src/soc/esp32s3/psram.rs b/esp-hal/src/soc/esp32s3/psram.rs index 59aa01d16e4..c910895e941 100644 --- a/esp-hal/src/soc/esp32s3/psram.rs +++ b/esp-hal/src/soc/esp32s3/psram.rs @@ -57,6 +57,7 @@ pub const PSRAM_BYTES: usize = PSRAM_SIZE as usize * 1024 * 1024; feature = "opsram-8m", feature = "opsram-16m" ))] +#[procmacros::ram] pub fn init_psram(_peripheral: impl crate::peripheral::Peripheral

) { const CONFIG_ESP32S3_INSTRUCTION_CACHE_SIZE: u32 = 0x4000; const CONFIG_ESP32S3_ICACHE_ASSOCIATED_WAYS: u8 = 8; diff --git a/esp-wifi/CHANGELOG.md b/esp-wifi/CHANGELOG.md index 8a1064b7581..c9b0d0d0b43 100644 --- a/esp-wifi/CHANGELOG.md +++ b/esp-wifi/CHANGELOG.md @@ -12,6 +12,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Added `have-strchr` feature to disable including `strchr` (#2096) ### Changed +- esp-wifi now allocates memory from the global allocator defined by esp-alloc ### Fixed diff --git a/esp-wifi/Cargo.toml b/esp-wifi/Cargo.toml index e935fe2b4fc..58b4412a0f6 100644 --- a/esp-wifi/Cargo.toml +++ b/esp-wifi/Cargo.toml @@ -24,9 +24,6 @@ log = { version = "0.4.22", optional = true } embedded-svc = { version = "0.27.1", default-features = false, features = [ ], optional = true } enumset = { version = "1.1.5", default-features = false, optional = true } -linked_list_allocator = { version = "0.10.5", default-features = false, features = [ - "const_mut_refs", -] } embedded-io = { version = "0.6.1", default-features = false } embedded-io-async = { version = "0.6.1", optional = true } fugit = "0.3.7" diff --git a/esp-wifi/MIGRATING-0.9.md b/esp-wifi/MIGRATING-0.9.md index 3763b185f8e..c33374dcf74 100644 --- a/esp-wifi/MIGRATING-0.9.md +++ b/esp-wifi/MIGRATING-0.9.md @@ -1,8 +1,6 @@ -Migration Guide from 0.9.x to vNext -==================================== +# Migration Guide from 0.9.x to vNext -Initialsation -------------- +## Initialization You no longer have to set up clocks and pass them to `esp_wifi::initialize`. @@ -39,3 +37,26 @@ You no longer have to set up clocks and pass them to `esp_wifi::initialize`. // ... } ``` + +## Memory allocation + +You now need to have a global allocator provided by `esp-alloc` providing allocations from internal memory + +```diff + #![no_std] + #![no_main] + ++extern crate alloc; ++ + use embedded_io::*; ++use esp_alloc as _; + use esp_backtrace as _; + // ... + + #[entry] + fn main() -> ! { ++ esp_alloc::heap_allocator!(72 * 1024); ++ + + // ... +``` diff --git a/esp-wifi/src/compat/malloc.rs b/esp-wifi/src/compat/malloc.rs index 0647db0ff90..ac5d58e1e08 100644 --- a/esp-wifi/src/compat/malloc.rs +++ b/esp-wifi/src/compat/malloc.rs @@ -1,20 +1,16 @@ use core::alloc::Layout; -use crate::HEAP; - #[no_mangle] pub unsafe extern "C" fn malloc(size: usize) -> *mut u8 { trace!("alloc {}", size); let total_size = size + 4; - let layout = Layout::from_size_align_unchecked(total_size, 4); - let ptr = critical_section::with(|cs| { - HEAP.borrow_ref_mut(cs) - .allocate_first_fit(layout) - .ok() - .map_or(core::ptr::null_mut(), |allocation| allocation.as_ptr()) - }); + extern "C" { + fn allocate_from_internal_ram(size: usize) -> *mut u8; + } + + let ptr = unsafe { allocate_from_internal_ram(total_size) }; if ptr.is_null() { warn!("Unable to allocate {} bytes", size); @@ -37,10 +33,7 @@ pub unsafe extern "C" fn free(ptr: *mut u8) { let total_size = *(ptr as *const usize); let layout = Layout::from_size_align_unchecked(total_size, 4); - critical_section::with(|cs| { - HEAP.borrow_ref_mut(cs) - .deallocate(core::ptr::NonNull::new_unchecked(ptr), layout) - }); + alloc::alloc::dealloc(ptr, layout); } #[no_mangle] diff --git a/esp-wifi/src/lib.rs b/esp-wifi/src/lib.rs index 5d8027bd037..7b0b2262d44 100644 --- a/esp-wifi/src/lib.rs +++ b/esp-wifi/src/lib.rs @@ -9,13 +9,12 @@ #![allow(unknown_lints)] #![allow(non_local_definitions)] +extern crate alloc; + // MUST be the first module mod fmt; -use core::{cell::RefCell, mem::MaybeUninit, ptr::addr_of_mut}; - use common_adapter::{chip_specific::phy_mem_init, init_radio_clock_control, RADIO_CLOCKS}; -use critical_section::Mutex; use esp_hal as hal; #[cfg(not(feature = "esp32"))] use esp_hal::timer::systimer::Alarm; @@ -25,7 +24,6 @@ use hal::{ system::RadioClockController, timer::{timg::Timer as TimgTimer, ErasedTimer, PeriodicTimer}, }; -use linked_list_allocator::Heap; #[cfg(feature = "wifi")] use wifi::WifiError; @@ -73,12 +71,6 @@ const DEFAULT_TICK_RATE_HZ: u32 = 50; #[cfg(not(debug_assertions))] const DEFAULT_TICK_RATE_HZ: u32 = 100; -#[cfg(not(coex))] -const DEFAULT_HEAP_SIZE: usize = 81920; - -#[cfg(coex)] -const DEFAULT_HEAP_SIZE: usize = 90112; - #[derive(Debug)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] #[toml_cfg::toml_config] @@ -112,8 +104,6 @@ struct Config { country_code_operating_class: u8, #[default(1492)] mtu: usize, - #[default(DEFAULT_HEAP_SIZE)] - heap_size: usize, #[default(DEFAULT_TICK_RATE_HZ)] tick_rate_hz: u32, #[default(3)] @@ -140,20 +130,6 @@ const _: () = { core::assert!(CONFIG.rx_ba_win < (CONFIG.static_rx_buf_num * 2), "WiFi configuration check: rx_ba_win should not be larger than double of the static_rx_buf_num!"); }; -const HEAP_SIZE: usize = crate::CONFIG.heap_size; - -#[cfg_attr(esp32, link_section = ".dram2_uninit")] -static mut HEAP_DATA: [MaybeUninit; HEAP_SIZE] = [MaybeUninit::uninit(); HEAP_SIZE]; - -pub(crate) static HEAP: Mutex> = Mutex::new(RefCell::new(Heap::empty())); - -fn init_heap() { - critical_section::with(|cs| { - HEAP.borrow_ref_mut(cs) - .init_from_slice(unsafe { &mut *addr_of_mut!(HEAP_DATA) as &mut [MaybeUninit] }) - }); -} - type TimeBase = PeriodicTimer<'static, ErasedTimer>; #[derive(Debug, PartialEq, PartialOrd)] @@ -320,7 +296,6 @@ pub fn initialize( crate::common_adapter::chip_specific::enable_wifi_power_domain(); - init_heap(); phy_mem_init(); init_radio_clock_control(radio_clocks); init_rng(rng); diff --git a/esp-wifi/src/wifi/os_adapter.rs b/esp-wifi/src/wifi/os_adapter.rs index dbb896b1abd..e2d9b2f66a7 100644 --- a/esp-wifi/src/wifi/os_adapter.rs +++ b/esp-wifi/src/wifi/os_adapter.rs @@ -905,7 +905,11 @@ pub unsafe extern "C" fn event_post( /// /// ************************************************************************* pub unsafe extern "C" fn get_free_heap_size() -> u32 { - critical_section::with(|cs| crate::HEAP.borrow_ref(cs).free() as u32) + extern "C" { + fn free_internal_heap() -> usize; + } + + free_internal_heap() as u32 } /// ************************************************************************** diff --git a/esp-wifi/tuning.md b/esp-wifi/tuning.md index c73625e1877..ec80d27e408 100644 --- a/esp-wifi/tuning.md +++ b/esp-wifi/tuning.md @@ -44,7 +44,6 @@ You can set the following settings |country_code|Country code. See [ESP-IDF Programming Guide](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-guides/wifi.html#wi-fi-country-code)| |country_code_operating_class|If not 0: Operating Class table number. See [ESP-IDF Programming Guide](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-guides/wifi.html#wi-fi-country-code)| |mtu|MTU, see [documentation](https://docs.rs/smoltcp/0.10.0/smoltcp/phy/struct.DeviceCapabilities.html#structfield.max_transmission_unit)| -|heap_size|Size of the WiFi/BLE heap in bytes| |tick_rate_hz|Tick rate of the internal task scheduler in hertz.| |listen_interval|Interval for station to listen to beacon from AP. The unit of listen interval is one beacon interval. For example, if beacon interval is 100 ms and listen interval is 3, the interval for station to listen to beacon is 300 ms| |beacon_timeout|For Station, If the station does not receive a beacon frame from the connected SoftAP during the inactive time, disconnect from SoftAP. Default 6s. Range 6-30| diff --git a/examples/src/bin/dma_extmem2mem.rs b/examples/src/bin/dma_extmem2mem.rs index 5f6ac7580da..69d9adf7bd6 100644 --- a/examples/src/bin/dma_extmem2mem.rs +++ b/examples/src/bin/dma_extmem2mem.rs @@ -7,6 +7,7 @@ #![no_main] use aligned::{Aligned, A64}; +use esp_alloc as _; use esp_backtrace as _; use esp_hal::{ delay::Delay, @@ -41,9 +42,6 @@ macro_rules! dma_alloc_buffer { }}; } -#[global_allocator] -static ALLOCATOR: esp_alloc::EspHeap = esp_alloc::EspHeap::empty(); - fn init_heap(psram: impl esp_hal::peripheral::Peripheral

) { esp_hal::psram::init_psram(psram); info!( @@ -51,10 +49,11 @@ fn init_heap(psram: impl esp_hal::peripheral::Peripheral

! { config }); + esp_alloc::heap_allocator!(72 * 1024); + let delay = Delay::new(); let timg0 = TimerGroup::new(peripherals.TIMG0); diff --git a/examples/src/bin/wifi_access_point.rs b/examples/src/bin/wifi_access_point.rs index 2673feecff0..d4171d51edf 100644 --- a/examples/src/bin/wifi_access_point.rs +++ b/examples/src/bin/wifi_access_point.rs @@ -14,6 +14,7 @@ #![no_main] use embedded_io::*; +use esp_alloc as _; use esp_backtrace as _; use esp_hal::{prelude::*, rng::Rng, timer::timg::TimerGroup}; use esp_println::{print, println}; @@ -40,6 +41,8 @@ fn main() -> ! { config }); + esp_alloc::heap_allocator!(72 * 1024); + let timg0 = TimerGroup::new(peripherals.TIMG0); let init = initialize( diff --git a/examples/src/bin/wifi_access_point_with_sta.rs b/examples/src/bin/wifi_access_point_with_sta.rs index ece68d13a1a..4417621cb49 100644 --- a/examples/src/bin/wifi_access_point_with_sta.rs +++ b/examples/src/bin/wifi_access_point_with_sta.rs @@ -15,6 +15,7 @@ #![no_main] use embedded_io::*; +use esp_alloc as _; use esp_backtrace as _; use esp_hal::{prelude::*, rng::Rng, timer::timg::TimerGroup}; use esp_println::{print, println}; @@ -47,6 +48,8 @@ fn main() -> ! { config }); + esp_alloc::heap_allocator!(72 * 1024); + let timg0 = TimerGroup::new(peripherals.TIMG0); let init = initialize( diff --git a/examples/src/bin/wifi_bench.rs b/examples/src/bin/wifi_bench.rs index f93e24f518d..ae9924840b2 100644 --- a/examples/src/bin/wifi_bench.rs +++ b/examples/src/bin/wifi_bench.rs @@ -14,6 +14,7 @@ #![no_main] use embedded_io::*; +use esp_alloc as _; use esp_backtrace as _; use esp_hal::{delay::Delay, prelude::*, rng::Rng, timer::timg::TimerGroup}; use esp_println::println; @@ -57,6 +58,8 @@ fn main() -> ! { config }); + esp_alloc::heap_allocator!(72 * 1024); + let server_address: Ipv4Address = HOST_IP.parse().expect("Invalid HOST_IP address"); let timg0 = TimerGroup::new(peripherals.TIMG0); diff --git a/examples/src/bin/wifi_ble.rs b/examples/src/bin/wifi_ble.rs index 11a9a55644f..dfbf3690c32 100644 --- a/examples/src/bin/wifi_ble.rs +++ b/examples/src/bin/wifi_ble.rs @@ -22,6 +22,7 @@ use bleps::{ Ble, HciConnector, }; +use esp_alloc as _; use esp_backtrace as _; use esp_hal::{ gpio::{Input, Io, Pull}, @@ -41,6 +42,8 @@ fn main() -> ! { config }); + esp_alloc::heap_allocator!(72 * 1024); + let timg0 = TimerGroup::new(peripherals.TIMG0); let init = initialize( diff --git a/examples/src/bin/wifi_coex.rs b/examples/src/bin/wifi_coex.rs index ee4097949ce..81aa0dbcd2f 100644 --- a/examples/src/bin/wifi_coex.rs +++ b/examples/src/bin/wifi_coex.rs @@ -25,6 +25,7 @@ use bleps::{ HciConnector, }; use embedded_io::*; +use esp_alloc as _; use esp_backtrace as _; use esp_hal::{prelude::*, rng::Rng, timer::timg::TimerGroup}; use esp_println::{print, println}; @@ -53,6 +54,8 @@ fn main() -> ! { config }); + esp_alloc::heap_allocator!(92 * 1024); + let timg0 = TimerGroup::new(peripherals.TIMG0); let init = initialize( diff --git a/examples/src/bin/wifi_dhcp.rs b/examples/src/bin/wifi_dhcp.rs index b2e8d0f665e..63006626a69 100644 --- a/examples/src/bin/wifi_dhcp.rs +++ b/examples/src/bin/wifi_dhcp.rs @@ -11,7 +11,10 @@ #![no_std] #![no_main] +extern crate alloc; + use embedded_io::*; +use esp_alloc as _; use esp_backtrace as _; use esp_hal::{prelude::*, rng::Rng, timer::timg::TimerGroup}; use esp_println::{print, println}; @@ -46,6 +49,8 @@ fn main() -> ! { config }); + esp_alloc::heap_allocator!(72 * 1024); + let timg0 = TimerGroup::new(peripherals.TIMG0); let init = initialize( diff --git a/examples/src/bin/wifi_embassy_access_point.rs b/examples/src/bin/wifi_embassy_access_point.rs index a47be1507f3..40ca47d6e3d 100644 --- a/examples/src/bin/wifi_embassy_access_point.rs +++ b/examples/src/bin/wifi_embassy_access_point.rs @@ -25,6 +25,7 @@ use embassy_net::{ StaticConfigV4, }; use embassy_time::{Duration, Timer}; +use esp_alloc as _; use esp_backtrace as _; use esp_hal::{prelude::*, rng::Rng, timer::timg::TimerGroup}; use esp_println::{print, println}; @@ -61,6 +62,8 @@ async fn main(spawner: Spawner) -> ! { config }); + esp_alloc::heap_allocator!(72 * 1024); + let timg0 = TimerGroup::new(peripherals.TIMG0); let init = initialize( diff --git a/examples/src/bin/wifi_embassy_access_point_with_sta.rs b/examples/src/bin/wifi_embassy_access_point_with_sta.rs index 3db855649ac..fa4aff52d96 100644 --- a/examples/src/bin/wifi_embassy_access_point_with_sta.rs +++ b/examples/src/bin/wifi_embassy_access_point_with_sta.rs @@ -28,6 +28,7 @@ use embassy_net::{ StaticConfigV4, }; use embassy_time::{Duration, Timer}; +use esp_alloc as _; use esp_backtrace as _; use esp_hal::{prelude::*, rng::Rng, timer::timg::TimerGroup}; use esp_println::{print, println}; @@ -69,6 +70,8 @@ async fn main(spawner: Spawner) -> ! { config }); + esp_alloc::heap_allocator!(72 * 1024); + let timg0 = TimerGroup::new(peripherals.TIMG0); let init = initialize( diff --git a/examples/src/bin/wifi_embassy_bench.rs b/examples/src/bin/wifi_embassy_bench.rs index 8ea9e44f2f0..b4b80b2b564 100644 --- a/examples/src/bin/wifi_embassy_bench.rs +++ b/examples/src/bin/wifi_embassy_bench.rs @@ -20,6 +20,7 @@ use embassy_executor::Spawner; use embassy_futures::join::join; use embassy_net::{tcp::TcpSocket, Ipv4Address, Stack, StackResources}; use embassy_time::{with_timeout, Duration, Timer}; +use esp_alloc as _; use esp_backtrace as _; use esp_hal::{prelude::*, rng::Rng, timer::timg::TimerGroup}; use esp_println::println; @@ -72,6 +73,8 @@ async fn main(spawner: Spawner) -> ! { config }); + esp_alloc::heap_allocator!(72 * 1024); + let server_address: Ipv4Address = HOST_IP.parse().expect("Invalid HOST_IP address"); let timg0 = TimerGroup::new(peripherals.TIMG0); diff --git a/examples/src/bin/wifi_embassy_ble.rs b/examples/src/bin/wifi_embassy_ble.rs index c8e7b0c04a8..d70d3414c17 100644 --- a/examples/src/bin/wifi_embassy_ble.rs +++ b/examples/src/bin/wifi_embassy_ble.rs @@ -25,6 +25,7 @@ use bleps::{ gatt, }; use embassy_executor::Spawner; +use esp_alloc as _; use esp_backtrace as _; use esp_hal::{ gpio::{Input, Io, Pull}, @@ -44,6 +45,8 @@ async fn main(_spawner: Spawner) -> ! { config }); + esp_alloc::heap_allocator!(72 * 1024); + let timg0 = TimerGroup::new(peripherals.TIMG0); let init = initialize( diff --git a/examples/src/bin/wifi_embassy_dhcp.rs b/examples/src/bin/wifi_embassy_dhcp.rs index 7e668f726a8..8ded2c40791 100644 --- a/examples/src/bin/wifi_embassy_dhcp.rs +++ b/examples/src/bin/wifi_embassy_dhcp.rs @@ -16,6 +16,7 @@ use embassy_executor::Spawner; use embassy_net::{tcp::TcpSocket, Ipv4Address, Stack, StackResources}; use embassy_time::{Duration, Timer}; +use esp_alloc as _; use esp_backtrace as _; use esp_hal::{prelude::*, rng::Rng, timer::timg::TimerGroup}; use esp_println::println; @@ -55,6 +56,8 @@ async fn main(spawner: Spawner) -> ! { config }); + esp_alloc::heap_allocator!(72 * 1024); + let timg0 = TimerGroup::new(peripherals.TIMG0); let init = initialize( diff --git a/examples/src/bin/wifi_embassy_esp_now.rs b/examples/src/bin/wifi_embassy_esp_now.rs index 03ea884b087..50bae0cc716 100644 --- a/examples/src/bin/wifi_embassy_esp_now.rs +++ b/examples/src/bin/wifi_embassy_esp_now.rs @@ -13,6 +13,7 @@ use embassy_executor::Spawner; use embassy_futures::select::{select, Either}; use embassy_time::{Duration, Ticker}; +use esp_alloc as _; use esp_backtrace as _; use esp_hal::{prelude::*, rng::Rng, timer::timg::TimerGroup}; use esp_println::println; @@ -31,6 +32,8 @@ async fn main(_spawner: Spawner) -> ! { config }); + esp_alloc::heap_allocator!(72 * 1024); + let timg0 = TimerGroup::new(peripherals.TIMG0); let init = initialize( diff --git a/examples/src/bin/wifi_embassy_esp_now_duplex.rs b/examples/src/bin/wifi_embassy_esp_now_duplex.rs index 66b241af1ad..cf63ba1dea9 100644 --- a/examples/src/bin/wifi_embassy_esp_now_duplex.rs +++ b/examples/src/bin/wifi_embassy_esp_now_duplex.rs @@ -13,6 +13,7 @@ use embassy_executor::Spawner; use embassy_sync::{blocking_mutex::raw::NoopRawMutex, mutex::Mutex}; use embassy_time::{Duration, Ticker}; +use esp_alloc as _; use esp_backtrace as _; use esp_hal::{prelude::*, rng::Rng, timer::timg::TimerGroup}; use esp_println::println; @@ -41,6 +42,8 @@ async fn main(spawner: Spawner) -> ! { config }); + esp_alloc::heap_allocator!(72 * 1024); + let timg0 = TimerGroup::new(peripherals.TIMG0); let init = initialize( diff --git a/examples/src/bin/wifi_esp_now.rs b/examples/src/bin/wifi_esp_now.rs index 83ebd654716..51432b49260 100644 --- a/examples/src/bin/wifi_esp_now.rs +++ b/examples/src/bin/wifi_esp_now.rs @@ -8,6 +8,7 @@ #![no_std] #![no_main] +use esp_alloc as _; use esp_backtrace as _; use esp_hal::{prelude::*, rng::Rng, timer::timg::TimerGroup}; use esp_println::println; @@ -27,6 +28,8 @@ fn main() -> ! { config }); + esp_alloc::heap_allocator!(72 * 1024); + let timg0 = TimerGroup::new(peripherals.TIMG0); let init = initialize( diff --git a/examples/src/bin/wifi_sniffer.rs b/examples/src/bin/wifi_sniffer.rs index 49746548f59..99837ea5113 100644 --- a/examples/src/bin/wifi_sniffer.rs +++ b/examples/src/bin/wifi_sniffer.rs @@ -17,7 +17,6 @@ use alloc::{ use core::cell::RefCell; use critical_section::Mutex; -use esp_alloc::heap_allocator; use esp_backtrace as _; use esp_hal::{ prelude::*, @@ -39,8 +38,7 @@ fn main() -> ! { config }); - // Create a heap allocator, with 32kB of space. - heap_allocator!(32_168); + esp_alloc::heap_allocator!(72 * 1024); let timg0 = TimerGroup::new(peripherals.TIMG0); let timer0: ErasedTimer = timg0.timer0.into(); diff --git a/examples/src/bin/wifi_static_ip.rs b/examples/src/bin/wifi_static_ip.rs index bd546d388ef..4f544626bf7 100644 --- a/examples/src/bin/wifi_static_ip.rs +++ b/examples/src/bin/wifi_static_ip.rs @@ -13,6 +13,7 @@ #![no_main] use embedded_io::*; +use esp_alloc as _; use esp_backtrace as _; use esp_hal::{prelude::*, rng::Rng, timer::timg::TimerGroup}; use esp_println::{print, println}; @@ -46,6 +47,8 @@ fn main() -> ! { config }); + esp_alloc::heap_allocator!(72 * 1024); + let timg0 = TimerGroup::new(peripherals.TIMG0); let init = initialize( From 54f35372a528c39410305abf93aa2e7f980bfe13 Mon Sep 17 00:00:00 2001 From: bjoernQ Date: Fri, 6 Sep 2024 11:34:05 +0200 Subject: [PATCH 2/8] CHANGELOG.md --- esp-alloc/CHANGELOG.md | 2 +- esp-wifi/CHANGELOG.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/esp-alloc/CHANGELOG.md b/esp-alloc/CHANGELOG.md index e2701d9f103..4ce4d03b19c 100644 --- a/esp-alloc/CHANGELOG.md +++ b/esp-alloc/CHANGELOG.md @@ -11,7 +11,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed -- a global allocator is created in esp-alloc, now you need to add individual memory regions (up to 3) to the allocator +- a global allocator is created in esp-alloc, now you need to add individual memory regions (up to 3) to the allocator (#2099) ### Fixed diff --git a/esp-wifi/CHANGELOG.md b/esp-wifi/CHANGELOG.md index c9b0d0d0b43..b85f9612de8 100644 --- a/esp-wifi/CHANGELOG.md +++ b/esp-wifi/CHANGELOG.md @@ -12,7 +12,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Added `have-strchr` feature to disable including `strchr` (#2096) ### Changed -- esp-wifi now allocates memory from the global allocator defined by esp-alloc +- esp-wifi now allocates memory from the global allocator provided by `esp-alloc` (#2099) ### Fixed From 56b844e510adb124233c28c924e022f4130bd6a8 Mon Sep 17 00:00:00 2001 From: bjoernQ Date: Fri, 6 Sep 2024 11:45:34 +0200 Subject: [PATCH 3/8] Apply suggestions --- esp-alloc/src/lib.rs | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/esp-alloc/src/lib.rs b/esp-alloc/src/lib.rs index 70f1677cb40..130f5da8109 100644 --- a/esp-alloc/src/lib.rs +++ b/esp-alloc/src/lib.rs @@ -94,6 +94,14 @@ pub struct HeapRegion { impl HeapRegion { /// Create a new [HeapRegion] with the given capabilities + /// + /// # Safety + /// + /// - The supplied memory region must be available for the entire program + /// (`'static`). + /// - The supplied memory region must be exclusively available to the heap + /// only, no aliasing. + /// - `size > 0`. pub unsafe fn new( heap_bottom: *mut u8, size: usize, @@ -230,6 +238,13 @@ impl EspHeap { } /// Allocate memory in a region satisfying the given requirements. + /// + /// # Safety + /// + /// This function is unsafe because undefined behavior can result + /// if the caller does not ensure that `layout` has non-zero size. + /// + /// The allocated block of memory may or may not be initialized. pub unsafe fn alloc_caps( &self, capabilities: EnumSet, @@ -279,13 +294,9 @@ unsafe impl GlobalAlloc for EspHeap { let mut regions = self.heap.borrow_ref_mut(cs); let mut iter = (*regions).iter_mut(); - loop { - if let Some(Some(region)) = iter.next() { - if region.heap.bottom() <= ptr && region.heap.top() >= ptr { - region.heap.deallocate(NonNull::new_unchecked(ptr), layout); - } - } else { - break; + while let Some(Some(region)) = iter.next() { + if region.heap.bottom() <= ptr && region.heap.top() >= ptr { + region.heap.deallocate(NonNull::new_unchecked(ptr), layout); } } }) From fe54c71dce9e4cef70626f88fc7373e678904299 Mon Sep 17 00:00:00 2001 From: bjoernQ Date: Fri, 6 Sep 2024 12:06:09 +0200 Subject: [PATCH 4/8] Use `alloc` when linting esp-wifi --- xtask/src/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xtask/src/main.rs b/xtask/src/main.rs index 3f9f223c27e..6514c2c80e5 100644 --- a/xtask/src/main.rs +++ b/xtask/src/main.rs @@ -667,7 +667,7 @@ fn lint_packages(workspace: &Path, args: LintPackagesArgs) -> Result<()> { lint_package( &path, &[ - "-Zbuild-std=core", + "-Zbuild-std=core,alloc", &format!("--target={}", chip.target()), "--no-default-features", &features, From 7e9b76080a3302d09984694fd3a73118843af399 Mon Sep 17 00:00:00 2001 From: bjoernQ Date: Fri, 6 Sep 2024 14:33:55 +0200 Subject: [PATCH 5/8] Make coex example build for ESP32 --- examples/src/bin/wifi_coex.rs | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/examples/src/bin/wifi_coex.rs b/examples/src/bin/wifi_coex.rs index 81aa0dbcd2f..2820d219a57 100644 --- a/examples/src/bin/wifi_coex.rs +++ b/examples/src/bin/wifi_coex.rs @@ -54,7 +54,25 @@ fn main() -> ! { config }); - esp_alloc::heap_allocator!(92 * 1024); + static mut HEAP: core::mem::MaybeUninit<[u8; 72 * 1024]> = core::mem::MaybeUninit::uninit(); + + #[link_section = ".dram2_uninit"] + static mut HEAP2: core::mem::MaybeUninit<[u8; 64 * 1024]> = core::mem::MaybeUninit::uninit(); + + unsafe { + esp_alloc::INSTANCE.add_region(esp_alloc::HeapRegion::new( + HEAP.as_mut_ptr() as *mut u8, + core::mem::size_of_val(&*core::ptr::addr_of!(HEAP)), + esp_alloc::MemoryCapability::Internal.into(), + )); + + // COEX needs more RAM - add some more + esp_alloc::INSTANCE.add_region(esp_alloc::HeapRegion::new( + HEAP2.as_mut_ptr() as *mut u8, + core::mem::size_of_val(&*core::ptr::addr_of!(HEAP2)), + esp_alloc::MemoryCapability::Internal.into(), + )); + } let timg0 = TimerGroup::new(peripherals.TIMG0); From eb4eec6a5156e04bdd1da97fa329fe6527249403 Mon Sep 17 00:00:00 2001 From: bjoernQ Date: Fri, 6 Sep 2024 14:52:30 +0200 Subject: [PATCH 6/8] Re-enable some wifi examples for ESP32-S2 --- examples/Cargo.toml | 2 +- examples/src/bin/wifi_embassy_access_point.rs | 2 +- .../bin/wifi_embassy_access_point_with_sta.rs | 2 +- examples/src/bin/wifi_embassy_bench.rs | 22 +++++++++++++++++-- examples/src/bin/wifi_embassy_dhcp.rs | 2 +- examples/src/bin/wifi_embassy_esp_now.rs | 2 +- .../src/bin/wifi_embassy_esp_now_duplex.rs | 2 +- 7 files changed, 26 insertions(+), 8 deletions(-) diff --git a/examples/Cargo.toml b/examples/Cargo.toml index eeb9e384ac2..c7c22dd935e 100644 --- a/examples/Cargo.toml +++ b/examples/Cargo.toml @@ -14,7 +14,7 @@ cfg-if = "1.0.0" critical-section = "1.1.2" crypto-bigint = { version = "0.5.5", default-features = false } elliptic-curve = { version = "0.13.8", default-features = false, features = ["sec1"] } -embassy-executor = { version = "0.6.0", features = ["task-arena-size-40960"] } +embassy-executor = { version = "0.6.0", features = ["task-arena-size-12288"] } embassy-futures = "0.1.1" embassy-net = { version = "0.4.0", features = [ "tcp", "udp", "dhcpv4", "medium-ethernet"] } embassy-sync = "0.6.0" diff --git a/examples/src/bin/wifi_embassy_access_point.rs b/examples/src/bin/wifi_embassy_access_point.rs index 40ca47d6e3d..43879decc2f 100644 --- a/examples/src/bin/wifi_embassy_access_point.rs +++ b/examples/src/bin/wifi_embassy_access_point.rs @@ -9,7 +9,7 @@ //! Because of the huge task-arena size configured this won't work on ESP32-S2 //% FEATURES: embassy embassy-generic-timers esp-wifi esp-wifi/async esp-wifi/embassy-net esp-wifi/wifi-default esp-wifi/wifi esp-wifi/utils -//% CHIPS: esp32 esp32s3 esp32c2 esp32c3 esp32c6 +//% CHIPS: esp32 esp32s2 esp32s3 esp32c2 esp32c3 esp32c6 #![no_std] #![no_main] diff --git a/examples/src/bin/wifi_embassy_access_point_with_sta.rs b/examples/src/bin/wifi_embassy_access_point_with_sta.rs index fa4aff52d96..de9cf87b50a 100644 --- a/examples/src/bin/wifi_embassy_access_point_with_sta.rs +++ b/examples/src/bin/wifi_embassy_access_point_with_sta.rs @@ -12,7 +12,7 @@ //! Because of the huge task-arena size configured this won't work on ESP32-S2 //% FEATURES: embassy embassy-generic-timers esp-wifi esp-wifi/async esp-wifi/embassy-net esp-wifi/wifi-default esp-wifi/wifi esp-wifi/utils -//% CHIPS: esp32 esp32s3 esp32c2 esp32c3 esp32c6 +//% CHIPS: esp32 esp32s2 esp32s3 esp32c2 esp32c3 esp32c6 #![no_std] #![no_main] diff --git a/examples/src/bin/wifi_embassy_bench.rs b/examples/src/bin/wifi_embassy_bench.rs index b4b80b2b564..6917c9baffe 100644 --- a/examples/src/bin/wifi_embassy_bench.rs +++ b/examples/src/bin/wifi_embassy_bench.rs @@ -11,7 +11,7 @@ //! //% FEATURES: embassy embassy-generic-timers esp-wifi esp-wifi/async esp-wifi/embassy-net esp-wifi/wifi-default esp-wifi/wifi esp-wifi/utils -//% CHIPS: esp32 esp32s3 esp32c3 esp32c6 +//% CHIPS: esp32 esp32s2 esp32s3 esp32c3 esp32c6 #![no_std] #![no_main] @@ -73,7 +73,25 @@ async fn main(spawner: Spawner) -> ! { config }); - esp_alloc::heap_allocator!(72 * 1024); + static mut HEAP: core::mem::MaybeUninit<[u8; 32 * 1024]> = core::mem::MaybeUninit::uninit(); + + #[link_section = ".dram2_uninit"] + static mut HEAP2: core::mem::MaybeUninit<[u8; 64 * 1024]> = core::mem::MaybeUninit::uninit(); + + unsafe { + esp_alloc::INSTANCE.add_region(esp_alloc::HeapRegion::new( + HEAP.as_mut_ptr() as *mut u8, + core::mem::size_of_val(&*core::ptr::addr_of!(HEAP)), + esp_alloc::MemoryCapability::Internal.into(), + )); + + // add some more RAM + esp_alloc::INSTANCE.add_region(esp_alloc::HeapRegion::new( + HEAP2.as_mut_ptr() as *mut u8, + core::mem::size_of_val(&*core::ptr::addr_of!(HEAP2)), + esp_alloc::MemoryCapability::Internal.into(), + )); + } let server_address: Ipv4Address = HOST_IP.parse().expect("Invalid HOST_IP address"); diff --git a/examples/src/bin/wifi_embassy_dhcp.rs b/examples/src/bin/wifi_embassy_dhcp.rs index 8ded2c40791..bc4237cb997 100644 --- a/examples/src/bin/wifi_embassy_dhcp.rs +++ b/examples/src/bin/wifi_embassy_dhcp.rs @@ -8,7 +8,7 @@ //! Because of the huge task-arena size configured this won't work on ESP32-S2 //% FEATURES: embassy embassy-generic-timers esp-wifi esp-wifi/async esp-wifi/embassy-net esp-wifi/wifi-default esp-wifi/wifi esp-wifi/utils -//% CHIPS: esp32 esp32s3 esp32c2 esp32c3 esp32c6 +//% CHIPS: esp32 esp32s2 esp32s3 esp32c2 esp32c3 esp32c6 #![no_std] #![no_main] diff --git a/examples/src/bin/wifi_embassy_esp_now.rs b/examples/src/bin/wifi_embassy_esp_now.rs index 50bae0cc716..a81d714cd8e 100644 --- a/examples/src/bin/wifi_embassy_esp_now.rs +++ b/examples/src/bin/wifi_embassy_esp_now.rs @@ -5,7 +5,7 @@ //! Because of the huge task-arena size configured this won't work on ESP32-S2 //% FEATURES: embassy embassy-generic-timers esp-wifi esp-wifi/async esp-wifi/embassy-net esp-wifi/wifi-default esp-wifi/wifi esp-wifi/utils esp-wifi/esp-now -//% CHIPS: esp32 esp32s3 esp32c2 esp32c3 esp32c6 +//% CHIPS: esp32 esp32s2 esp32s3 esp32c2 esp32c3 esp32c6 #![no_std] #![no_main] diff --git a/examples/src/bin/wifi_embassy_esp_now_duplex.rs b/examples/src/bin/wifi_embassy_esp_now_duplex.rs index cf63ba1dea9..060c58215f1 100644 --- a/examples/src/bin/wifi_embassy_esp_now_duplex.rs +++ b/examples/src/bin/wifi_embassy_esp_now_duplex.rs @@ -5,7 +5,7 @@ //! Because of the huge task-arena size configured this won't work on ESP32-S2 //% FEATURES: embassy embassy-generic-timers esp-wifi esp-wifi/async esp-wifi/embassy-net esp-wifi/wifi-default esp-wifi/wifi esp-wifi/utils esp-wifi/esp-now -//% CHIPS: esp32 esp32s3 esp32c2 esp32c3 esp32c6 +//% CHIPS: esp32 esp32s2 esp32s3 esp32c2 esp32c3 esp32c6 #![no_std] #![no_main] From 674878147bc65588ab31ae199519dfc3e8cb30bc Mon Sep 17 00:00:00 2001 From: bjoernQ Date: Fri, 6 Sep 2024 15:35:35 +0200 Subject: [PATCH 7/8] Optionally depend on `esp-alloc` (by default) --- esp-alloc/src/lib.rs | 19 --------- esp-wifi/Cargo.toml | 73 +++++++++++++++++++++++++++++++-- esp-wifi/README.md | 32 --------------- esp-wifi/src/compat/malloc.rs | 23 ++++++++++- esp-wifi/src/lib.rs | 14 ++++++- esp-wifi/src/wifi/os_adapter.rs | 4 +- 6 files changed, 104 insertions(+), 61 deletions(-) diff --git a/esp-alloc/src/lib.rs b/esp-alloc/src/lib.rs index 130f5da8109..a7f5ad76d96 100644 --- a/esp-alloc/src/lib.rs +++ b/esp-alloc/src/lib.rs @@ -114,25 +114,6 @@ impl HeapRegion { } } -/// For esp-wifi -#[doc(hidden)] -#[no_mangle] -pub extern "C" fn free_internal_heap() -> usize { - INSTANCE.free_caps(MemoryCapability::Internal.into()) -} - -/// For esp-wifi -#[doc(hidden)] -#[no_mangle] -pub extern "C" fn allocate_from_internal_ram(size: usize) -> *mut u8 { - unsafe { - INSTANCE.alloc_caps( - MemoryCapability::Internal.into(), - Layout::from_size_align_unchecked(size, 4), - ) - } -} - /// A memory allocator /// /// In addition to what Rust's memory allocator can do it allows to allocate diff --git a/esp-wifi/Cargo.toml b/esp-wifi/Cargo.toml index 58b4412a0f6..8082e54c956 100644 --- a/esp-wifi/Cargo.toml +++ b/esp-wifi/Cargo.toml @@ -13,6 +13,8 @@ categories = ["embedded", "hardware-support", "no-std"] [dependencies] defmt = { version = "0.3.8", optional = true } +document-features = "0.2.10" +esp-alloc = { version = "0.4.0", path = "../esp-alloc", optional = true } esp-hal = { version = "0.20.0", path = "../esp-hal", default-features = false } esp-hal-embassy = { version = "0.3.0", path = "../esp-hal-embassy", default-features = false, optional = true } smoltcp = { version = "0.11.0", default-features = false, features = [ @@ -57,46 +59,59 @@ esp-build = { version = "0.1.0", path = "../esp-build" } esp-metadata = { version = "0.3.0", path = "../esp-metadata" } [features] -default = ["log"] +default = ["log", "esp-alloc"] -# chip features +## Use `esp-alloc` for dynamic allocations. +## +## If you opt-out you need to provide implementations for `pub extern "C" fn esp_wifi_free_internal_heap() -> usize` +## and `pub extern "C" fn esp_wifi_allocate_from_internal_ram(size: usize) -> *mut u8` +esp-alloc = ["dep:esp-alloc"] + +# Chip Support Feature Flags +# Target the ESP32-C2. esp32c2 = [ "esp-hal/esp32c2", "esp-hal-embassy?/esp32c2", "esp-wifi-sys/esp32c2", ] +# Target the ESP32-C3. esp32c3 = [ "esp-hal/esp32c3", "esp-hal-embassy?/esp32c3", "esp-wifi-sys/esp32c3", ] +# Target the ESP32-C6. esp32c6 = [ "esp-hal/esp32c6", "esp-hal-embassy?/esp32c6", "esp-wifi-sys/esp32c6", ] +# Target the ESP32-H2. esp32h2 = [ "esp-hal/esp32h2", "esp-hal-embassy?/esp32h2", "esp-wifi-sys/esp32h2", ] +# Target the ESP32. esp32 = [ "esp-hal/esp32", "esp-hal-embassy?/esp32", "esp-wifi-sys/esp32", ] +# Target the ESP32-S2. esp32s2 = [ "esp-hal/esp32s2", "esp-hal-embassy?/esp32s2", "esp-wifi-sys/esp32s2", ] +# Target the ESP32-S3. esp32s3 = [ "esp-hal/esp32s3", "esp-hal-embassy?/esp32s3", "esp-wifi-sys/esp32s3", ] -# async features +## Enable Async support async = [ "dep:embassy-sync", "dep:embassy-futures", @@ -105,34 +120,84 @@ async = [ "dep:bt-hci", ] +## Enable `embassy-net` support embassy-net = ["dep:embassy-net-driver", "async"] -# misc features +## Enable WiFi-BLE coexistence support coex = [] + +## Logs the WiFi logs from the driver at log level info (needs a nightly-compiler) wifi-logs = [] + +## Dumps packet info at log level info dump-packets = [] + +## Provide implementations of smoltcp traits smoltcp = ["dep:smoltcp"] + +## Provide utilities for smoltcp initialization. Adds smoltcp dependency utils = ["smoltcp"] + enumset = [] + +## Enable WiFi support wifi = ["dep:enumset", "dep:no-std-net"] + +## Implement the embedded-svc Wifi trait embedded-svc = ["dep:embedded-svc"] + +## Enable BLE support ble = ["esp-hal/bluetooth"] + +## See USB-SERIAL-JTAG below phy-enable-usb = [] + +## Enable minimum modem sleep. Only affects STA mode ps-min-modem = [] + +## Enable maximum modem sleep. Only affects STA mode ps-max-modem = [] + +## Enable esp-now support esp-now = ["wifi"] + +## IPv6 support. Includes utils feature ipv6 = ["wifi", "utils", "smoltcp?/proto-ipv6"] + +## IPv4 support. Includes utils feature ipv4 = ["wifi", "utils", "smoltcp?/proto-ipv4"] + +## TCP socket support. Includes ipv4 feature tcp = ["ipv4", "smoltcp?/socket-tcp"] + +## UDP socket support. Includes ipv4 feature udp = ["ipv4", "smoltcp?/socket-udp"] + +## ICMP socket support. Includes ipv4 feature icmp = ["ipv4", "smoltcp?/socket-icmp"] + +## IGMP (multicast) support. Includes ipv4 featu igmp = ["ipv4", "smoltcp?/proto-igmp"] + +## DNS support. Includes udp feature dns = ["udp", "smoltcp?/proto-dns", "smoltcp?/socket-dns"] + +## DHCPv4 support, both creating sockets and autoconfiguring network settings. Includes utils feature dhcpv4 = ["wifi", "utils", "smoltcp?/proto-dhcpv4", "smoltcp?/socket-dhcpv4"] + +## Convenience to enable "ipv4", "tcp", "udp", "icmp", "igmp", "dns", "dhcpv4" wifi-default = ["ipv4", "tcp", "udp", "icmp", "igmp", "dns", "dhcpv4"] + +## Enable support for `defmt` defmt = ["dep:defmt", "smoltcp?/defmt", "esp-hal/defmt"] + +## Enable support for the `log` crate log = ["dep:log", "esp-hal/log"] + +## Enable sniffer mode support sniffer = ["wifi"] + +# Don't include `strchr` - not shown in docs have-strchr = [] [package.metadata.docs.rs] diff --git a/esp-wifi/README.md b/esp-wifi/README.md index c7e9fa1501b..3b19baa4877 100644 --- a/esp-wifi/README.md +++ b/esp-wifi/README.md @@ -71,38 +71,6 @@ When using USB-SERIAL-JTAG (for example by selecting `jtag-serial` in [`esp-prin Don't use this feature if you are _not_ using USB-SERIAL-JTAG as it might reduce WiFi performance. -## Features - -| Feature | Meaning | -| -------------- | ---------------------------------------------------------------------------------------------------- | -| wifi-logs | logs the WiFi logs from the driver at log level `info` (needs a nightly-compiler) | -| wifi-default | A convenience feature to enable some reasonable defaults for wifi use. | -| dump-packets | dumps packet info at log level `info` | -| smoltcp | Provide implementations of `smoltcp` traits | -| utils | Provide utilities for smoltcp initialization. Adds `smoltcp` dependency | -| ble | Enable BLE support | -| wifi | Enable WiFi support | -| esp-now | Enable [esp-now](https://www.espressif.com/en/solutions/low-power-solutions/esp-now) support | -| coex | Enable WiFi-BLE coexistence support | -| ipv4 | IPv4 support. Includes `utils` feature | -| ipv6 | IPv6 support. Includes `utils` feature | -| tcp | TCP socket support. Includes `ipv4` feature | -| udp | UDP socket support. Includes `ipv4` feature | -| igmp | IGMP (multicast) support. Includes `ipv4` feature | -| dns | DNS support. Includes `udp` feature | -| dhcpv4 | DHCPv4 support, both creating sockets and autoconfiguring network settings. Includes `utils` feature | -| phy-enable-usb | See [USB-SERIAL-JTAG](#usb-serial-jtag) above | -| ps-min-modem | Enable minimum modem sleep. Only affects STA mode | -| ps-max-modem | Enable maximum modem sleep. Only affects STA mode | -| log | Route log output to the `log` crate | -| defmt | Add `defmt::Format` implementation and output logs via `defmt` | -| embedded-svc | Implement the embedded-svc Wifi trait | - -Note that not all features are available on every MCU. For example, `ble` (and thus, `coex`) is not available on ESP32-S2. - -When using the `dump-packets` feature you can use the extcap in `extras/esp-wifishark` to analyze the frames in Wireshark. -For more information see [extras/esp-wifishark/README.md](../extras/esp-wifishark/README.md) - ## Tuning The defaults used by `esp-wifi` and the examples are rather conservative. It is possible to change a few of the important settings. diff --git a/esp-wifi/src/compat/malloc.rs b/esp-wifi/src/compat/malloc.rs index ac5d58e1e08..ad536bd7841 100644 --- a/esp-wifi/src/compat/malloc.rs +++ b/esp-wifi/src/compat/malloc.rs @@ -7,10 +7,10 @@ pub unsafe extern "C" fn malloc(size: usize) -> *mut u8 { let total_size = size + 4; extern "C" { - fn allocate_from_internal_ram(size: usize) -> *mut u8; + fn esp_wifi_allocate_from_internal_ram(size: usize) -> *mut u8; } - let ptr = unsafe { allocate_from_internal_ram(total_size) }; + let ptr = unsafe { esp_wifi_allocate_from_internal_ram(total_size) }; if ptr.is_null() { warn!("Unable to allocate {} bytes", size); @@ -73,3 +73,22 @@ unsafe extern "C" fn realloc(ptr: *mut u8, new_size: usize) -> *mut u8 { p } } + +#[cfg(feature = "esp-alloc")] +#[doc(hidden)] +#[no_mangle] +pub extern "C" fn esp_wifi_free_internal_heap() -> usize { + esp_alloc::INSTANCE.free_caps(esp_alloc::MemoryCapability::Internal.into()) +} + +#[cfg(feature = "esp-alloc")] +#[doc(hidden)] +#[no_mangle] +pub extern "C" fn esp_wifi_allocate_from_internal_ram(size: usize) -> *mut u8 { + unsafe { + esp_alloc::INSTANCE.alloc_caps( + esp_alloc::MemoryCapability::Internal.into(), + core::alloc::Layout::from_size_align_unchecked(size, 4), + ) + } +} diff --git a/esp-wifi/src/lib.rs b/esp-wifi/src/lib.rs index 7b0b2262d44..66a495e850c 100644 --- a/esp-wifi/src/lib.rs +++ b/esp-wifi/src/lib.rs @@ -1,8 +1,18 @@ +//! # Features flags +//! +//! Note that not all features are available on every MCU. For example, `ble` +//! (and thus, `coex`) is not available on ESP32-S2. +//! +//! When using the `dump-packets` feature you can use the extcap in +//! `extras/esp-wifishark` to analyze the frames in Wireshark. +//! For more information see +//! [extras/esp-wifishark/README.md](../extras/esp-wifishark/README.md) +#![doc = document_features::document_features!(feature_label = r#"{feature}"#)] +#![doc = include_str!("../README.md")] +#![doc(html_logo_url = "https://avatars.githubusercontent.com/u/46717278")] #![no_std] #![cfg_attr(target_arch = "xtensa", feature(asm_experimental_arch))] #![cfg_attr(any(feature = "wifi-logs", nightly), feature(c_variadic))] -#![doc = include_str!("../README.md")] -#![doc(html_logo_url = "https://avatars.githubusercontent.com/u/46717278")] #![allow(rustdoc::bare_urls)] // allow until num-derive doesn't generate this warning anymore (unknown_lints because Xtensa // toolchain doesn't know about that lint, yet) diff --git a/esp-wifi/src/wifi/os_adapter.rs b/esp-wifi/src/wifi/os_adapter.rs index e2d9b2f66a7..b45a2276d03 100644 --- a/esp-wifi/src/wifi/os_adapter.rs +++ b/esp-wifi/src/wifi/os_adapter.rs @@ -906,10 +906,10 @@ pub unsafe extern "C" fn event_post( /// ************************************************************************* pub unsafe extern "C" fn get_free_heap_size() -> u32 { extern "C" { - fn free_internal_heap() -> usize; + fn esp_wifi_free_internal_heap() -> usize; } - free_internal_heap() as u32 + esp_wifi_free_internal_heap() as u32 } /// ************************************************************************** From b4d498db191340d81943d88e4b828e521dc26fb1 Mon Sep 17 00:00:00 2001 From: bjoernQ Date: Fri, 6 Sep 2024 17:28:36 +0200 Subject: [PATCH 8/8] Rename INSTANCE -> HEAP --- esp-alloc/src/lib.rs | 4 ++-- esp-alloc/src/macros.rs | 4 ++-- esp-wifi/src/compat/malloc.rs | 4 ++-- examples/src/bin/dma_extmem2mem.rs | 2 +- examples/src/bin/psram_octal.rs | 2 +- examples/src/bin/psram_quad.rs | 2 +- examples/src/bin/wifi_coex.rs | 4 ++-- examples/src/bin/wifi_embassy_bench.rs | 4 ++-- 8 files changed, 13 insertions(+), 13 deletions(-) diff --git a/esp-alloc/src/lib.rs b/esp-alloc/src/lib.rs index a7f5ad76d96..c3c6c7f0009 100644 --- a/esp-alloc/src/lib.rs +++ b/esp-alloc/src/lib.rs @@ -72,7 +72,7 @@ use linked_list_allocator::Heap; /// The global allocator instance #[global_allocator] -pub static INSTANCE: EspHeap = EspHeap::empty(); +pub static HEAP: EspHeap = EspHeap::empty(); const NON_REGION: Option = None; @@ -157,7 +157,7 @@ impl EspHeap { /// - `size > 0`. pub unsafe fn add_region(&self, region: HeapRegion) { critical_section::with(|cs| { - let mut regions = INSTANCE.heap.borrow_ref_mut(cs); + let mut regions = self.heap.borrow_ref_mut(cs); let free = regions .iter() .enumerate() diff --git a/esp-alloc/src/macros.rs b/esp-alloc/src/macros.rs index e53be94e6cb..47d9c454fa4 100644 --- a/esp-alloc/src/macros.rs +++ b/esp-alloc/src/macros.rs @@ -8,7 +8,7 @@ macro_rules! heap_allocator { static mut HEAP: core::mem::MaybeUninit<[u8; $size]> = core::mem::MaybeUninit::uninit(); unsafe { - $crate::INSTANCE.add_region($crate::HeapRegion::new( + $crate::HEAP.add_region($crate::HeapRegion::new( HEAP.as_mut_ptr() as *mut u8, $size, $crate::MemoryCapability::Internal.into(), @@ -33,7 +33,7 @@ macro_rules! psram_allocator { use $psram_module as _psram; _psram::init_psram($peripheral); unsafe { - $crate::INSTANCE.add_region($crate::HeapRegion::new( + $crate::HEAP.add_region($crate::HeapRegion::new( _psram::psram_vaddr_start() as *mut u8, _psram::PSRAM_BYTES, $crate::MemoryCapability::External.into(), diff --git a/esp-wifi/src/compat/malloc.rs b/esp-wifi/src/compat/malloc.rs index ad536bd7841..be4eb3ccc2a 100644 --- a/esp-wifi/src/compat/malloc.rs +++ b/esp-wifi/src/compat/malloc.rs @@ -78,7 +78,7 @@ unsafe extern "C" fn realloc(ptr: *mut u8, new_size: usize) -> *mut u8 { #[doc(hidden)] #[no_mangle] pub extern "C" fn esp_wifi_free_internal_heap() -> usize { - esp_alloc::INSTANCE.free_caps(esp_alloc::MemoryCapability::Internal.into()) + esp_alloc::HEAP.free_caps(esp_alloc::MemoryCapability::Internal.into()) } #[cfg(feature = "esp-alloc")] @@ -86,7 +86,7 @@ pub extern "C" fn esp_wifi_free_internal_heap() -> usize { #[no_mangle] pub extern "C" fn esp_wifi_allocate_from_internal_ram(size: usize) -> *mut u8 { unsafe { - esp_alloc::INSTANCE.alloc_caps( + esp_alloc::HEAP.alloc_caps( esp_alloc::MemoryCapability::Internal.into(), core::alloc::Layout::from_size_align_unchecked(size, 4), ) diff --git a/examples/src/bin/dma_extmem2mem.rs b/examples/src/bin/dma_extmem2mem.rs index 69d9adf7bd6..1fb0081f631 100644 --- a/examples/src/bin/dma_extmem2mem.rs +++ b/examples/src/bin/dma_extmem2mem.rs @@ -49,7 +49,7 @@ fn init_heap(psram: impl esp_hal::peripheral::Peripheral

! { static mut HEAP2: core::mem::MaybeUninit<[u8; 64 * 1024]> = core::mem::MaybeUninit::uninit(); unsafe { - esp_alloc::INSTANCE.add_region(esp_alloc::HeapRegion::new( + esp_alloc::HEAP.add_region(esp_alloc::HeapRegion::new( HEAP.as_mut_ptr() as *mut u8, core::mem::size_of_val(&*core::ptr::addr_of!(HEAP)), esp_alloc::MemoryCapability::Internal.into(), )); // COEX needs more RAM - add some more - esp_alloc::INSTANCE.add_region(esp_alloc::HeapRegion::new( + esp_alloc::HEAP.add_region(esp_alloc::HeapRegion::new( HEAP2.as_mut_ptr() as *mut u8, core::mem::size_of_val(&*core::ptr::addr_of!(HEAP2)), esp_alloc::MemoryCapability::Internal.into(), diff --git a/examples/src/bin/wifi_embassy_bench.rs b/examples/src/bin/wifi_embassy_bench.rs index 6917c9baffe..7eaa1997e71 100644 --- a/examples/src/bin/wifi_embassy_bench.rs +++ b/examples/src/bin/wifi_embassy_bench.rs @@ -79,14 +79,14 @@ async fn main(spawner: Spawner) -> ! { static mut HEAP2: core::mem::MaybeUninit<[u8; 64 * 1024]> = core::mem::MaybeUninit::uninit(); unsafe { - esp_alloc::INSTANCE.add_region(esp_alloc::HeapRegion::new( + esp_alloc::HEAP.add_region(esp_alloc::HeapRegion::new( HEAP.as_mut_ptr() as *mut u8, core::mem::size_of_val(&*core::ptr::addr_of!(HEAP)), esp_alloc::MemoryCapability::Internal.into(), )); // add some more RAM - esp_alloc::INSTANCE.add_region(esp_alloc::HeapRegion::new( + esp_alloc::HEAP.add_region(esp_alloc::HeapRegion::new( HEAP2.as_mut_ptr() as *mut u8, core::mem::size_of_val(&*core::ptr::addr_of!(HEAP2)), esp_alloc::MemoryCapability::Internal.into(),