Detect potential race condition (should be rare) and return false back
to caller, allowing them to handle the possibility that either the
alarm was never set because it was in the past (old meaning of false),
or that in fact the alarm was set and may have fired within the race
window (new meaning of false). In either case, the caller needs to
make sure the callback got called.
Based off an example, noting what to copy, what to change and why
Briefly summarizing how to require embassy crates via github
All steps tested and proven working at the time of writing
New: delaying_a_task.adoc, copied as-is from the wiki and placed in the
navigation until we have a better place for it (or remove/replace it)
index: Tweaked the structure, added some content from the wiki, and made
some general copy edits to improve clarity.
getting_started.adoc: Corrected various out-of-date information, added
troubleshooting tips from the wiki, added some new information, various
other small edits.
basic_application.adoc: Corrected out-of-date information, various clarifications
and edits.
After these changes, IMO most of the content on the github wiki is no longer
necessary and can be removed for clarity. The few sections I didn‘t integrate
or copy over were either out of date or unfinished.
This is a detail I didn't originally understand when hoping to use TIM16/17 as alternative embassy-time driver providers.
Adding my note here to hopefully save the next person a little time.
- Removes the slow "updating crates.io index, updating git" at start of the job.
- Avoids CI being randomly slower if a widely-used dep (like serde) gets bumped causing rebuilding everything.
see e.g. STM32H503 RM section 15.4.4...
1. Write 1 into GPDMA_CxCR.SUSP
2. Poll GPDMA_CxSR.SUSPF until it is 1
3. Write 1 into GPDMA_CxCR.RESET (occurs upon next init, in new_inner())
Previously, because DHCP DISCOVER is sent before the link is
established, socket has to timeout first. Which takes extra 10 s.
Now if the state of the link changed to up, socket is explicitly reset
so the DISCOVER is repeated much earlier and DHCP configuration is
acquired much faster.
Update the start and stop flags for all read/write/read_write methods to match
those in the default blocking implementation of these methods (as well as
other RP2040 I2C implementations, and expected I2C behavior).
Also adds a write_read_async method that doesnt require using embedded-hal, as
this is required to use I2C in an idiomatic fashion (see TI Application Report
SLVA704).
The RP2040 datasheet indicates that I2C pins should have a limited
slew rate (Page 440 - 4.3.1.3.). This configures that for both
`I2c` and `I2cSlave`.
In addition, the pin configuration has been centralized to a single
fn.
Previously, PHY addressing was a concern of the `Ethernet` struct
which limited the `PHY` implementations which very often have to manage
multiple PHYs internally and thus possibly need to address many of them.
This change extends `StationManagement` to allow addressing different
PHY addresses via SMI.
This commit allows STM32U5 devices to operate at 160 MHz.
On STM32U5, MSIS can run at 48 MHz and HSE can reach 50 MHz. Faster
clocks require using PLL1's R output, though PLL1 can serve other
functions besides using the R output for the system clock. This commit
extracts a public `PllConfig` struct, primarily to place associated
constructors on that type, but also with an eye towards enabling the P
and Q outputs in a later commit.
STM32U5 PLLs have various frequency requirements on each stage: after
the `m` prescaler, after the `n` multiplier, and after the `r` divider.
This commit implements the associated checks as assertions.
This commit fixes clock calculation and PLL register configuration
errors in PLL initialization.
STM32U5 has a PWR peripheral which can be configured to push Vcore into
different voltage ranges. System clocks exceeding 55 MHz require range
2, and system clocks exceeding 110 MHz require range 1. This commit
adds `voltage_range` to `Config` and configures PWR as directed.
The voltage range implies different performance limits on various clock
signals, including inside a PLL. This commit implements voltage range
<-> frequency range checks as assertions, and extracts the
otherwise-repeated MSIS, HSI16, and HSE initialization into private
methods on `Config`.
STM32U5 frequencies above 55 MHz require using the PWR EPOD booster.
The EPOD booster requires configuring a second `m` term for PLL1,
`mboost`, such that it falls in a particular range. (Recall that >50
MHz cannot be reached without PLL1, so there is no scenario where EPOD
is needed but PLL1 is not.) This commit configures and enables the EPOD
booster automatically as required.
They're heavily spamming logs for HIL tests, and I don't believe
they're valuable now that the thing they helped debug in their young
age is now solid and mature.
This struct allows users to acquire the current time without putting `Rtc`
in a mutex and passing that around. This is allowed because reading from the
rtc registers is atomic.
Move i2c to mod, split device and controller
Remove mode generic:
I don't think it's reasonable to use the i2c in device mode while
blocking, so I'm cutting the generic.
This implements SPIM TX workaround suggested from section 3.8.1
from Anomaly 109 addendum.
In workaround case we first keep track of original maxcnt values,
then initiate "fake" transfer with zero-length maxcnt values.
Once the "fake" transfer is triggered, we handle it, fill in the
original maxcnt values and restart the transmission.
If no data was available to read then the loop would wait for an interrupt and skip to the next chunk without writing the current one.
This could cause the given slice to only be partially filled with random data.
Fixed by moving the wait to before actually writing data to the chunk.
The example spins too fast so it doesn't appear to change;
it's delaying for microseconds instead of milliseconds.
This commit slows it down and adds a comment noting the pin
mapping for the Adafruit feather rp2040+RFM95 LoRA module,
which has its Neopixel on pin 4 instead of 16.
The application can append FSC to outgoing packets and the MAC can detect
and report when a bitflip has occurred.
But the MAC can also add FSC if we want, but we can´t do both.
When adding FSC by the application and MAC results in the packet drop by
the MAC when the TX packet size > (MTU - 4).
Having the application append the FSC is preferred.
So set the right config bits.
read_fifo() used part of the frame buffer to readout non-frame data.
This results in incorrect readout of the fifo buffer but also the full
MTU could not be used.
Also added some more tests to check this and that the readout is a
multipule of 4 bytes.
Now this function uses frame data directly in the SPI transaction
instead making a copy of it.
Also fixing some length calculations and refactor/add tests to test this
function.
I like program with deny(clippy::pedantic) but it was set as allowed, so
I did get less linting errors/hints. Now it is corrected and also fix
the lint errors and hints.
Also fixes some comment and demagic some values.
Rename `FEC` to more appropriate name `FSC`.
Setting the compare_value to max_compare_value make the PWM output
go low when the timer reach the max_compare_value and go high again
on the next timer clock, when the value roll back to 0.
So to allow a 100% PWM that never goes low, the compare_value must
be set to max_compare_value + 1.
This refactoring of the chip specific bootloader creates the internal boot instance and aligned
buffer in the prepare stage, so that they are automatically dropped after. This unlocks a use
case where peripherals owning the flash need to be Drop'ed before load() happens.
This allows normal linux terminal emulators, like screen or picocom
to be used with the usb_logger. Without this, calling `tcsetattr` with
`TCSAFLUSH` will hang.
* Allow manipulating state without accessing DFU partition.
* Provide aligned buffer when creating updater to reduce potential wrong parameters passed.
this is "generic" in that it doesn't require the user to set up anything
specific to go to dormant sleep, unlike the C sdk which requires clock
sources to be configured explicitly and doesn't much care about PLLs. we
will instead take a snapshot of the current clock configuration, switch
to a known clock source (very slow rosc, in this case), go to sleep, and
on wakeup undo everything we've done (ensuring stability of PLLs and
such).
tested locally, but adding tests to HIL seems infeasible. we'd need at
least another pico or extensive modifications to teleprobe since
dormant-sleep breaks SWD (except to rescue-dp), neither of which is
feasible at this point. if we *did* want to add tests we should check
for both rtc wakeups (with an external rtc clock source) and gpio wakeups.
GP29 is connected to the cyw43 SCK pin. cyw43 is selected by
default (due to rp2040 pins being input/pulldown by default), so the
wifi chip is always selected and watches the SCK pin. this little bit of
load on the SCK pin is enough to disturb the 300k voltage divider used
for VSYS sensing, making the test flaky.
this temporarily takes ownership of pins because we need to clear edge
interrupts before waiting for them (otherwise we may wait indefinitely),
we want to clean up the dormant-wake bits after a wakeup, and doing
anything *else* with the input while we're waiting for a wakeup isn't
possible at all. doing it like this lets us not impose any cost on those
who don't use dormant wakes without entangling dormant waits too badly
with regular interrupt waits.
with uniform treatment of adc inputs it's easy enough to add a new
sampling method. dma sampling only supports one channel at the moment,
though round-robin sampling would be a simple extension (probably a new
trait that's implemented for Channel and &[Channel]). continuous dma as
proposed in #1608 also isn't done here, we'd expect that to be a
compound dma::Channel that internally splits a buffer in half and
dispatches callbacks or something like that.
this lets us treat pins and the temperature sensor uniformly using the
same interface. uniformity in turn lets us add more adc features without
combinatorial explosion of methods and types needed to handle them all.
so far only bank0 interrupts were processed and configured, even if a
qspi pin was given. this is obviously not the right thing to do, so
let's rectify that. the fact that no problems have shown up so far does
suggest that most, if not all, applications don't use this functionality
at all.
this will be mostly not useful to anyone since flash is attached to
qspi, and using flash chips that don't use the *entire* qspi interface
will severly slow down the chip. the code overhead is minimal right now,
but if we also fix interrupt support on qspi pins this will
change (adding more code to potentially hot paths, using more memory for
wakers that are never used, and preventing the qspi gpio irq from being
used in software interrupts as RTIC applications may want to do).
we'll need access to the pin io bank registers for an upcoming fix, and
having both `io` and `io_bank` or similar can get confusing quickly.
rename `io` to `gpio` to avoid this, and also match the type while there.
With a large enough HSE input frequency, the vco clock calculation will
overflow a u32. Therefore, in this specific case we have to use the
inner value and cast to u64 to ensure the mul isn't clipped before
applying the divider.
this removed the RelocatedProgram construction step from pio uses.
there's not all that much to be said for the extra step because the
origin can be set on the input program itself, and the remaining
information exposed by RelocatedProgram can be exposed from
LoadedProgram instead (even though it's already available on the pio_asm
programs, albeit perhaps less convenient). we do lose access to the
relocated instruction iterator, but we also cannot think of anything
this iterator would actually be useful for outside of program loading.
This makes rtt output work right when using `cargo run` in release mode.
Debug was already enabled for release builds in some of the examples but
not all.
Make sure that the ptr() function for ROM functions always returns
the actual ROM pointer. This allows the use of flash I/O while the
function cache is enabled.
This provides a helper function with an async implementation, that
will only return (or error) when it was able to read that many bytes,
sleeping until ready.
Additionally, corrected the documentation for Ringbuffer functions to use
"elements" instead of "bytes" as the types were already generic over the
word/element size.
The DAC driver defaults to enabling the channel trigger, but leaves it
at the default value of TIM6 TRGO, then performs a software trigger
after writing the new output value. We could change the trigger
selection to software trigger, but for this example it's simpler to just
disable the trigger.
using these will require some linker script intervention. setting the
core0 stack needs linker intervention anyway (to provide _stack_start),
having it also provide _stack_end for the guard to use is not that much
of a stretch.
the region field of the register is four bits wide followed by the valid
bit that causes the rnr update we rely on for the rasr write. 0x08 is
just a bit short to reach the valid bit, and since rp2040 has only 8
regions it (at best) doesn't do anything at all.
the adc constantly pulls a small but significant amount of current while
the hardware is enabled. this can have quite an effect on sleeping
devices that also use the adc.
Change embassy-rp i2c.rs impl of embedded_hal_async::i2c::I2c::transaction
to only do the call to setup() for address once per call to transactions.
Calling setup multiple times results in I2C transactions being skipped
on the bus, even across calls to transaction() or devices.
* Add clippy allow to not report if same then branch
* Support enabling RTC clock on STM32WL
* Add clippy allow to not report if same then branch
* Support enabling RTC clock on STM32WL
* Add rtc example for stm32wl
* Address code review feedback
- don't require an irq binding for blocking-only adc
- abstract adc pins into an AnyPin like interface, erasing the actual
peripheral type at runtime.
- add pull-up/pull-down functions for adc pins
- add a test (mostly a copy of the example, to be honest)
- configure adc pads according to datasheet
- report conversion errors (although they seem exceedingly rare?)
- drop embedded-hal interfaces. embedded-hal channels can do neither
AnyPin nor pullup/pulldown without encoding both into the type
Otherwise you can create multiple drivers on the same singleton like this:
```rust
let mut input = Input::new(&pin, Pull::None);
let mut output = Output::new(&pin, Level::Low, Speed::Low);
input.is_high();
output.set_high();
input.is_high();
output.set_high();
```
Thanks @pennae for reporting.
CI was not building the a.rs application due to the requirement of b.bin
having been built first. Add a feature flag to examples so that CI can
build them including a dummy application.
Update a.rs application examples so that they compile again.
- Move typelevel interrupts to a special-purpose mod: `embassy_xx::interrupt::typelevel`.
- Reexport the PAC interrupt enum in `embassy_xx::interrupt`.
This has a few advantages:
- The `embassy_xx::interrupt` module is now more "standard".
- It works with `cortex-m` functions for manipulating interrupts, for example.
- It works with RTIC.
- the interrupt enum allows holding value that can be "any interrupt at runtime", this can't be done with typelevel irqs.
- When "const-generics on enums" is stable, we can remove the typelevel interrupts without disruptive changes to `embassy_xx::interrupt`.
The regular one permanently requests HFCLK, while the low power one only does
so while counting, for 1 clock cycle. The regular mode is "deprecated" too.
1480: stm32: Async flash support for F4 r=rmja a=rmja
This PR depends on https://github.com/embassy-rs/embassy/pull/1478.
It adds async write/erase operations to the F4 series based on the work in https://github.com/embassy-rs/embassy/pull/870 but aligned to the new flash regions.
If one considers the entire `Flash` then nothing has changed other than the async operations have been added.
Co-authored-by: Rasmus Melchior Jacobsen <rmja@laesoe.org>
1487: rp: Implement embedded_hal::serial::Write for Uart/UartTx r=Dirbaio a=Alpha-3
Uart/UartTx currently implements `embedded_hal_02::serial::Read<u8>` and `embedded_hal_02::blocking::serial::Write<u8>` but not `embedded_hal_02::serial::Write<u8>`.
This implements the missing `embedded_hal_02::serial::Write<u8>` to allow use of Uart with crates that expect this interface, such as [defmt_serial](https://docs.rs/defmt-serial/latest/defmt_serial/).
Co-authored-by: Alpha3__0 <Alpha3.0gmail.com>
1485: Align with updated stm32 metapac r=Dirbaio a=rmja
This now depends on https://github.com/embassy-rs/stm32-data/pull/192 as it seems that ppre1 is using the enum, but ppre2 does not.
Please have a good look at this. I do not have a G4 chip so I cannot verify this change.
Co-authored-by: Rasmus Melchior Jacobsen <rmja@laesoe.org>
1471: embassy-net: Make TcpSocket::abort() async r=Dirbaio a=mkj
This lets callers ensure that the reset packet is sent to the remote host. Otherwise there isn't a way to wait for the smoltcp stack to send the reset.
Requires changes to smoltcp to wake after the reset has been sent, see https://github.com/smoltcp-rs/smoltcp/compare/master...mkj:smoltcp:abort-wake
This commit also adds a "TCP accept" demo of the problem. Without the `.await` for abort() it gets dropped before the RST packet is emitted.
Co-authored-by: Matt Johnston <matt@ucc.asn.au>
The oidc token is only valid for 5min, builds are starting to fail because HIL tests
take more than 5 min and we only obtain it once at start.
Instead of fixing it, let's remove it. My hope for OIDC was to allow running
HIL tests on PRs from forks if the author is in a list of trusted users.
However GHA simply doesn't give the ID token to PRs from forks. 🤷
Same limitation as with static tokens. So it's useless complexity, let's kill it.
1475: Add YieldingAsync adapter r=Dirbaio a=rmja
This PR calls `yield_now()` for long blocking `NorFlash` read and erase operations.
The motivation for this change is to allow for other tasks on the same executor to get something done between these long running operations, for example a task that feeds a watchdog. This will allow the watchdog to have a timer relative to e.g. one sector erase, instead of all sector erase.
1478: stm32: Minor fixes in flash regions for F4 dual bank layout r=Dirbaio a=rmja
This PR has the following fixes:
* Ensure that `FlashRegion` instances can only be created within the embassy-stm32 crate.
* Remove `Drop` trait for `AltFlashLayout`, as it is hard to use, as one cannot take the individual regions out from the struct. Instead of going back to single bank mode on `Drop`, we instead transition to single bank mode when calling `Flash::into_regions()`.
* Add missing `otp_region` to the dual bank layout and implement `NorFlash` for the alternate regions.
1482: Add ConcatFlash utility r=Dirbaio a=rmja
This PR adds a `ConcatFlash` utility that can be used to concatenate two `NorFlash` flashes. This is especially useful when concatenating multiple flash regions with unequal erase size.
Co-authored-by: Rasmus Melchior Jacobsen <rmja@laesoe.org>
1340: Add I2S for f4 r=Dirbaio a=xoviat
This is only for f4, but it puts us equal to or ahead of the standard rust hal.
1474: stm32: Fix watchdog timeout computation r=Dirbaio a=rmja
Co-authored-by: xoviat <xoviat@users.noreply.github.com>
Co-authored-by: Rasmus Melchior Jacobsen <rmja@laesoe.org>
1477: embassy-embedded-hal: Add i2c transaction to I2cDevice r=Dirbaio a=CBJamo
Not sure why this was a todo before, but this seems to be working fine in my limited testing.
Co-authored-by: Caleb Jamison <caleb@hellbender.com>
1457: TL Mbox read and write for stm32wb r=xoviat a=OueslatiGhaith
Hello,
This pull request is related to #1397 and #1401, inspired by #24, built upon the work done in #1405 and #1424, and was tested on an stm32wb55rg.
This pull request aims to add read and write functionality to the TL mailbox for stm32wb microcontrollers
Co-authored-by: goueslati <ghaith.oueslati@habemus.com>
Co-authored-by: xoviat <xoviat@users.noreply.github.com>
1473: Protect default implementations for FirmwareUpdater and BootLoader r=lulf a=rmja
It seems as if the arm compiler can does not care about whether the bootloader symbols are undefined if the default() function is never used. The x64 compiler does care however, so this change ensures that we can instantiate the types from tests.
Co-authored-by: Rasmus Melchior Jacobsen <rmja@laesoe.org>
It seems as if the arm compiler can does not care about whether the bootloader symbols are undefined if the default() function is never used. The x64 compiler does care however, so this change ensures that we can instantiate the types from tests.
1440: rp: Pin fix, improve fifo handling r=Dirbaio a=CBJamo
Went to actually use this code and found two issues:
* The config for the pins got dropped in the shuffle.
* I found that when using more than one ws2812, only the first would get data. I'm pretty sure the data was shifted out before the task got back to push the next word. So now the fifo gets filled, then we wait.
Co-authored-by: Caleb Jamison <caleb@cbjamo.com>
Co-authored-by: Caleb Jamison <caleb@hellbender.com>
1463: Allow for an optional user-defined entry macro when targeting RISC-V r=Dirbaio a=jessebraham
In [esp-hal](https://github.com/esp-rs/esp-hal) we use our own custom runtime crate, [esp-riscv-rt](https://github.com/esp-rs/esp-riscv-rt). This PR adds the ability to optionally specify an entry macro when using `embassy_executor::main`. The following forms are both accepted:
```rust
#[embassy_executor::main] // uses `riscv_rt::entry` by default
async fn main() {}
#[embassy_executor::main(entry = "esp_riscv_rt::entry")]
async fn main() {}
```
I attempted to get this working without needing to quote the entry macro argument, however I was not able to get this working. Based off some reading I did this may not be possible, however I am rather inexperienced with proc macros. Happy to change this if anybody has any insight.
Co-authored-by: Jesse Braham <jesse@beta7.io>
1465: rp: continue clock rework r=Dirbaio a=pennae
vastly reduce the code size of initial clock config (over 700 bytes saved!), at the cost of about 48 bytes of ram used to store the frequencies of all clocks in the system. also stop exporting unstable pac items for clock config, fix a few settings that were out of spec, and add missing features (most notably gpin source information).
Co-authored-by: pennae <github@quasiparticle.net>
gpin clock sources aren't going to be very useful during cold boot and
thus require runtime clock reconfig. once we get there we can use this
for reference. or maybe we can't, only time will tell.
we'll take static ownership of an entire pin (not just a limited
reference), otherwise we cannot at all guarantee that the pin will not
be reused for something else while still in use. in theory we could
limit the liftime of this use, but that would require attaching
lifetimes to ClockConfig (and subsequently the main config), passing
those through init(), and returning an object that undoes the gpin
configuration on drop. that's a lot unnecessary support code while we
don't have runtime clock reconfig.
don't recalculate clock frequencies every time they are asked for. while
this is not very often in practice it does consume a bunch of flash
space that cannot be optimized away, and was pulled in unconditionally
previously. while we technically only need the configured rosc, xosc and
gpin frequencies it is easier to store all frequencies (and much cheaper
at runtime too).
if rosc really does run at 140MHz in high at div=1 then these values
were not correct and would've exceeded the chip spec. the HIL test
device seems to run fast (150MHz) so they're still not quite correct,
but rosc has high variance anyway so it's probably fine.
exposing pac items kind of undermines the unstable-pac feature. directly
exposing register structure is also pretty inconvenient since the clock
switching code takes care of the src/aux difference in behavior, so a
user needn't really be forced to write down decomposed register values.
the datasheet says that the xosc may be run by feeding a square wave
into the XIN pin of the chip, but requires that the oscillator be set to
pass through XIN in that case. it does not mention how, the xosc
peripheral does not seem to have any config bits that could be set to
this effect, and pico-sdk seems to have no (or at least no special)
handling for this configuration at all. it can thus be assumed to either
be not supported even by the reference sdk or to not need different
handling.
solvers usually output fbdiv directly, using vco_freq to get back to
fbdiv is not all that necessary or useful. both vco_freq and fbdiv have
hidden constraints, but vco_freq is a lot less accurate because the
fbdiv value resulting from the division may be off by almost a full
ref_freq's worth of frequency.
also fixes the usb pll config, which ran the pll vco way out of (below)
spec.
we might not configure both, so we should put the others into reset
state. leaving them fully as is might leave them running, which might
not be the goal for runtime reconfig (when it comes around). this now
mirrors how we reset all clock-using peripherals and only unreset those
that are properly clocked.
this is only really useful for runtime *re*configuration, which we don't
currently support. even runtime reconfig probably won't need it, unless
we keep taking the sledgehammer approach of reconfiguring everything all
the time.
1459: rp/multicore: fix undefined behavior in multicore spawn. r=Dirbaio a=Dirbaio
It is UB to pass `entry` to core1 as `&mut`, because core0 keeps an aliasing pointer to that memory region, and actually writes to it (when `spawn_core1` returns, the stack frame gets deallocated and the memory gets reused). This violates noalias requirements.
Added the fence just in case, een though it works without.
bors r+
Co-authored-by: Dario Nieuwenhuis <dirbaio@dirbaio.net>
It is UB to pass `entry` to core1 as `&mut`, because core0 keeps
an aliasing pointer to that memory region, and actually writes to
it (when `spawn_core1` returns, the stack frame gets deallocated and the memory
gets reused). This violates noalias requirements.
Added the fence just in case, een though it works without.
1458: rp: remove take!, add bind_interrupts! r=Dirbaio a=pennae
both of the uart interrupts now check a flag that only the dma rx path ever sets (and now unsets again on drop) to return early if it's not as they expect. this is ... not our preferred solution, but if bind_interrupts *must* allow mutiple handlers to be specified then this is the only way we can think of that doesn't break uarts.
Co-authored-by: pennae <github@quasiparticle.net>
1456: net: do not use smoltcp Instant/Duration in public API, docs. r=Dirbaio a=Dirbaio
bors r+
Co-authored-by: Dario Nieuwenhuis <dirbaio@dirbaio.net>
1451: Work around xtensa deadlock, take 2 r=Dirbaio a=bugadani
This PR is another go at trying to do something with #1449. The commit was part of the previous attempt but mistakenly discarded as I still experienced lockups. However, after further testing, it looks like that lockup is caused by something else.
This is a manual, "cpu-local" critical section impl that should be good enough on dual-core CPUs, although the implementation still contains `SIGNAL_WORK_THREAD_MODE` which is absolutely not correct on dual-core. This approach was chosen because:
- not taking the global lock technically allows the second core to run
- wrapping the signal read and the sleep in a critical section prevents a race condition that would cause the CPU to sleep longer than ideal if an interrupt hits after reading, but before sleeping.
Co-authored-by: Dániel Buga <bugadani@gmail.com>
1454: stm32f0 flash implementation r=Dirbaio a=jp99
i've copied and modified the f3 implementation and it seems to be working.
Co-authored-by: Jaap Prickartz <jaap@tetra.nl>
1453: stm32 uart: Fix error flag handling for blocking operations r=Dirbaio a=timokroeger
Clear and report the error flags one by one and pop the data byte only after all error flags were handled.
For v1/v2 we emulate the v3/v4 behaviour by buffering the status register because a read to the data register clears all flags at once which means we might loose all but the first error.
Only tested on stm32f3 discovery board with loopback. Let‘s see what CI says for the other families.
Fixes#1452
Co-authored-by: Timo Kröger <timokroeger93@gmail.com>
Clear and report the error flags one by one and pop the data byte only
after all error flags were handled.
For v1/v2 we emulate the v3/v4 behaviour by buffering the status
register because a read to the data register clears all flags at once
which means we might loose all but the first error.
Mode was being set to 2 (PM2_POWERSAVE_MODE), should be
0 (NO_POWERSAVE_MODE). Setting None mode failed with a panic:
85.707099 DEBUG set pm2_sleep_ret = [00, 00, 00, 00]
└─ cyw43::control::{impl#0}::set_iovar_v::{async_fn#0} @ cyw43/src/fmt.rs:127
85.710469 ERROR panicked at 'IOCTL error -29'
1448: rp: don't use SetConfig trait in PWM and PIO. r=Dirbaio a=Dirbaio
It was intended to allow changing baudrate on shared spi/i2c. There's no advantage in using it for PWM or PIO, and makes it less usable because you have to have `embassy-embedded-hal` as a dep to use it.
bors r+
Co-authored-by: Dario Nieuwenhuis <dirbaio@dirbaio.net>
It was intended to allow changing baudrate on shared spi/i2c. There's no
advantage in using it for PWM or PIO, and makes it less usable because you have to
have `embassy-embedded-hal` as a dep to use it.
1447: rp/watchdog: fix overflow if period is longer than 4294 seconds. r=Dirbaio a=Dirbaio
bors r+
Co-authored-by: Dario Nieuwenhuis <dirbaio@dirbaio.net>
1424: add TL maibox for stm32wb r=xoviat a=OueslatiGhaith
Hello,
This pull request is related to #1397 and #1401, inspired by #24, build upon the work done in #1405, and was tested on an stm32wb55rg.
This pull request aims to add the transport layer mailbox for stm32wb microcontrollers. For now it's only capable of initializing it and getting the firmware information
Co-authored-by: goueslati <ghaith.oueslati@habemus.com>
Co-authored-by: Ghaith Oueslati <73850124+OueslatiGhaith@users.noreply.github.com>
Co-authored-by: xoviat <xoviat@users.noreply.github.com>
1436: rp: Clock configuration r=CBJamo a=CBJamo
Draft of a more complete clock config for the 2040.
I also extended and made public the clk_<name>_freq functions. I know at least the ws2812 pio example would like to get the sys clock at runtime rather than just using a constant. I suspect most pio-based peripherals will want access to the clocks.
Open questions:
1. Best way to handle the 3 external clock frequencies. I think the XIN (aka crystal) freq should just be set by the init function then never changed, though if it's an external clock that could change? I'm not sure anyone would ever want to do that but maybe it should be handled just in case? The other two should probably be set by the application.
2. Better estimation of ROSC frequency. Right now it's really just a lookup table of the speed from the single sample I did this testing on, and only uses the frequency range and div, drive strength is ignored.
3. Probably some kind of warning should be generated if the random bit from the rosc won't be useful, not sure how to do that.
4. Should clocks only be allowed to be configured at init, or should they be modifiable at runtime? For example, switching the RTC to a clock in pin when a pps source is available.
Bonus feature to support clock output. I only implemented the bare minimum, and only for gpout0. I'm sure there's a clean way with macros to impl all 4 without just copy/paste, but I haven't learned macros yet.
Co-authored-by: Caleb Jamison <caleb@cbjamo.com>
1439: rp: use rp2040-boot2 to provide the boot2 blob r=Dirbaio a=pennae
we're currently shipping an old boot2 that runs the flash at half speed. use the more recent version instead, and allow user to choose between the different supported boot2 versions for different flash chips if they need that.
Co-authored-by: pennae <github@quasiparticle.net>
we're currently shipping an old boot2 that runs the flash at half speed.
use the more recent version instead, and allow user to choose between
the different supported boot2 versions for different flash chips if they
need that.
1434: rp pio IV (the voyage home) r=Dirbaio a=pennae
this should hopefully be the last entry in this series. after this we'll have a reasonably safe interface to pio, both for configuration and at runtime. pio now looks very much like the other peripherals (though not exactly, seeing how state machines can't be constructed from a config but only have it applied to them later). the generated code for `StateMachine::set_config` is still larger than we'd like (almost 300 bytes at Oz), but it's a great step up in safety from the previous interface at approximately the same code space cost.
Co-authored-by: pennae <github@quasiparticle.net>
execution wraps around after the end of instruction memory and wrapping
works with this, so we may as well allow program loading across this
boundary. could be useful for reusing chunks of instruction memory.
sometimes state machines need to be started, restarted, or synchronized
at exactly the same time. the current interface does not allow this but
the hardware does, so let's expose that.
the many individual sets aren't very efficient, and almost no checks
were done to ensure that the configuration written to the hardware was
actually valid. this adresses both of these.
none of these are safe. the x/y functions mangle the fifos, the set
functions require the state machine to be stopped to be in any way safe,
the out functions do both of those things at once. only the jump
instruction is marginally safe, but running this on an active program is
bound to cause problems.
programs contain information we could pull from them directly and use to
validate other configuration of the state machine instead of asking the
user to pull them out and hand them to us bit by bit. unfortunately
programs do not specify how many in or out bits they use, so we can only
handle side-set and wrapping jumps like this. it's still something though.
there's nothing this critical section protects against. both read and
write-to-clear are atomic and don't interfere with other irq futures,
only potentially with setting/clearing an irq flag from an arm core.
neither have ever been synchronized, and both have the same observable
effects under atomic writes and critical sections. (for both setting and
clearing an irq flag observable differences could only happen if the
set/clear happened after the poll read, but before the write. if it's a
clear we observe the same effects as sequencing the clear entirely after
the poll, and if it's a set we observe the same effects as sequencing
the set entirely before the poll)
it's only any good for PioPin because there it follows a pattern of gpio
pin alternate functions being named like that, everything else can just
as well be referred to as `pio::Thing`
This flag for example permits the following clock tree
configuration on stm32f103r8
let mut config = Config::default();
config.rcc.hse = Some(Hertz(16_000_000));
config.rcc.sys_ck = Some(Hertz(72_000_000));
config.rcc.pclk1 = Some(Hertz(36_000_000));
config.rcc.pclk2 = Some(Hertz(72_000_000));
config.rcc.pllxtpre = true;
Init fails if pllxtpre is false.
1429: rp pio, √9 r=Dirbaio a=pennae
another mix of refactoring and soundness issues. most notably pio pins are now checked for being actually accessible to the pio blocks, are constructible from not just the owned peripherals but refs as well, and have their registrations to the pio block reverted once all state machines and the common block has been dropped.
state machines are now also stopped when dropped, and concurrent rx+tx using dma can finally be done in a sound manner. previously it was possible to do, but allowed users to start two concurrent transfers to the same fifo using different dma channels, which obviously would not have the expected results on average.
Co-authored-by: pennae <github@quasiparticle.net>
1430: Handle SUBGHZSPI as async r=lulf a=ceekdee
For STM32WL, simplify configuration for the use of SUBGHZSPI to perform LoRa operations. Use Rx/Tx DMA on SPI to enable async functionality.
Co-authored-by: ceekdee <taigatensor@gmail.com>
Co-authored-by: Chuck Davis <taigatensor@gmail.com>
this *finally* allows sound implementions of bidirectional transfers
without blocking. the futures previously allowed only a single direction
to be active at any given time, and the dma transfers didn't take a
mutable reference and were thus unsound.
this way we can share irq handling between state machines and common
without having to duplicate the methods. it also lets us give irq flag
access to places without having to dedicate a state machine or the
common instance to those places, which can be very useful to eg trigger
an event and wait for a confirmation using an irq wait object.
we can only have one active waiter for any given irq at any given time.
allowing waits for irqs on state machines bypasses this limitation and
causes lost events for all but the latest waiter for a given irq.
splitting this out also allows us to signal from state machines to other
parts of the application without monopolizing state machine access for
the irq wait, as would be necessary to make irq waiting sound.
move all methods into PioStateMachine instead. the huge trait wasn't
object-safe and thus didn't have any benefits whatsoever except for
making it *slightly* easier to write bounds for passing around state
machines. that would be much better solved with generics-less instances.
once all sharing owners of pio pins have been dropped we should reset
the pin for use by other hal objects. unfortunately this needs an atomic
state per pio block because PioCommon and all of the state machines
really do share ownership of any wrapped pins. only PioCommon can create
them, but all state machines can keep them alive. since state machines
can be moved to core1 we can't do reference counting in relaxed mode,
but we *can* do relaxed pin accounting (since only common and the final
drop can modify this).
we can't prove that some instruction memory is not used as long as state
machines are alive, and we can pass instance memory handles between
instances as well. mark free_instr unsafe, with documentation for this caveat.
1425: rp pio, round 2 r=Dirbaio a=pennae
another round of bugfixes for pio, and some refactoring. in the end we'd like to make pio look like all the other modules and not expose traits that provide all the methods of a type, but put them onto the type itself. traits only make much sense, even if we added an AnyPio and merged the types for the member state machines (at the cost of at least a u8 per member of Pio).
Co-authored-by: pennae <github@quasiparticle.net>
not requiring a PioInstance for splitting lets us split from a
PeripheralRef or borrowed PIO as well, mirroring every other peripheral
in embassy_rp. pio pins still have to be constructed from owned pin
instances for now.
merge into PioInstance instead. PioPeripheral was mostly a wrapper
around PioInstance anyway, and the way the wrapping was done required
PioInstanceBase<N> types where PIO{N} could've been used instead.
1423: rp: fix gpio InputFuture and inefficiencies r=pennae a=pennae
InputFuture could not wait for edges without breaking due to a broken From impl, but even if the impl had been correct it would not have worked correctly because raw edge interrupts are sticky and must be cleared from software. also replace critical sections with atomic accesses, and do nvic setup only once.
Co-authored-by: pennae <github@quasiparticle.net>
doing this setup work repeatedly, on every wait, is unnecessary. with
nothing ever disabling the interrupt it is sufficient to enable it once
during device init and never touch it again.
pio control registers are notionally shared between state machines as
well. state machine operations that change these registers must use
atomic accesses (or critical sections, which would be overkill).
notably PioPin::set_input_sync_bypass was even wrong, enabling the
bypass on a pin requires the corresponding bit to be set (not cleared).
the PioCommon function got it right.
add an hd44780 example for pio. hd44780 with busy polling is a pretty
complicated protocol if the busy polling is to be done by the
peripheral, and this example exercises many pio features that we don't
have good examples for yet.
1422: rp: remove leftovers from #1414 r=Dirbaio a=pennae
forgot to remove these when they were no longer necessary or useful. oops.
Co-authored-by: pennae <github@quasiparticle.net>
fixing the dma word size to 32 makes it impossible to implement any
peripheral that takes its data in smaller chunks, eg uart, spi, i2c,
ws2812, the list goes on.
compiler barriers were also not set correctly; we need a SeqCst barrier
before starting a transfer as well to avoid reordering of accesses into
a buffer after dma has started.
InputFuture did not use and check edge interrupts correctly.
InterruptTrigger should've checked for not 1,2,3,4 but 1,2,4,8 since the
inte fields are bitmasks, and not clearing INTR would have repeatedly
triggered edge interrupts early.
1404: feat(stm32): Add DMA based, ring-buffer based rx uart, v3 r=Dirbaio a=rmja
This PR replaces #1150. Comparing to that PR, this one has the following changes:
* The implementation now aligns with the new stm32 dma module, thanks `@Dirbaio!`
* Calls to `read()` now returns on either 1) idle line, or 2) ring buffer is at most half full. This is different from the previous pr, which would return a lot of 1 byte reads. Thank you `@chemicstry` for making me realize that it was actually not what I wanted. This is accomplished using half-transfer completed and full-transfer completed interrupts. Both seems to be supported on both dma and bdma.
The implementation still have the issue mentioned here: https://github.com/embassy-rs/embassy/pull/1150#discussion_r1094627035
Regarding the todos here: https://github.com/embassy-rs/embassy/pull/1150#issuecomment-1513905925. I have removed the exposure of ndtr from `dma::RingBuffer` to the uart so that the uart now simply calls `ringbuf::reload_position()` to align the position within the ring buffer to that of the actual running dma controller. BDMA and GPDMA is not implemented. I do not have any chips with those dma controllers, so maybe someone else should to this so that it can be tested.
The `saturate_serial` test utility inside `tests/utils` has an `--idles` switch which can be used to saturate the uart from a pc, but with random idles.
Because embassy-stm32 now can have tests, we should probably run them in ci. I do this locally to test the DmaRingBuffer: `cargo test --no-default-features --features stm32f429ig`.
cc `@chemicstry` `@Dirbaio`
Co-authored-by: Rasmus Melchior Jacobsen <rmja@laesoe.org>
Co-authored-by: Dario Nieuwenhuis <dirbaio@dirbaio.net>
1376: rtc: cleanup and consolidate r=Dirbaio a=xoviat
This removes an extra file that I left in, adds an example, and consolidates the files into one 'v2' file.
Co-authored-by: xoviat <xoviat@users.noreply.github.com>
1414: rp: report errors from buffered and dma uart receives r=Dirbaio a=pennae
neither of these reported errors so far, which is not ideal. add error reporting to both of them that matches the blocking error reporting as closely as is feasible, even allowing partial receives from buffered uarts before errors are reported where they would have been by the blocking code. dma transfers don't do this, if an errors applies to any byte in a transfer the entire transfer is nuked (though we probably could report how many bytes have been transferred).
Co-authored-by: pennae <github@quasiparticle.net>
this reports errors at the same location the blocking uart would, which
works out to being mostly exact (except in the case of overruns, where
one extra character is dropped). this is actually easier than going
nuclear in the case of errors and nuking both the buffer contents and
the rx fifo, both of which are things we'd have to do in addition to
what's added here, and neither are needed for correctness.
sending break conditions is necessary to implement some protocols, and
the hardware supports this natively. we do have to make sure that we
don't assert a break condition while the uart is busy though, otherwise
the break may be inserted before the last character in the tx fifo.
1395: rp/pio: bit of a rework r=Dirbaio a=pennae
the pio module is currently in a Bit of a State. this is far from all that's needed to make it more useful, but it's a start.
Co-authored-by: pennae <github@quasiparticle.net>
the rp uart receive fifo is 32 entries deep, so the 31 byte test data
fits into it without needing any buffering. extend to 48 bytes to fill
the entire fifo and the 16 byte test buffer.
instruction memory is a shared resource. writing it only from PioCommon
clarifies this, and perhaps makes it more obvious that multiple state
machines can share the same instructions.
this also allows *freeing* of instruction memory to reprogram the
system, although this interface is not entirely safe yet. it's safe in
the sense rusts understands things, but state machines may misbehave if
their instruction memory is freed and rewritten while they are running.
fixing this is out of scope for now since it requires some larger
changes to how state machines are handled. the interface provided
currently is already unsafe in that it lets people execute instruction
memory that has never been written, so this isn't much of a drawback for now.
pin and irq operations affect the entire pio block. with pins this is
not very problematic since pins themselves are resources, but irqs are
not treated like that and can thus interfere across state machines. the
ability to wait for an irq on a state machine is kept to make
synchronization with user code easier, and since we can't inspect loaded
programs at build time we wouldn't gain much from disallowing waits from
state machines anyway.
this mainly removes the need for explicit indexing to get the pac
object. runtime effect is zero, but arguably things are a bit easier to
read with less indexing.
this is already done during platform init. it wasn't even sound in the
original implementation because futures would meddle with the nvic in
critical sections, while another (interrupt) executor could meddle with
the nvic without critical sections here. it is only accidentally sound
now and only if irq1 of both pios isn't used by user code. luckily the
worst we can expect to happen is interrupt priorities being set wrong,
but wrong is wrong is wrong.
since we never actually *disable* these interrupts for any length of
time we can simply enable them globally. we also initialize all pio
interrupt flags to not cause system interrupts since state machine
irqa are not necessarily meant to cause a system interrupt when set. the
fifo interrupts are sticky and can likewise only be cleared inside the
handler by disabling them.
dma does this too, also with 12 bits to check. this decreases code size
significantly (increasing speed when the cache is cold), frees up an
interrupt handler, and avoids read-modify-write cycles (which makes each
processed flag cheaper). due to more iterations per handler invocation
the actual runtime of the handler body remains roughly the
same (slightly faster at O2, slightly slower at Oz).
notably wakers are now kept in one large array indexed by the irq
register bit number instead of three different arrays, this allows for
machine code-level optimizations of waker lookups.
1405: add IPCC peripheral for stm32wb r=xoviat a=OueslatiGhaith
Hello again,
This pull request is related to #1397 and #1401, inspired by #24, and was tested on an stm32wb55rg.
This pull request aims to add the IPCC peripheral for stm32wb microcontrollers.
I am debating whether this should be included in the public API, since the IPCC peripheral would be typically managed by the TL Mailbox, not by the app directly.
Co-authored-by: OueslatiGhaith <ghaith.oueslati@enis.tn>
1412: stm32/uart: abort on error r=Dirbaio a=xoviat
This PR aborts the DMA transfer in the event of a UART error. Otherwise, the transfer will never complete, and an error will not be returned.
Co-authored-by: xoviat <xoviat@users.noreply.github.com>
1403: Bump versions preparing for -macros and -executor release r=lulf a=lulf
I'd like to propose a new release of embassy-macros and embassy-executor, as there is a challenge with some of the features changing since 0.1.1 when using libraries that depend on 0.1.1 with applications that patch to use git versions.
Co-authored-by: Ulf Lilleengen <lulf@redhat.com>
1406: rp: DMA behaviour during flash operations r=Dirbaio a=kalkyl
This PR changes the old behaviour during flash operations where all DMA transfers were paused during the flash operation.
The new approach is to wait for any DMA operating in flash region to finish and let RAM transfers continue.
Co-authored-by: kalkyl <henrik.alser@me.com>
1402: rp: remove pio Cargo feature. r=Dirbaio a=Dirbaio
We shouldn't have Cargo features if their only purpose is reduce cold build time a bit.
bors r+
Co-authored-by: Dario Nieuwenhuis <dirbaio@dirbaio.net>
1396: Add an external LoRa physical layer feature r=Dirbaio a=ceekdee
The original LoRa drivers have been deprecated and examples associated with them deleted; however, the original LoRa drivers are still available to allow a gentle transition to the external lora-phy crate.
Co-authored-by: ceekdee <taigatensor@gmail.com>
Co-authored-by: Chuck Davis <taigatensor@gmail.com>
Co-authored-by: Ulf Lilleengen <lulf@redhat.com>
- probe-run screwed up the last release 2 weeks ago and it's still not fixed (issue 391). Doesn't look well maintained.
- Even when it's not broken, it lags behind probe-rs-cli in new chips support because it's slow in updating probe-rs.
1383: embassy-boot: Add nightly flag r=Dirbaio a=sawi97
This adds "nightly" as a flag to embassy-boot and embassy-boot-nrf which gates features requiring nightly, enabled by default.
Makes it possible to build the bootloader with the stable compiler when setting `default-features=false`.
It should be straight forward to do this for stm32 and rp as well, but I am not been able to test it.
Co-authored-by: sander <sander.wittwer@dengineering.no>
Co-authored-by: sawi97 <34313578+sawi97@users.noreply.github.com>
1384: rp: optimize rom-func-cache for runtime r=Dirbaio a=pennae
storing a full function pointer initialized to a resolver trampoline lets us avoid the runtime cost of checking whether we need to do the initialization. this also slightly reduces flash usage due to a slightly more space-efficient initialization procedure.
Co-authored-by: pennae <github@quasiparticle.net>
storing a full function pointer initialized to a resolver trampoline
lets us avoid the runtime cost of checking whether we need to do the
initialization.
1370: stm32/i2c: fix races when using dma. r=Dirbaio a=xoviat
This change addresses two races:
1. It removes the `chunks_transferred` state variable that is modified inside the interrupt. Analysis of the code reveals that the only time the waker can be woken is when `chunks_transferred` is incremented. Therefore, waking is enough to signal the `poll_fn` that the `chunks_transferred` has incremented. Moving to `remaining_len` clarifies the code, since there is no need to track how many chunks are remaining.
2. It moves the start of the transfer until after the waker is registered, which could theoretically occur if the clock speed is very low, but probably never would even if this wasn't fixed.
There is another race that I noticed: between writes the waker may not yet be registered. In that case, the code would simply be stuck and the `poll_fn` would never be woken. There is no way to resolve this without broadening the scope of the analysis, and this will likely never occur.
Co-authored-by: xoviat <xoviat@users.noreply.github.com>
1382: rp: hook up softfloat intrinsics to bootrom r=Dirbaio a=pennae
rp-hal has done this very well already, so we'll just copy their entire impl again. only div.rs needed some massaging because our sio access works a little differently, everything else worked as is.
includes a minor bit of refactoring to make it easier to check which bits we've copied from rp2040-hal and which we haven't.
Co-authored-by: pennae <github@quasiparticle.net>
rp-hal has done this very well already, so we'll just copy their entire
impl again. only div.rs needed some massaging because our sio access
works a little differently, everything else worked as is.
1379: enable inline-asm feature for cortex-m in examples r=Dirbaio a=pennae
inline assembly is supported since rust 1.59, we're way past that. enabling this makes the compiled code more compact, and on rp2040 even decreses memory usage by not needing thunks in sram.
Co-authored-by: pennae <github@quasiparticle.net>
1345: Added a neopixel constructor to spi, with an example in the stm32g0 d… r=Dirbaio a=smeenka
For Spi I added the possibility to use the Spi device as a Neopixel driver, with very precise timing, and not dependent on software during the transfer. Even without the --release flag, the timing is perfect.
Note that between the bursts of data the Mosi line should stay on low level. A resistor of 10k can guarantee that, as it seems the the pin is floating between the bursts (on the nucleo-G070RB platform I use).
I created an example for the STM32G0 family.
This example does contain a very simple Neopixel driver, only for one type. But this Neopixel driver can easy be adapted to different types (for example RGBW types).
Co-authored-by: Dario Nieuwenhuis <dirbaio@dirbaio.net>
Co-authored-by: anton smeenk <asmeenk@planet.nl>
inline assembly is supported since rust 1.59, we're way past that.
enabling this makes the compiled code more compact, and on rp2040
even decreses memory usage by not needing thunks in sram.
1378: Add ability to invert UART pins, take 2 r=Dirbaio a=jakewins
Same PR as before, except this now works :)
There was a minor hiccup in the UartRx code where the rx pin got passed as the tx argument, so the invert settings didn't get applied. With this fix, my local setup at least is happily reading inverted uart data.
Co-authored-by: Jacob Davis-Hansson <jake@davis-hansson.com>
1369: Lora AFIT r=Dirbaio a=Dirbaio
Extracted out of #1367
Probably we should wait until `rust-lorawan` is merged+released?
Co-authored-by: Ulf Lilleengen <lulf@redhat.com>
1371: RTC r=Dirbaio a=xoviat
This adds RTC for most of the stm32 chips. Nearly all of the work was not done by me, but I took it the last bit by disabling the chips that weren't working. I think it would be easier to enable them in future PRs if requested.
1374: stm32: remove TIMX singleton when used on timer driver r=Dirbaio a=xoviat
After multiple ways of looking at this, this is the best solution I could think of.
Co-authored-by: Mathias <mk@blackbird.online>
Co-authored-by: xoviat <xoviat@users.noreply.github.com>
1372: rp: add division intrinsics r=Dirbaio a=pennae
rp2040-hal adds division intrinsics using the hardware divider unit in the SIO, as does the pico-sdk itself. using the hardware is faster than the compiler_rt implementations, and more compact too.
since embassy does not expose the hardware divider in any way (yet?) we could go even further an remove the state-saving code rp2040-hal needs, but that doesn't seem to be worth it.
Co-authored-by: pennae <github@quasiparticle.net>
rp2040-hal adds division intrinsics using the hardware divider unit in
the SIO, as does the pico-sdk itself. using the hardware is faster than
the compiler_rt implementations, and more compact too.
1360: stm32/rcc: add i2s pll on some f4 micros r=Dirbaio a=xoviat
Adds the i2s pll on some f4 micros.
1361: Executor: Replace unnecessary atomics in runqueue r=Dirbaio a=GrantM11235
Only the head pointer needs to be atomic. The `RunQueueItem` pointers are only loaded and stored, and never concurrently
Co-authored-by: xoviat <xoviat@users.noreply.github.com>
Co-authored-by: Grant Miller <GrantM11235@gmail.com>
This is useful in some cases where the surrounding circuit
for some reason inverts the UART signal, for instance if you're talking
to a device via an optocoupler.
This commit adds the allow(unused) attribute to functions and constants
that are not currently used. There is one warning remaining but
https://github.com/embassy-rs/cyw43/pull/23 attempts to address that
one. The constants have been moved into a module to allow the attribute
to be applied to the module as a whole.
The motivation for this is that it will hopefully make it easier to
spot new warnings that might be introduced by new, or updated code.
This commit adds constants intended to be used with the `cmd_word`
function.
The motivation for this to (hopefully) improve the readability of the
code.
This commit comments out two Timer::after calls which look like they
go together with previous instructions, but those instructions are
currently commented out, so it looks like these calls are not
currently needed.
This commit adds a comment to the setting of the iovar `bus:txglom`.
The motivation for this is that I had not heard of 'glom/glomming'
before and having a comment might help others that are not familar with
the term.
This commit add two constants and updates the comment about ALP.
It was not easy to find the definition of ALP but after searching I
found what I believe is the correct definition in section 3.3 "Clocks"
in the referenced document below.
Active Low Power (ALP):
Supplied by an internal or external oscillator. This clock is
requested by cores when accessing backplane registers in other cores
or when performing minor computations. When an external crystal is
used to provide reference clock, ALP clock frequency is determined by
the frequency of the external oscillator. A 37.4 MHz reference clock
is recommended.
Refs:
https://www.infineon.com/dgdl/Infineon-AN214828_Power_Consumption_Measurements-ApplicationNotes-v03_00-EN.pdf?fileId=8ac78c8c7cdc391c017d0d2803a4630d
This commit uses wrapping_sub for subtraction in update_credit.
The motivation for this is that currently the rpi-pico-w example panics
(at least for me) with the following error:
3.825277 INFO init done
└─ cyw43::{impl#4}::init::{async_fn#0} @ /embassy/cyw43/src/fmt.rs:138
3.825486 INFO Downloading CLM...
└─ cyw43::{impl#2}::init::{async_fn#0} @ /embassy/cyw43/src/fmt.rs:138
3.841328 WARN TX stalled
└─ cyw43::{impl#4}::run::{async_fn#0} @ /embassy/cyw43/src/fmt.rs:151
3.845549 ERROR panicked at 'attempt to subtract with overflow', /embassy/cyw43/src/lib.rs:919:16
└─ panic_probe::print_defmt::print @ .cargo/registry/src/github.com-1ecc6299db9ec823/panic-probe-0.3.0/src/lib.rs:91
────────────────────────────────────────────────────────────────────────────────
stack backtrace:
0: HardFaultTrampoline
<exception entry>
1: lib::inline::__udf
at ./asm/inline.rs:181:5
2: __udf
at ./asm/lib.rs:51:17
3: cortex_m::asm::udf
at .cargo/registry/src/github.com-1ecc6299db9ec823/cortex-m-0.7.6/src/asm.rs:43:5
4: rust_begin_unwind
at .cargo/registry/src/github.com-1ecc6299db9ec823/panic-probe-0.3.0/src/lib.rs:72:9
5: core::panicking::panic_fmt
at rustc/1c7b36d4db582cb47513a6c7176baaec1c3346ab/library/core/src/panicking.rs:142:14
6: core::panicking::panic
at /rustc/1c7b36d4db582cb47513a6c7176baaec1c3346ab/library/core/src/panicking.rs:48:5
7: cyw43::Runner<PWR,SPI>::update_credit
at /embassy/cyw43/src/lib.rs:919:16
8: cyw43::Runner<PWR,SPI>::rx
at /embassy/cyw43/src/lib.rs:808:9
9: cyw43::Runner<PWR,SPI>::run::{{closure}}
at /embassy/cyw43/src/lib.rs:727:21
10: <core::future::from_generator::GenFuture<T> as core::future::future::Future>::poll
at /rustc/1c7b36d4db582cb47513a6c7176baaec1c3346ab/library/core/src/future/mod.rs:91:19
11: cyw43_example_rpi_pico_w::__wifi_task_task::{{closure}}
at src/main.rs:32:17
total_len is already rounded up, so the `+ 3` is not needed.
And even if it was, the calculation should have been `((total_len + 3) / 4)`.
`(total_len + 3 / 4)` is equivalent to `total_len` and can overflow
the slice, leading to a panic which can easily be triggered by sending
large ICMP ECHO packets to the device.
This commit adds two constants which are intended to be used for setting
the `Word Length` and `High Speed` fields in the gSPR register
(address: 0x0000, bit: 0 and bit 4).
Currently, this field is being set by the following line:
```rust
// 32bit, little endian.
self.write32_swapped(REG_BUS_CTRL, 0x00010031).await;
```
Assuming that we are sending these bits using the gSPI write protocol
and using 16-bit word operation in little endian (which I think might
be the default) then the data bytes should be packed like this:
```
+--+--+--+--+
|D1|D0|D3|D2|
+--+--+--+--+
val (hex): 0x00010031
val (bin): 00000000000000010000000000110001
rotated(16): 00000000001100010000000000000001
```
If we split val into bytes and rotated the bits we get:
```
Split into bytes:
D3 D2 D1 D0
00000000 00000001 00000000 00110001
Rotate 16 and split into bytes:
D1 D0 D3 D2
00000000 00110001 00000000 00000001
```
Looking at the write procotol it seems to me that the above will
indeed set the `Word Length` to 1 but will also set other values.
```
Status enable (1=default)
D1 D0 D3 D2 ↓
00000000 00110001 00000000 00000001
↑↑ ↑↑ ↑
|| |Word Length (1=32-bit)
|| |
|| Endianess (0=Little)
||
|High-speed mode (1=High speed (default))
|
Interrupt polarity (1=high (default))
```
This commit suggests adding the above mentioned constants for setting
the only the word length field and the high speed field.
This commit renames the REG_BUS_FEEDBEAD to REG_BUS_TEST_RO
(Read-Only) which is the name used in the specification, section 4.2.3
Table 6.
It also adds a constant named REG_BUS_TEST_RW (Read-Write) to represent
the dummy register which the host can use to write data and read back
to check that the gSPI interface is working properly.
This commit add comments about what CLM stands for.
The motivation of this is that I think it helps understanding the code
for users who are new to the codebase (like me).
For some reason I got strange events on channel 1 (ASYNCEVENT_HEADER):
0.647329 WARN unexpected ehternet type 0x0508, expected Qualcom ether type 0x886c
This patch improves the validation of BCD WHD events to minimize the
risk for panic.
@ -33,9 +33,10 @@ The <a href="https://docs.embassy.dev/embassy-net/">embassy-net</a> network stac
- **Bluetooth** -
The <ahref="https://github.com/embassy-rs/nrf-softdevice">nrf-softdevice</a> crate provides Bluetooth Low Energy 4.x and 5.x support for nRF52 microcontrollers.
The <ahref="https://github.com/embassy-rs/embassy/tree/main/embassy-stm32-wpan">embassy-stm32-wpan</a> crate provides Bluetooth Low Energy 5.x support for stm32wb microcontrollers.
- **LoRa** -
<ahref="https://docs.embassy.dev/embassy-lora/">embassy-lora</a> supports LoRa networking on STM32WL wireless microcontrollers and Semtech SX126x and SX127x transceivers.
<ahref="hthttps://github.com/lora-rs/lora-rs">The lora-rs project</a> provides an async LoRa and LoRaWAN stack that works well on Embassy.
- **USB** -
<ahref="https://docs.embassy.dev/embassy-usb/">embassy-usb</a> implements a device-side USB stack. Implementations for common classes such as USB serial (CDC ACM) and USB HID are available, and a rich builder API allows building your own.
@ -61,9 +62,9 @@ async fn blink(pin: AnyPin) {
loop {
// Timekeeping is globally available, no need to mess with hardware timers.
led.set_high();
Timer::after(Duration::from_millis(150)).await;
Timer::after_millis(150).await;
led.set_low();
Timer::after(Duration::from_millis(150)).await;
Timer::after_millis(150).await;
}
}
@ -99,17 +100,10 @@ Examples are found in the `examples/` folder seperated by the chip manufacturer
### Running examples
- Setup git submodules (needed for STM32 examples)
- Install `probe-rs`.
```bash
git submodule init
git submodule update
```
- Install `probe-run` with defmt support.
```bash
cargo install probe-run
cargo install probe-rs --features cli
```
- Change directory to the sample's base directory. For example:
@ -118,14 +112,22 @@ cargo install probe-run
cd examples/nrf52840
```
- Ensure `Cargo.toml` sets the right feature for the name of the chip you are programming.
If this name is incorrect, the example may fail to run or immediately crash
after being programmed.
- Ensure `.cargo/config.toml` contains the name of the chip you are programming.
- Run the example
For example:
```bash
cargo run --bin blinky
cargo run --release --bin blinky
```
For more help getting started, see [Getting Started][1] and [Running the Examples][2].
## Developing Embassy with Rust Analyzer based editors
The [Rust Analyzer](https://rust-analyzer.github.io/) is used by [Visual Studio Code](https://code.visualstudio.com/)
@ -158,3 +160,5 @@ This work is licensed under either of
RP2040 PIO driver for the nonstandard half-duplex SPI used in the Pico W. The PIO driver offloads SPI communication with the WiFi chip and improves throughput.
## Minimum supported Rust version (MSRV)
Embassy is guaranteed to compile on the latest stable Rust version at the time of release. It might compile with older versions but that may change in any new patch release.
## License
This work is 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>)
Rust driver for the CYW43439 wifi chip, used in the Raspberry Pi Pico W. Implementation based on [Infineon/wifi-host-driver](https://github.com/Infineon/wifi-host-driver).
- RP2040 PIO driver for the nonstandard half-duplex SPI used in the Pico W.
- Using IRQ for device events
- GPIO support (for LED on the Pico W)
TODO:
- Setting a custom MAC address.
- Bus sleep (for power consumption optimization)
## Running the examples
-`cargo install probe-rs --features cli`
-`cd examples/rp`
### Example 1: Scan the wifi stations
-`cargo run --release --bin wifi_scan`
### Example 2: Create an access point (IP and credentials in the code)
-`cargo run --release --bin wifi_ap_tcp_server`
### Example 3: Connect to an existing network and create a server
-`cargo run --release --bin wifi_tcp_server`
After a few seconds, you should see that DHCP picks up an IP address like this
```
11.944489 DEBUG Acquired IP configuration:
11.944517 DEBUG IP address: 192.168.0.250/24
11.944620 DEBUG Default gateway: 192.168.0.33
11.944722 DEBUG DNS server 0: 192.168.0.33
```
This example implements a TCP echo server on port 1234. You can try connecting to it with:
```
nc 192.168.0.250 1234
```
Send it some data, you should see it echoed back and printed in the firmware's logs.
## Minimum supported Rust version (MSRV)
Embassy is guaranteed to compile on the latest stable Rust version at the time of release. It might compile with older versions but that may change in any new patch release.
## License
This work is 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>)
// There MUST be 2 bytes of padding between the SDPCM and BDC headers.
// And ONLY for data packets!
// No idea why, but the firmware will append two zero bytes to the tx'd packets
// otherwise. If the packet is exactly 1514 bytes (the max MTU), this makes it
// be oversized and get dropped.
// WHD adds it here https://github.com/Infineon/wifi-host-driver/blob/c04fcbb6b0d049304f376cf483fd7b1b570c8cd5/WiFi_Host_Driver/src/include/whd_sdpcm.h#L90
// and adds it to the header size her https://github.com/Infineon/wifi-host-driver/blob/c04fcbb6b0d049304f376cf483fd7b1b570c8cd5/WiFi_Host_Driver/src/whd_sdpcm.c#L597
@ -6,13 +6,24 @@ So you've got one of the xref:examples.adoc[examples] running, but what now? Let
The full example can be found link:https://github.com/embassy-rs/embassy/tree/master/docs/modules/ROOT/examples/basic[here].
=== Rust Nightly
NOTE: If you’re using VS Code and rust-analyzer to view and edit the examples, you may need to make some changes to `.vscode/settings.json` to tell it which project we’re working on. Follow the instructions commented in that file to get rust-analyzer working correctly.
The first thing you'll notice is a few declarations stating that Embassy requires some nightly features:
=== Bare metal
The first thing you’ll notice are two attributes at the top of the file. These tells the compiler that program has no access to std, and that there is no main function (because it is not run by an OS).
[source,rust]
----
include::example$basic/src/main.rs[lines="1..3"]
include::example$basic/src/main.rs[lines="1..2"]
----
=== Rust Nightly
The next declaration is a Rust Unstable feature, which means that Embassy requires Rust Nightly:
[source,rust]
----
include::example$basic/src/main.rs[lines="3"]
----
=== Dealing with errors
@ -39,19 +50,18 @@ NOTE: Notice that there is no busy waiting going on in this task. It is using th
=== Main
The main entry point of an Embassy application is defined using the `#[embassy_executor::main]` macro. The entry point is also required to take a `Spawner` and a `Peripherals` argument.
The main entry point of an Embassy application is defined using the `#[embassy_executor::main]` macro. The entry point is passed a `Spawner`, which it can use to spawn other tasks.
The `Spawner` is the way the main application spawns other tasks. The `Peripherals` type comes from the HAL and holds all peripherals that the application may use. In this case, we want to configure one of the pins as a GPIO output driving the LED:
We then initialize the HAL with a default config, which gives us a `Peripherals` struct we can use to access the MCU’s various peripherals. In this case, we want to configure one of the pins as a GPIO output driving the LED:
What happens when the `blinker` task has been spawned and main returns? Well, the main entry point is actually just like any other task, except that you can only have one and it takes some specific type arguments. The magic lies within the `#[embassy::main]` macro. The macro does the following:
What happens when the `blinker` task has been spawned and main returns? Well, the main entry point is actually just like any other task, except that you can only have one and it takes some specific type arguments. The magic lies within the `#[embassy_executor::main]` macro. The macro does the following:
. Creates an Embassy Executor
. Initializes the microcontroller HAL to get the `Peripherals`
Over time, a couple of best practices have emerged. The following list should serve as a guideline for developers writing embedded software in _Rust_, especially in the context of the _Embassy_ framework.
== Passing Buffers by Reference
It may be tempting to pass arrays or wrappers, like link:https://docs.rs/heapless/latest/heapless/[`heapless::Vec`], to a function or return one just like you would with a `std::Vec`. However, in most embedded applications you don't want to spend ressources on an allocator and end up placing buffers on the stack.
This, however, can easily blow up your stack if you are not careful.
@ -45,6 +45,8 @@ The BOOTLOADER_STATE partition must be big enough to store one word per page in
The bootloader has a platform-agnostic part, which implements the power fail safe swapping algorithm given the boundaries set by the partitions. The platform-specific part is a minimal shim that provides additional functionality such as watchdogs or supporting the nRF52 softdevice.
NOTE: The linker scripts for the application and bootloader look similar, but the FLASH region must point to the BOOTLOADER partition for the bootloader, and the ACTIVE partition for the application.
=== FirmwareUpdater
The `FirmwareUpdater` is an object for conveniently flashing firmware to the DFU partition and subsequently marking it as being ready for swapping with the active partition on the next reset. Its principle methods are `write_firmware`, which is called once per the size of the flash "write block" (typically 4KiB), and `mark_updated`, which is the final call.
When a project that imports `embassy-stm32` is compiled, that project selects the feature corresponding to the chip that project is using. Based on that feature, `embassy-stm32` selects supported link:https://anysilicon.com/ip-intellectual-property-core-semiconductors/[IP] for the chip, and enables the corresponding HAL implementations. But how does `embassy-stm32` know what IP the chip contains, out of the hundreds of chips that we support? It's a long story that starts with `stm32-data-sources`.
== `stm32-data-sources`
link:https://github.com/embassy-rs/stm32-data-sources[`stm32-data-sources`] is as mostly barren repository. It has no README, no documentation, and few watchers. But it's the core of what makes `embassy-stm32` possible. The data for every chip that we support is taken in part from a corresponding XML file like link:https://github.com/embassy-rs/stm32-data-sources/blob/b8b85202e22a954d6c59d4a43d9795d34cff05cf/cubedb/mcu/STM32F051K4Ux.xml[`STM32F051K4Ux.xml`]. In that file, you'll see lines like the following:
These lines indicate that this chip has an i2c, and that it's version is "v1_1". It also indicates that it has a general purpose timer that with a version of "v2_x". From this data, it's possible to determine which implementations should be included in `embassy-stm32`. But actually doing that is another matter.
== `stm32-data`
While all users of this project are familiar with `embassy-stm32`, fewer are familiar with the project that powers it: `stm32-data`. This project doesn't just aim to generate data for `embassy-stm32`, but for machine consumption in general. To acheive this, information from multiple files from the `stm32-data-sources` project are combined and parsed to assign register block implementations for each supported IP. The core of this matching resides in `chips.rs`:
In this case, the i2c version corresponds to our "v2" and the general purpose timer version corresponds to our "v1". Therefore, the `i2c_v2.yaml` and `timer_v1.yaml` register block implementations are assigned to those IP, respectively. The result is that these lines arr generated in `STM32F051K4.json`:
[source,json]
----
{
"name": "I2C1",
"address": 1073763328,
"registers": {
"kind": "i2c",
"version": "v2",
"block": "I2C"
},
// snip
}
// snip
{
"name": "TIM1",
"address": 1073818624,
"registers": {
"kind": "timer",
"version": "v1",
"block": "TIM_ADV"
},
// snip
}
----
In addition to register blocks, data for pin and RCC mapping is also generated and consumed by `embassy-stm32`. `stm32-metapac-gen` is used to package and publish the data as a crate.
== `embassy-stm32`
In the `lib.rs` file located in the root of `embassy-stm32`, you'll see this line:
[source,rust]
----
#[cfg(i2c)]
pub mod i2c;
----
And in the `mod.rs` of the i2c mod, you'll see this:
[source,rust]
----
#[cfg_attr(i2c_v2, path = "v2.rs")]
----
Because i2c is supported for STM32F051K4 and its version corresponds to our "v2", the `i2c` and `i2c_v2`, configuration directives will be present, and `embassy-stm32` will include these files, respectively. This and other configuration directives and tables are generated from the data for chip, allowing `embassy-stm32` to expressively and clearly adapt logic and implementations to what is required for each chip. Compared to other projects across the embedded ecosystem, `embassy-stm32` is the only project that can re-use code across the entire stm32 lineup and remove difficult-to-implement unsafe logic to the HAL.
Here are known examples of real-world projects which make use of Embassy. Feel free to link:https://github.com/embassy-rs/embassy/blob/main/docs/modules/ROOT/pages/embassy_in_the_wild.adoc[add more]!
* link:https://github.com/cbruiz/printhor/[Printhor: The highly reliable but not necessarily functional 3D printer firmware]
** Targets some STM32 MCUs
* link:https://github.com/card-io-ecg/card-io-fw[Card/IO firmware] - firmware for an open source ECG device
** Targets the ESP32-S3 or ESP32-C6 MCU
* The link:https://github.com/lora-rs/lora-rs[lora-rs] project includes link:https://github.com/lora-rs/lora-rs/tree/main/examples/stm32l0/src/bin[various standalone examples] for NRF52840, RP2040, STM32L0 and STM32WL
These are a list of unsorted, commonly asked questions and answers.
Please feel free to add items to link:https://github.com/embassy-rs/embassy/edit/main/docs/modules/ROOT/pages/faq.adoc[this page], especially if someone in the chat answered a question for you!
== How to deploy to RP2040 without a debugging probe.
Install link:https://github.com/JoNil/elf2uf2-rs[elf2uf2-rs] for converting the generated elf binary into a uf2 file.
Configure the runner to use this tool, add this to `.cargo/config.toml`:
The command-line parameters `--deploy` will detect your device and upload the binary, `--serial` starts a serial connection. See the documentation for more info.
== Missing main macro
If you see an error like this:
[source,rust]
----
#[embassy_executor::main]
| ^^^^ could not find `main` in `embassy_executor`
----
You are likely missing some features of the `embassy-executor` crate.
For Cortex-M targets, consider making sure that ALL of the following features are active in your `Cargo.toml` for the `embassy-executor` crate:
* `arch-cortex-m`
* `executor-thread`
* `nightly`
For Xtensa ESP32, consider using the executors and `#[main]` macro provided by your appropriate link:https://crates.io/crates/esp-hal-common[HAL crate].
== Why is my binary so big?
The first step to managing your binary size is to set up your link:https://doc.rust-lang.org/cargo/reference/profiles.html[profiles].
[source,toml]
----
[profile.release]
debug = false
lto = true
opt-level = "s"
incremental = false
codegen-units = 1
----
All of these flags are elaborated on in the Rust Book page linked above.
=== My binary is still big... filled with `std::fmt` stuff!
This means your code is sufficiently complex that `panic!` invocation's formatting requirements could not be optimized out, despite your usage of `panic-halt` or `panic-reset`.
You can remedy this by adding the following to your `.cargo/config.toml`:
[source,toml]
----
[unstable]
build-std = ["core"]
build-std-features = ["panic_immediate_abort"]
----
This replaces all panics with a `UDF` (undefined) instruction.
Depending on your chipset, this will exhibit different behavior.
Refer to the spec for your chipset, but for `thumbv6m`, it results in a hardfault. Which can be configured like so:
>>> referenced by driver.rs:127 (src/driver.rs:127)
>>> embassy_time-846f66f1620ad42c.embassy_time.4f6a638abb75dd4c-cgu.0.rcgu.o:(embassy_time::driver::now::hefb1f99d6e069842) in archive Devel/Embedded/pogodyna/target/thumbv7em-none-eabihf/debug/deps/libembassy_time-846f66f1620ad42c.rlib
>>> referenced by driver.rs:134 (src/driver.rs:134)
>>> embassy_time-846f66f1620ad42c.embassy_time.4f6a638abb75dd4c-cgu.0.rcgu.o:(embassy_time::driver::allocate_alarm::hf5145b6bd46706b2) in archive Devel/Embedded/pogodyna/target/thumbv7em-none-eabihf/debug/deps/libembassy_time-846f66f1620ad42c.rlib
>>> referenced by driver.rs:139 (src/driver.rs:139)
>>> embassy_time-846f66f1620ad42c.embassy_time.4f6a638abb75dd4c-cgu.0.rcgu.o:(embassy_time::driver::set_alarm_callback::h24f92388d96eafd2) in archive Devel/Embedded/pogodyna/target/thumbv7em-none-eabihf/debug/deps/libembassy_time-846f66f1620ad42c.rlib
>>> referenced by driver.rs:144 (src/driver.rs:144)
>>> embassy_time-846f66f1620ad42c.embassy_time.4f6a638abb75dd4c-cgu.0.rcgu.o:(embassy_time::driver::set_alarm::h530a5b1f444a6d5b) in archive Devel/Embedded/pogodyna/target/thumbv7em-none-eabihf/debug/deps/libembassy_time-846f66f1620ad42c.rlib
----
You probably need to enable a time driver for your HAL (not in `embassy-time`!). For example with `embassy-stm32`, you might need to enable `time-driver-any`:
[source,toml]
----
[dependencies.embassy-stm32]
version = "0.1.0"
features = [
# ...
"time-driver-any", # Add this line!
# ...
]
----
== Error: `Only one package in the dependency graph may specify the same links value.`
You have multiple versions of the same crate in your dependency tree. This means that some of your
embassy crates are coming from crates.io, and some from git, each of them pulling in a different set
of dependencies.
To resolve this issue, make sure to only use a single source for all your embassy crates! To do this,
you should patch your dependencies to use git sources using `[patch.crates.io]` and maybe `[patch.'https://github.com/embassy-rs/embassy.git']`.
** make `main`` spawn everything, then enable link:https://docs.rs/cortex-m/latest/cortex_m/peripheral/struct.SCB.html#method.set_sleeponexit[SCB.SLEEPONEXIT] and `loop { cortex_m::asm::wfi() }`
** *Note:* If you need 2 priority levels, using 2 interrupt executors is better than 1 thread executor + 1 interrupt executor.
So you want to try Embassy, great! To get started, there are a few tools you need to install:
* link:https://rustup.rs/[rustup] - the Rust toolchain is needed to compile Rust code.
* link:https://crates.io/crates/probe-run[probe-run] - to flash the firmware on your device. If you already have other tools like `OpenOCD` setup, you can use that as well.
* link:https://crates.io/crates/probe-rs[probe-rs] - to flash the firmware on your device. If you already have other tools like `OpenOCD` setup, you can use that as well.
If you don't have any supported board, don't worry: you can also run embassy on your PC using the `std` examples.
== Getting a board with examples
Embassy supports many microcontroller families, but the easiest ways to get started is if you have one of the more common development kits.
Embassy supports many microcontroller families, but the quickest way to get started is by using a board which Embassy has existing example code for.
This list is non-exhaustive. If your board isn’t included here, check the link:https://github.com/embassy-rs/embassy/tree/main/examples[examples folder] to see if example code has been written for it.
=== nRF kits
@ -30,28 +32,94 @@ Embassy supports many microcontroller families, but the easiest ways to get star
* link:https://www.raspberrypi.com/products/raspberry-pi-pico/[Raspberry Pi Pico]
You can run an example by opening a terminal and entering the following commands:
Once you have a copy of the repository, find examples folder for your board and, and build an example program. `blinky` is a good choice as all it does is blink an LED – the embedded world’s equivalent of “Hello World”.
[source, bash]
----
cd examples/nrf52840
cargo build --bin blinky --release
----
Once you’ve confirmed you can build the example, connect your computer to your board with a debug probe and run it on hardware:
[source, bash]
----
cargo run --bin blinky --release
----
== Whats next?
If everything worked correctly, you should see a blinking LED on your board, and debug output similar to this on your computer:
Congratulations, you have your first Embassy application running! Here are some alternatives on where to go from here:
[source]
----
Finished dev [unoptimized + debuginfo] target(s) in 1m 56s
NOTE: How does the `cargo run` command know how to connect to our board and program it? In each `examples` folder, there’s a `.cargo/config.toml` file which tells cargo to use link:https://probe.rs/[probe-rs] as the runner for ARM binaries in that folder. probe-rs handles communication with the debug probe and MCU. In order for this to work, probe-rs needs to know which chip it’s programming, so you’ll have to edit this file if you want to run examples on other chips.
=== It didn’t work!
If you hare having issues when running `cargo run --release`, please check the following:
* You are specifying the correct `--chip on the command line``, OR
* You have set `.cargo/config.toml`'s run line to the correct chip, AND
* You have changed `examples/Cargo.toml`'s HAL (e.g. embassy-stm32) dependency's feature to use the correct chip (replace the existing stm32xxxx feature)
At this point the project should run. If you do not see a blinky LED for blinky, for example, be sure to check the code is toggling your board's LED pin.
If you are trying to run an example with `cargo run --release` and you see the following output:
To get rid of the frame-index error add the following to your `Cargo.toml`:
[source,toml]
----
[profile.release]
debug = 2
----
If you’re still having problems, check the link:https://embassy.dev/book/dev/faq.html[FAQ], or ask for help in the link:https://matrix.to/#/#embassy-rs:matrix.org[Embassy Chat Room].
== What's next?
Congratulations, you have your first Embassy application running! Here are some suggestions for where to go from here:
* Read more about the xref:runtime.adoc[executor].
@ -4,31 +4,61 @@ Embassy is a project to make async/await a first-class option for embedded devel
== What is async?
Software written without async may block on I/O operations. In an std environment, such as a PC, software can handle this either by using threads or non-blocking operations.
When handling I/O, software must call functions that block program execution until the I/O operation completes. When running inside of an OS such as Linux, such functions generally transfer control to the kernel so that another task (known as a “thread”) can be executed if available, or the CPU can be put to sleep until another task is ready.
With threads, one thread blocks on an I/O operation, another is able to take its place. However, even on a PC, threads are relatively heavy, and therefore some programming languages, such as Go, have implemented a concept called coroutines or 'goroutines' that are much lighter and less-intensive than threads.
Because an OS cannot presume that threads will behave cooperatively, threads are relatively resource-intensive, and may be forcibly interrupted they do not transfer control back to the kernel within an allotted time. If tasks could be presumed to behave cooperatively, or at least not maliciously, it would be possible to create tasks that appear to be almost free when compared to a traditional OS thread.
The other way to handle blocking I/O operations is to support polling the state of the underlying peripherals to check whether it is available to perform the requested operation. In programming languages without builtin async support,
this requires building a complex loop checking for events.
In other programming languages, these lightweight tasks are known as “coroutines” or ”goroutines”. In Rust, they are implemented with async. Async-await works by transforming each async function into an object called a future. When a future blocks on I/O the future yields, and the scheduler, called an executor, can select a different future to execute.
In Rust, non-blocking operations can be implemented using async-await. Async-await works by transforming each async function into an object called a future. When a future blocks on I/O the future yields, and the scheduler, called an executor, can select a different future to execute. Compared to alternatives such as an RTOS, async can yield better performance and lower power consumption because the executor doesn't have to guess when a future is ready to execute. However, program size may be higher than other alternatives, which may be a problem for certain space-constrained devices with very low memory. On the devices Embassy supports, such as stm32 and nrf, memory is generally large enough to accommodate the modestly-increased program size.
Compared to alternatives such as an RTOS, async can yield better performance and lower power consumption because the executor doesn't have to guess when a future is ready to execute. However, program size may be higher than other alternatives, which may be a problem for certain space-constrained devices with very low memory. On the devices Embassy supports, such as stm32 and nrf, memory is generally large enough to accommodate the modestly-increased program size.
== What is Embassy?
The Embassy project consists of several crates that you can use together or independently:
* **Executor** - The link:https://docs.embassy.dev/embassy-executor/[embassy-executor] is an async/await executor that generally executes a fixed number of tasks, allocated at startup, though more can be added later. The HAL is an API that you can use to access peripherals, such as USART, UART, I2C, SPI, CAN, and USB. Embassy provides implementations of both async and blocking APIs where it makes sense. DMA (Direct Memory Access) is an example where async is a good fit, whereas GPIO states are a better fit for a blocking API. The executor may also provide a system timer that you can use for both async and blocking delays. For less than one microsecond, blocking delays should be used because the cost of context-switching is too high and the executor will be unable to provide accurate timing.
=== Executor
The link:https://docs.embassy.dev/embassy-executor/[embassy-executor] is an async/await executor that generally executes a fixed number of tasks, allocated at startup, though more can be added later. The executor may also provide a system timer that you can use for both async and blocking delays. For less than one microsecond, blocking delays should be used because the cost of context-switching is too high and the executor will be unable to provide accurate timing.
* **Hardware Abstraction Layers** - HALs implement safe, idiomatic Rust APIs to use the hardware capabilities, so raw register manipulation is not needed. The Embassy project maintains HALs for select hardware, but you can still use HALs from other projects with Embassy.
** link:https://docs.embassy.dev/embassy-stm32/[embassy-stm32], for all STM32 microcontroller families.
** link:https://docs.embassy.dev/embassy-nrf/[embassy-nrf], for the Nordic Semiconductor nRF52, nRF53, nRF91 series.
=== Hardware Abstraction Layers
HALs implement safe Rust API which let you use peripherals such as USART, UART, I2C, SPI, CAN, and USB without having to directly manipulate registers.
* **Networking** - The link:https://docs.embassy.dev/embassy-net/[embassy-net] network stack implements extensive networking functionality, including Ethernet, IP, TCP, UDP, ICMP and DHCP. Async drastically simplifies managing timeouts and serving multiple connections concurrently.
Embassy provides implementations of both async and blocking APIs where it makes sense. DMA (Direct Memory Access) is an example where async is a good fit, whereas GPIO states are a better fit for a blocking API.
* **Bluetooth** - The link:https://github.com/embassy-rs/nrf-softdevice[nrf-softdevice] crate provides Bluetooth Low Energy 4.x and 5.x support for nRF52 microcontrollers.
The Embassy project maintains HALs for select hardware, but you can still use HALs from other projects with Embassy.
* **LoRa** - link:https://docs.embassy.dev/embassy-lora/[embassy-lora] supports LoRa networking on STM32WL wireless microcontrollers and Semtech SX127x transceivers.
* link:https://docs.embassy.dev/embassy-stm32/[embassy-stm32], for all STM32 microcontroller families.
* link:https://docs.embassy.dev/embassy-nrf/[embassy-nrf], for the Nordic Semiconductor nRF52, nRF53, nRF91 series.
* link:https://docs.embassy.dev/embassy-rp/[embassy-rp], for the Raspberry Pi RP2040 microcontroller.
* link:https://github.com/esp-rs[esp-rs], for the Espressif Systems ESP32 series of chips.
* **USB** - link:https://docs.embassy.dev/embassy-usb/[embassy-usb] implements a device-side USB stack. Implementations for common classes such as USB serial (CDC ACM) and USB HID are available, and a rich builder API allows building your own.
NOTE: A common question is if one can use the Embassy HALs standalone. Yes, it is possible! There are no dependency on the executor within the HALs. You can even use them without async,
as they implement both the link:https://github.com/rust-embedded/embedded-hal[Embedded HAL] blocking and async traits.
* **Bootloader and DFU** - link:https://github.com/embassy-rs/embassy/tree/master/embassy-boot[embassy-boot] is a lightweight bootloader supporting firmware application upgrades in a power-fail-safe way, with trial boots and rollbacks.
=== Networking
The link:https://docs.embassy.dev/embassy-net/[embassy-net] network stack implements extensive networking functionality, including Ethernet, IP, TCP, UDP, ICMP and DHCP. Async drastically simplifies managing timeouts and serving multiple connections concurrently. Several drivers for WiFi and Ethernet chips can be found.
=== Bluetooth
The link:https://github.com/embassy-rs/nrf-softdevice[nrf-softdevice] crate provides Bluetooth Low Energy 4.x and 5.x support for nRF52 microcontrollers.
=== LoRa
link:https://github.com/embassy-rs/lora-phy[lora-phy] and link:https://docs.embassy.dev/embassy-lora/[embassy-lora] supports LoRa networking on a wide range of LoRa radios, fully integrated with a Rust link:https://github.com/ivajloip/rust-lorawan[LoRaWAN] implementation.
=== USB
link:https://docs.embassy.dev/embassy-usb/[embassy-usb] implements a device-side USB stack. Implementations for common classes such as USB serial (CDC ACM) and USB HID are available, and a rich builder API allows building your own.
=== Bootloader and DFU
link:https://github.com/embassy-rs/embassy/tree/master/embassy-boot[embassy-boot] is a lightweight bootloader supporting firmware application upgrades in a power-fail-safe way, with trial boots and rollbacks.
== What is DMA?
For most I/O in embedded devices, the peripheral doesn't directly support the transmission of multiple bits at once, with CAN being a notable exception. Instead, the MCU must write each byte, one at a time, and then wait until the peripheral is ready to send the next. For high I/O rates, this can pose a problem if the MCU must devote an increasing portion of its time handling each byte. The solution to this problem is to use the Direct Memory Access controller.
The Direct Memory Access controller (DMA) is a controller that is present in MCUs that Embassy supports, including stm32 and nrf. The DMA allows the MCU to set up a transfer, either send or receive, and then wait for the transfer to complete. With DMA, once started, no MCU intervention is required until the transfer is complete, meaning that the MCU can perform other computation, or set up other I/O while the transfer is in progress. For high I/O rates, DMA can cut the time that the MCU spends handling I/O by over half. However, because DMA is more complex to set-up, it is less widely used in the embedded community. Embassy aims to change that by making DMA the first choice rather than the last. Using Embassy, there's no additional tuning required once I/O rates increase because your application is already set-up to handle them.
== Resources
For more reading material on async Rust and Embassy:
* link:https://tweedegolf.nl/en/blog/65/async-rust-vs-rtos-showdown[Comparsion of FreeRTOS and Embassy]
If you're new to Embassy, it can be overwhelming to grasp all the terminology and concepts. This guide aims to clarify the different layers in Embassy, which problem each layer solves for the application writer.
@ -8,8 +8,7 @@ The application we'll write is a simple 'push button, blink led' application, wh
== PAC version
The PAC is the lowest API for accessing peripherals and registers, if you don't count reading/writing directly to memory addresses. It provides distinct types
to make accessing peripheral registers easier, but it does not prevent you from writing unsafe code.
The PAC is the lowest API for accessing peripherals and registers, if you don't count reading/writing directly to memory addresses. It provides distinct types to make accessing peripheral registers easier, but it does not prevent you from writing unsafe code.
Writing an application using the PAC directly is therefore not recommended, but if the functionality you want to use is not exposed in the upper layers, that's what you need to use.
Once you’ve successfully xref:getting_started.adoc[run some example projects], the next step is to make a standalone Embassy project. The easiest way to do this is to adapt an example for a similar chip to the one you’re targeting.
As an example, let’s create a new embassy project from scratch for a STM32G474. The same instructions are applicable for any supported chip with some minor changes.
Run:
[source,bash]
----
cargo new stm32g474-example
cd stm32g474-example
----
to create an empty rust project:
[source]
----
stm32g474-example
├── Cargo.toml
└── src
└── main.rs
----
Looking in link:https://github.com/embassy-rs/embassy/tree/main/examples[the Embassy examples], we can see there’s a `stm32g4` folder. Find `src/blinky.rs` and copy its contents into our `src/main.rs`.
== .cargo/config.toml
Currently, we’d need to provide cargo with a target triple every time we run `cargo build` or `cargo run`. Let’s spare ourselves that work by copying `.cargo/config.toml` from `examples/stm32g4` into our project.
[source]
----
stm32g474-example
├── .cargo
│ └── config.toml
├── Cargo.toml
└── src
└── main.rs
----
In addition to a target triple, `.cargo/config.toml` contains a `runner` key which allows us to conveniently run our project on hardware with `cargo run` via probe-rs. In order for this to work, we need to provide the correct chip ID. We can do this by checking `probe-rs chip list`:
[source,bash]
----
$ probe-rs chip list | grep -i stm32g474re
STM32G474RETx
----
and copying `STM32G474RETx` into `.cargo/config.toml` as so:
# replace STM32G071C8Rx with your chip as listed in `probe-rs chip list`
runner = "probe-rs run --chip STM32G474RETx"
----
== Cargo.toml
Now that cargo knows what target to compile for (and probe-rs knows what chip to run it on), we’re ready to add some dependencies.
Looking in `examples/stm32g4/Cargo.toml`, we can see that the examples require a number of embassy crates. For blinky, we’ll only need three of them: `embassy-stm32`, `embassy-executor` and `embassy-time`.
At the time of writing, the latest version of embassy isn‘t available on crates.io, so we need to install it straight from the git repository. The recommended way of doing so is as follows:
* Copy the required `embassy-*` lines from the example `Cargo.toml`
* Make any necessary changes to `features`, e.g. requiring the `stm32g474re` feature of `embassy-stm32`
* Remove the `path = ""` keys in the `embassy-*` entries
* Create a `[patch.crates-io]` section, with entries for each embassy crate we need. These should all contain identical values: a link to the git repository, and a reference to the commit we’re checking out. Assuming you want the latest commit, you can find it by running `git ls-remote https://github.com/embassy-rs/embassy.git HEAD`
NOTE: When using this method, it’s necessary that the `version` keys in `[dependencies]` match up with the versions defined in each crate’s `Cargo.toml` in the specificed `rev` under `[patch.crates.io]`. This means that when updating, you have to a pick a new revision, change everything in `[patch.crates.io]` to match it, and then correct any versions under `[dependencies]` which have changed. Hopefully this will no longer be necessary once embassy is released on crates.io!
At the time of writing, this method produces the following results:
There are a few other dependencies we need to build the project, but fortunately they’re much simpler to install. Copy their lines from the example `Cargo.toml` to the the `[dependencies]` section in the new `Cargo.toml`:
[source,toml]
----
defmt = "0.3.5"
defmt-rtt = "0.4.0"
cortex-m = {version = "0.7.7", features = ["critical-section-single-core"]}
cortex-m-rt = "0.7.3"
panic-probe = "0.3.1"
----
These are the bare minimum dependencies required to run `blinky.rs`, but it’s worth taking a look at the other dependencies specified in the example `Cargo.toml`, and noting what features are required for use with embassy – for example `futures = { version = "0.3.17", default-features = false, features = ["async-await"] }`.
Finally, copy the `[profile.release]` section from the example `Cargo.toml` into ours.
[source,toml]
----
[profile.release]
debug = 2
----
== rust-toolchain.toml
Before we can build our project, we need to add an additional file to tell cargo to use the nightly toolchain. Copy the `rust-toolchain.toml` from the embassy repo to ours, and trim the list of targets down to only the target triple relevent for our project — in this case, `thumbv7em-none-eabi`:
[source]
----
stm32g474-example
├── .cargo
│ └── config.toml
├── Cargo.toml
├── rust-toolchain.toml
└── src
└── main.rs
----
[source,toml]
----
# Before upgrading check that everything is available on all tier1 targets here:
There are many ways to configure embassy and its components for your exact application. The link:https://github.com/embassy-rs/embassy/tree/main/examples[examples] directory for each chipset demonstrates how your project structure should look. Let's break it down:
The toplevel file structure of your project should look like this:
[source,plain]
----
{} = Maybe
my-project
|- .cargo
| |- config.toml
|- src
| |- main.rs
|- build.rs
|- Cargo.toml
|- {memory.x}
|- rust-toolchain.toml
----
=== .cargo/config.toml
This directory/file describes what platform you're on, and configures link:https://github.com/probe-rs/probe-rs[probe-rs] to deploy to your device.
Here is a minimal example:
[source,toml]
----
[target.thumbv6m-none-eabi] # <-change for your platform
runner = 'probe-rs run --chip STM32F031K6Tx' # <- change for your chip
[build]
target = "thumbv6m-none-eabi" # <-change for your platform
[env]
DEFMT_LOG = "trace" # <- can change to info, warn, or error
----
=== build.rs
This is the build script for your project. It links defmt (what is defmt?) and the `memory.x` file if needed. This file is pretty specific for each chipset, just copy and paste from the corresponding link:https://github.com/embassy-rs/embassy/tree/main/examples[example].
=== Cargo.toml
This is your manifest file, where you can configure all of the embassy components to use the features you need.
TODO: someone should exhaustively describe every feature for every component!
=== memory.x
This file outlines the flash/ram usage of your program. It is especially useful when using link:https://github.com/embassy-rs/nrf-softdevice[nrf-softdevice] on an nRF5x.
Here is an example for using S140 with an nRF52840:
[source,x]
----
MEMORY
{
/* NOTE 1 K = 1 KiBi = 1024 bytes */
/* These values correspond to the NRF52840 with Softdevices S140 7.0.1 */
FLASH : ORIGIN = 0x00027000, LENGTH = 868K
RAM : ORIGIN = 0x20020000, LENGTH = 128K
}
----
=== rust-toolchain.toml
This file configures the rust version and configuration to use.
A minimal example:
[source,toml]
----
[toolchain]
channel = "nightly-2023-08-19" # <- as of writing, this is the exact rust version embassy uses
components = [ "rust-src", "rustfmt" ] # <- optionally add "llvm-tools-preview" for some extra features like "cargo size"
@ -6,11 +6,11 @@ The Embassy executor is an async/await executor designed for embedded usage alon
* No `alloc`, no heap needed. Task are statically allocated.
* No "fixed capacity" data structures, executor works with 1 or 1000 tasks without needing config/tuning.
* Integrated timer queue: sleeping is easy, just do `Timer::after(Duration::from_secs(1)).await;`.
* Integrated timer queue: sleeping is easy, just do `Timer::after_secs(1).await;`.
* No busy-loop polling: CPU sleeps when there's no work to do, using interrupts or `WFE/SEV`.
* Efficient polling: a wake will only poll the woken task, not all of them.
* Fair: a task can't monopolize CPU time even if it's constantly being woken. All other tasks get a chance to run before a given task gets polled for the second time.
* Creating multiple executor instances is supported, to run tasks with multiple priority levels. This allows higher-priority tasks to preempt lower-priority tasks.
* Creating multiple executor instances is supported, to run tasks at different priority levels. This allows higher-priority tasks to preempt lower-priority tasks.
== Executor
@ -27,7 +27,7 @@ If you use the `#[embassy_executor::main]` macro in your application, it creates
Interrupts are a common way for peripherals to signal completion of some operation and fits well with the async execution model. The following diagram describes a typical application flow where (1) a task is polled and is attempting to make progress. The task then (2) instructs the peripheral to perform some operation, and awaits. After some time has passed, (3) an interrupt is raised, marking the completion of the operation.
The peripheral HAL then (4) ensures that interrupt signals are routed to to the peripheral and updating the peripheral state with the results of the operation. The executor is then (5) notified that the task should be polled, which it will do.
The peripheral HAL then (4) ensures that interrupt signals are routed to the peripheral and updating the peripheral state with the results of the operation. The executor is then (5) notified that the task should be polled, which it will do.
@ -8,16 +8,36 @@ The bootloader can be used either as a library or be flashed directly with the d
By design, the bootloader does not provide any network capabilities. Networking capabilities for fetching new firmware can be provided by the user application, using the bootloader as a library for updating the firmware, or by using the bootloader as a library and adding this capability yourself.
## Overview
The bootloader divides the storage into 4 main partitions, configurable when creating the bootloader instance or via linker scripts:
* BOOTLOADER - Where the bootloader is placed. The bootloader itself consumes about 8kB of flash, but if you need to debug it and have space available, increasing this to 24kB will allow you to run the bootloader with probe-rs.
* ACTIVE - Where the main application is placed. The bootloader will attempt to load the application at the start of this partition. The minimum size required for this partition is the size of your application.
* DFU - Where the application-to-be-swapped is placed. This partition is written to by the application. This partition must be at least 1 page bigger than the ACTIVE partition.
* BOOTLOADER STATE - Where the bootloader stores the current state describing if the active and dfu partitions need to be swapped.
For any partition, the following preconditions are required:
* Partitions must be aligned on the page size.
* Partitions must be a multiple of the page size.
The linker scripts for the application and bootloader look similar, but the FLASH region must point to the BOOTLOADER partition for the bootloader, and the ACTIVE partition for the application.
For more details on the bootloader, see [the documentation](https://embassy.dev/book/dev/bootloader.html).
## Hardware support
The bootloader supports different hardware in separate crates:
*`embassy-boot-nrf` - for the nRF microcontrollers.
*`embassy-boot-rp` - for the RP2040 microcontrollers.
*`embassy-boot-stm32` - for the STM32 microcontrollers.
## Minimum supported Rust version (MSRV)
`embassy-boot`requires Rust nightly to compile as it relies on async traits for interacting with the flash peripherals.
`embassy-boot`is guaranteed to compile on the latest stable Rust version at the time of release. It might compile with older versions but that may change in any new patch release.
/// Firmware updater flash configuration holding the two flashes used by the updater
///
/// If only a single flash is actually used, then that flash should be partitioned into two partitions before use.
/// The easiest way to do this is to use [`FirmwareUpdaterConfig::from_linkerfile`] or [`FirmwareUpdaterConfig::from_linkerfile_blocking`] which will partition
/// the provided flash according to symbols defined in the linkerfile.
@ -6,14 +6,14 @@ An adaptation of `embassy-boot` for nRF.
## Features
* Load applications with our without the softdevice.
* Load applications with or without the softdevice.
* Configure bootloader partitions based on linker script.
* Using watchdog timer to detect application failure.
## Minimum supported Rust version (MSRV)
`embassy-boot-nrf`requires Rust nightly to compile as it relies on async traits for interacting with the flash peripherals.
`embassy-boot-nrf`is guaranteed to compile on the latest stable Rust version at the time of release. It might compile with older versions but that may change in any new patch release.
@ -13,7 +13,7 @@ NOTE: The applications using this bootloader should not link with the `link-rp.x
## Minimum supported Rust version (MSRV)
`embassy-boot-rp`requires Rust nightly to compile as it relies on async traits for interacting with the flash peripherals.
`embassy-boot-rp`is guaranteed to compile on the latest stable Rust version at the time of release. It might compile with older versions but that may change in any new patch release.
@ -11,7 +11,7 @@ An adaptation of `embassy-boot` for STM32.
## Minimum supported Rust version (MSRV)
`embassy-boot-stm32`requires Rust nightly to compile as it relies on async traits for interacting with the flash peripherals.
`embassy-boot-stm32`is guaranteed to compile on the latest stable Rust version at the time of release. It might compile with older versions but that may change in any new patch release.
/// A type which can be used as state with `PeripheralMutex`.
///
/// It needs to be `Send` because `&mut` references are sent back and forth between the 'thread' which owns the `PeripheralMutex` and the interrupt,
/// and `&mut T` is only `Send` where `T: Send`.
pubtraitPeripheralState: Send{
/// The interrupt that is used for this peripheral.
typeInterrupt: Interrupt;
/// The interrupt handler that should be invoked for the peripheral. Implementations need to clear the appropriate interrupt flags to ensure the handle will not be called again.
fnon_interrupt(&mutself);
}
/// A type for storing the state of a peripheral that can be stored in a static.
pubstructStateStorage<S>(MaybeUninit<S>);
impl<S>StateStorage<S>{
/// Create a new instance for storing peripheral state.
pubconstfnnew()-> Self{
Self(MaybeUninit::uninit())
}
}
/// A type for a peripheral that keeps the state of a peripheral that can be accessed from thread mode and an interrupt handler in
/// a safe way.
pubstructPeripheralMutex<'a,S: PeripheralState>{
state: *mutS,
irq: PeripheralRef<'a,S::Interrupt>,
}
/// Whether `irq` can be preempted by the current interrupt.
// On failure, it's important to still flush and deassert CS.
Some files were not shown because too many files have changed in this diff
Show More
Reference in New Issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.