mirror of
https://github.com/esp-rs/esp-hal.git
synced 2025-09-29 21:30:39 +00:00
Move the esp-alloc
package into the repository (#1449)
This commit is contained in:
parent
2a750dfedc
commit
3c2dccd51c
@ -2,6 +2,7 @@
|
||||
resolver = "2"
|
||||
members = ["xtask"]
|
||||
exclude = [
|
||||
"esp-alloc",
|
||||
"esp-build",
|
||||
"esp-hal",
|
||||
"esp-hal-procmacros",
|
||||
|
@ -56,7 +56,6 @@ There are a number of other crates within the [esp-rs organization] which can be
|
||||
|
||||
| Crate | Description |
|
||||
| :--------------: | :----------------------------------------------------------------------------: |
|
||||
| [esp-alloc] | A simple `no_std` heap allocator |
|
||||
| [esp-backtrace] | Backtrace support for bare-metal applications |
|
||||
| [esp-ieee802154] | Low-level IEEE802.15.4 driver for the ESP32-C6 and ESP32-H2 |
|
||||
| [esp-openthread] | A bare-metal Thread implementation using `esp-ieee802154` |
|
||||
|
29
esp-alloc/Cargo.toml
Normal file
29
esp-alloc/Cargo.toml
Normal file
@ -0,0 +1,29 @@
|
||||
[package]
|
||||
name = "esp-alloc"
|
||||
version = "0.3.0"
|
||||
edition = "2021"
|
||||
rust-version = "1.68"
|
||||
description = "A heap allocator for Espressif devices"
|
||||
repository = "https://github.com/esp-rs/esp-hal"
|
||||
license = "MIT OR Apache-2.0"
|
||||
|
||||
keywords = [
|
||||
"allocator",
|
||||
"esp32",
|
||||
"riscv",
|
||||
"xtensa",
|
||||
]
|
||||
categories = [
|
||||
"memory-management",
|
||||
"no-std",
|
||||
]
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
default-target = "riscv32imc-unknown-none-elf"
|
||||
|
||||
[dependencies]
|
||||
critical-section = "1.1.1"
|
||||
linked_list_allocator = { version = "0.10.5", default-features = false, features = ["const_mut_refs"] }
|
||||
|
||||
[features]
|
||||
nightly = []
|
26
esp-alloc/README.md
Normal file
26
esp-alloc/README.md
Normal file
@ -0,0 +1,26 @@
|
||||
# esp-alloc
|
||||
|
||||

|
||||
[](https://crates.io/crates/esp-alloc)
|
||||
[](https://docs.rs/esp-alloc)
|
||||

|
||||

|
||||
|
||||
A simple `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.
|
||||
|
||||
## License
|
||||
|
||||
Licensed under either of:
|
||||
|
||||
- Apache License, Version 2.0 ([LICENSE-APACHE](../LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0)
|
||||
- MIT license ([LICENSE-MIT](../LICENSE-MIT) or http://opensource.org/licenses/MIT)
|
||||
|
||||
at your option.
|
||||
|
||||
### Contribution
|
||||
|
||||
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in
|
||||
the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without
|
||||
any additional terms or conditions.
|
160
esp-alloc/src/lib.rs
Normal file
160
esp-alloc/src/lib.rs
Normal file
@ -0,0 +1,160 @@
|
||||
//! A simple `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();
|
||||
//!
|
||||
//! 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);
|
||||
//! }
|
||||
//! }
|
||||
//! ```
|
||||
//!
|
||||
//! # 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,
|
||||
//! which allows you to specify an allocator for single allocations.
|
||||
//!
|
||||
//! **NOTE:** To use this, you have to enable the create's `nightly` feature
|
||||
//! flag.
|
||||
//!
|
||||
//! Create and initialize an allocator to use in single allocations:
|
||||
//! ```rust
|
||||
//! static PSRAM_ALLOCATOR: esp_alloc::EspHeap = esp_alloc::EspHeap::empty();
|
||||
//!
|
||||
//! fn init_psram_heap() {
|
||||
//! unsafe {
|
||||
//! PSRAM_ALLOCATOR.init(psram::psram_vaddr_start() as *mut u8, psram::PSRAM_BYTES);
|
||||
//! }
|
||||
//! }
|
||||
//! ```
|
||||
//!
|
||||
//! And then use it in an allocation:
|
||||
//! ```rust
|
||||
//! let large_buffer: Vec<u8, _> = Vec::with_capacity_in(1048576, &PSRAM_ALLOCATOR);
|
||||
//! ```
|
||||
|
||||
#![no_std]
|
||||
#![cfg_attr(feature = "nightly", feature(allocator_api))]
|
||||
|
||||
pub mod macros;
|
||||
|
||||
#[cfg(feature = "nightly")]
|
||||
use core::alloc::{AllocError, Allocator};
|
||||
use core::{
|
||||
alloc::{GlobalAlloc, Layout},
|
||||
cell::RefCell,
|
||||
ptr::{self, NonNull},
|
||||
};
|
||||
|
||||
use critical_section::Mutex;
|
||||
use linked_list_allocator::Heap;
|
||||
|
||||
pub struct EspHeap {
|
||||
heap: Mutex<RefCell<Heap>>,
|
||||
}
|
||||
|
||||
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 {
|
||||
EspHeap {
|
||||
heap: Mutex::new(RefCell::new(Heap::empty())),
|
||||
}
|
||||
}
|
||||
|
||||
/// Initializes the heap
|
||||
///
|
||||
/// This function must be called BEFORE you run any code that makes use of
|
||||
/// the allocator.
|
||||
///
|
||||
/// `heap_bottom` is a pointer to the location of the bottom of the heap.
|
||||
///
|
||||
/// `size` is the size of the heap in bytes.
|
||||
///
|
||||
/// Note that:
|
||||
///
|
||||
/// - The heap grows "upwards", towards larger addresses. Thus `end_addr`
|
||||
/// must be larger than `start_addr`
|
||||
///
|
||||
/// - The size of the heap is `(end_addr as usize) - (start_addr as usize)`.
|
||||
/// The allocator won't use the byte at `end_addr`.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// Obey these or Bad Stuff will happen.
|
||||
///
|
||||
/// - 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));
|
||||
}
|
||||
|
||||
/// Returns an estimate of the amount of bytes in use.
|
||||
pub fn used(&self) -> usize {
|
||||
critical_section::with(|cs| self.heap.borrow(cs).borrow_mut().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())
|
||||
}
|
||||
}
|
||||
|
||||
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())
|
||||
})
|
||||
}
|
||||
|
||||
unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
|
||||
critical_section::with(|cs| {
|
||||
self.heap
|
||||
.borrow(cs)
|
||||
.borrow_mut()
|
||||
.deallocate(NonNull::new_unchecked(ptr), layout)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "nightly")]
|
||||
unsafe impl Allocator for EspHeap {
|
||||
fn allocate(&self, layout: Layout) -> Result<NonNull<[u8]>, 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()))
|
||||
})
|
||||
}
|
||||
|
||||
unsafe fn deallocate(&self, ptr: NonNull<u8>, layout: Layout) {
|
||||
self.dealloc(ptr.as_ptr(), layout);
|
||||
}
|
||||
}
|
41
esp-alloc/src/macros.rs
Normal file
41
esp-alloc/src/macros.rs
Normal file
@ -0,0 +1,41 @@
|
||||
//! 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
|
||||
#[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);
|
||||
}
|
||||
}};
|
||||
}
|
||||
|
||||
/// Create a heap allocator backed by PSRAM
|
||||
///
|
||||
/// You can only have ONE allocator at most. 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.
|
||||
///
|
||||
/// # Usage
|
||||
/// ```no_run
|
||||
/// esp_alloc::psram_allocator!(peripherals.PSRAM, hal::psram);
|
||||
/// ```
|
||||
#[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);
|
||||
}
|
||||
}};
|
||||
}
|
@ -22,7 +22,7 @@ embedded-hal-async = "1.0.0"
|
||||
embedded-hal-bus = "0.1.0"
|
||||
embedded-io-async = "0.6.1"
|
||||
embedded-can = "0.4.1"
|
||||
esp-alloc = "0.3.0"
|
||||
esp-alloc = { version = "0.3.0", path = "../esp-alloc" }
|
||||
esp-backtrace = { version = "0.11.1", features = ["exception-handler", "panic-handler", "println"] }
|
||||
esp-hal = { version = "0.16.0", path = "../esp-hal", features = ["log"] }
|
||||
esp-hal-smartled = { version = "0.9.0", path = "../esp-hal-smartled", optional = true }
|
||||
|
Loading…
x
Reference in New Issue
Block a user