本篇主要内容Embassy1. Task arena1.1 Attention: we set the arena size to the sum of sizes of all tasks.1.2 Attention: we can set arena size in two ways2. Executor2.1 Attention the executor-interrupt particularly in cortex-M3. Attribute Macros3.1 Attention: we can spawn multiple task from the same function by setting the pool_size4. what is const generic and how we use?5.additional part for previous blog:5.1 note the type, don’t be messed up6. Embassy Bookcortex-m pac1. Interrupt Vector Table2. the Attributes:2.1 Intro2.2 the Attribute Macros2.3 Attribute Macro cortex_m_rt::exceptionSyntaxUsageDrone RTOS1.Memory Allocation1.1 we need the platform module and stream module1.2 with heap we can do more thing like smart pointer1.3 problem: we need heap! macro
本篇主要内容
本篇主要聚焦于与开发过程中相关的一些其他的软件项目
Embassy
1. Task arena
1.1 Attention: we set the arena size to the sum of sizes of all tasks.
When the
nightly
Cargo feature is not enabled, embassy-executor
allocates tasks out of an arena (a very simple bump allocator).
If the task arena gets full, the program will panic at runtime. To guarantee this doesn’t happen, you must set the size to the sum of sizes of all tasks.1.2 Attention: we can set arena size in two ways
The arena size can be configured in two ways:
- Via Cargo features: enable a Cargo feature like
task-arena-size-8192
. Only a selection of values is available, see Task Area Sizes for reference.
- Via environment variables at build time: set the variable named
EMBASSY_EXECUTOR_TASK_ARENA_SIZE
. For exampleEMBASSY_EXECUTOR_TASK_ARENA_SIZE=4321 cargo build
. You can also set them in the[env]
section of.cargo/config.toml
. Any value can be set, unlike with Cargo features.
Environment variables take precedence over Cargo features. If two Cargo features are enabled for the same setting with different values, compilation fails.
2. Executor
2.1 Attention the executor-interrupt particularly in cortex-M
executor-thread
— Enable the thread-mode executor (using WFE/SEV in Cortex-M, WFI in other embedded archs)
executor-interrupt
— Enable the interrupt-mode executor (available in Cortex-M only)
3. Attribute Macros
3.1 Attention: we can spawn multiple task from the same function by setting the pool_size
- main
Creates a new
executor
instance and declares an application entry point for Cortex-M spawning the corresponding function body as an async task.- task
Declares an async task that can be run by
embassy-executor
. The optional pool_size
parameter can be used to specify how many concurrent tasks can be spawned (default is 1) for the function.4. what is const generic and how we use?
5.additional part for previous blog:
5.1 note the type, don’t be messed up
from embassy-executor/src/raw/mod.rs:189
Note the parameter future is not what we thought of future. In fact it’s return is what
future
in rust is, which is generic type F who implement the Future trait.And so we found that
self.task.future.write_in_place(future);
, who’s write_in_place
function is critical:from embassy-executor/src/raw/util.rs:5
note that what the
write_in_place
does is just call the func(in our example is the future parameter who implement the FnOnce() → T trait). So actually we write the return future which truly implement Future trait into the UninitCell
, which in our example is future member of TaskStorage: from embassy-executor/src/raw/mod.rs:104
6. Embassy Book
cortex-m pac
1. Interrupt Vector Table
cortex-m-rt
: Startup code and interrupt handling2. the Attributes:
2.1 Intro
This crate also provides the following attributes:
#[entry]
to declare the entry point of the program
#[exception]
to override an exception handler. If not overridden all exception handlers default to an infinite loop.
#[pre_init]
to run code beforestatic
variables are initialized
This crate also implements a related attribute called
#[interrupt]
, which allows you to define interrupt handlers. However, since which interrupts are available depends on the microcontroller in use, this attribute should be re-exported and used from a device crate.
The documentation for these attributes can be found in the Attribute Macros section.2.2 the Attribute Macros
entry: Attribute to declare the entry point of the program
exception: Attribute to declare an exception handler
interrupt: Attribute to declare an interrupt (AKA device-specific exception) handler
pre_init: Attribute to mark which function will be called at the beginning of the reset handler.
2.3 Attribute Macro cortex_m_rt::exception
Syntax
where the name of the function must be one of:
DefaultHandler
NonMaskableInt
HardFault
MemoryManagement
(a)
BusFault
(a)
UsageFault
(a)
SecureFault
(b)
SVCall
DebugMonitor
(a)
PendSV
SysTick
(a) Not available on Cortex-M0 variants (
thumbv6m-none-eabi
)(b) Only available on ARMv8-M
Usage
#[exception] unsafe fn HardFault(..
sets the hard fault handler. The handler must have signature unsafe fn(&ExceptionFrame) -> !
. This handler is not allowed to return as that can cause undefined behavior.#[exception] unsafe fn DefaultHandler(..
sets the default handler. All exceptions which have not been assigned a handler will be serviced by this handler. This handler must have signature unsafe fn(irqn: i16) [-> !]
. irqn
is the IRQ number (See CMSIS); irqn
will be a negative number when the handler is servicing a core exception; irqn
will be a positive number when the handler is servicing a device specific exception (interrupt).#[exception] fn Name(..
overrides the default handler for the exception with the given Name
. These handlers must have signature [unsafe] fn() [-> !]
. When overriding these other exception it’s possible to add state to them by declaring static mut
variables at the beginning of the body of the function. These variables will be safe to access from the function body.Drone RTOS
Some reference about the research of RTOS in rust:https://arewertosyet.com/
we need two repo, the file directory is:
drone
drone-os • Updated Jul 25, 2024
drone-core
drone-os • Updated Sep 23, 2024
we reference from the drone book:https://book.drone-os.com/introduction.html
1.Memory Allocation
Dynamic memory is crucial for Drone operation. Objectives like real-time characteristics, high concurrency, small code size, fast execution have led to Memory Pools design of the heap. All operations are lock-free and have O(1) time complexity, which means they are deterministic.
The continuous memory region for the heap is split into pools. A pool is further split into fixed-sized blocks that hold actual allocations. A pool is defined by its block-size and the number of blocks. The pools configuration should be defined in the compile-time. A drawback of this approach is that memory pools may need to be tuned for the application.
Using empiric values for the memory pools layout may lead to undesired memory fragmentation. Eventually the layout will need to be tuned for the application. Drone can capture allocation statistics from the real target device at the run-time and generate an optimized memory layout for this specific application. Ideally this will result in zero fragmentation.
The actual steps are platform-specific. Refer to the platform crate documentation for instructions.
1.1 we need the platform module and stream module
To adapt our structure, I decide to add it to helper directory, the whole structure like this:
and to use stream, I have to import it’s dependency—
drone_stream
directly into the mod.rs
finally our project like this(I omit the other parts that not belonged to our adapt of Drone):
1.2 with heap we can do more thing like smart pointer
1.3 problem: we need heap! macro
according to the api doc:
we need to use the macro heap, which is a
proc-macro (1)proc-macro
of rust, we have to know it’s grammar:you should know workspace:
As the macro in drone is so poor in designing, I give up port it to my project. So I try to construct a global allocator myself.
there is my reference:
When I implementing the allocator above, as it discussed, we also need linked list to optimize our design:
I leave the tutorial’s linked list example, but still use the
linked_list_allocator
crate because of the merge of freed blocks.