* Add FlashProvider and FlashConfig traits to define flash
characteristics
* Use traits in bootloader to retrieve flash handles and for
copying data between flash instances
* Add convenience implementations for using a single flash instance.
* Adds implementations of embedded-storage and embedded-storage-async
for QSPI
* Add blocking implementations of QSPI
* Use blocking implementation in new() and embedded-storage impls
* Use async implementation in embedded-storage-async impls
* Add FLASH_SIZE const generic parameter
* Own IRQ in Qspi to disable it on drop
- Renamed structs to HidReaderWriter, HidReader, HidWriter.
- Removed unused const generics on `State`.
- Simplified generics on `HidReaderWriter`.
The class type previously was `HidClass<D, Driver<'d, USBD>, ReportReader<'d, Driver<'d, USBD>, OUT_N>, IN_N>`
It's now `HidClass<D, Driver<'d, USBD>, IN_N, OUT_N>`. Note that the driver type `Driver<'d, USBD>` is no longer repeated.
- Constructors are now: `HidWriter::new()` for IN-only, `HidReaderWriter::new()` for IN+OUT. No complicated bounds.
- HidReaderWriter has all the methods from HidReader, HidWriter.
711: Add DeviceStateHandler, DeviceCommand channel, and remote wakeup support r=Dirbaio a=alexmoon
Apologies for the size of this PR. Once I started getting into the Vbus power management side of my device I found a couple of areas of functionality missing from embassy-usb. Specifically, I need the application to be able to respond to changes in the USB device state in order to properly control the amount of power I'm drawing from Vbus. I also wanted to enable remote wakeup support for my device.
In order to enable device state monitoring, I've created a `DeviceStateHandler` trait and made it possible to pass in an optional reference a handler implementing that trait when creating the `UsbDeviceBuilder`.
Remote wakeup required a way to send commands to the bus which is exclusively owned by the `UsbDevice::run` method. This is the same problem we were discussing for enabling/disabling the device on Vbus power events. My solution is to allow an optional `Channel` to be provided to the `UsbDeviceBuilder` (via `UsbDeviceBuilder::new_with_channel`), allowing the application to send commands into the `run` method. Right now it supports enable, disable and remote wakeup commands.
Since there's now a way to dynamically enable and disable the device, I also added `Config::start_enabled` to control whether or not the `UsbDevice` should start in the enabled state. That also allowed me to make `UsbDeviceBuilder::build` sync again and move enabling the bus into `UsbDevice::run`.
This led to a few driver changes:
1. `Driver::enable` became `Driver::into_bus`
2. `Bus::enable`, `Bus::disable`, and `Bus::remote_wakeup` were added
3. I removed `Bus::reset`, `Bus::suspend`, and `Bus::resume` because they were only ever called based on the result of `Bus::poll`. It made more sense to me to have `Bus::poll` handle the driver-specific state management itself.
I've updated the `usb_hid_keyboard` example to take advantage of all these additional features.
Let me know what you think.
Thanks!
Co-authored-by: alexmoon <alex.r.moon@gmail.com>
714: add more clock options for l4 and l5 r=Dirbaio a=ant32
- added an assert so it panics if pll48div is not 48Mhz
- added MSI as a clock source for PLL
- removed hsi48 option for MCUs mentioned in l4 rcc presentation
- copied some code from l4 to l5, but don't have a way of testing it.
Co-authored-by: Philip A Reimer <antreimer@gmail.com>
657: Async usb stack r=Dirbaio a=Dirbaio
TODO
- [x] Make it work on nRF
- [x] Add a way for classes to handle their own EP0 control requests - thanks `@alexmoon!`
- [x] Handle CONTROL OUT requests with data.
- [ ] Impl AsyncRead/AsyncWrite for CDC ACM -- will do later, it's not trivial
- [x] Cleanup unwraps/asserts/panics
- [x] Cleanup logs (make everything trace/debug, not info)
- [ ] Port synopsys-usb-otg
- [ ] Port stm32-usbd
- [ ] Add more classes? HID, MSD?
Co-authored-by: Dario Nieuwenhuis <dirbaio@dirbaio.net>
Co-authored-by: alexmoon <alex.r.moon@gmail.com>
696: Add async Mutex. r=Dirbaio a=Dirbaio
What it says on the tin :)
It allows sharing data between tasks when you want to `.await` stuff while holding it locked.
Co-authored-by: Dario Nieuwenhuis <dirbaio@dirbaio.net>
- Allow initializing in a static, without Forever.
- Remove ability to close, since in embedded enviromnents channels usually live forever and don't get closed.
- Remove MPSC restriction, it's MPMC now. Rename "mpsc" to "channel".
- `Sender` and `Receiver` are still available if you want to enforce a piece of code only has send/receive access, but are optional: you can send/receive directly into the Channel if you want.
* Keeps existing API for usart, but wraps it in Tx and Rx sub-types
* Adds split() method similar to nRF for getting indepdendent TX and RX
parts
* Implements e-h traits for TX and RX types
* Add stm32h7 example
648: Fix nRF Saadc continuous sampling r=Dirbaio a=huntc
Starting the sampling task prior to starting the SAADC peripheral can lead to unexpected buffer behaviour with multiple channels. We now provide an init callback at the point where the SAADC has started for the first time. This callback can be used to kick off sampling via PPI.
We also need to trigger the SAADC to start sampling the next buffer when the previous one is ended so that we do not drop samples - the major benefit of double buffering.
Given these additional tasks, we now simplify the API by passing in the TIMER and two PPI channels.
As a bonus, we provide an async `calibrate` method as it is recommended to use before starting up the sampling.
The example has been updated to illustrate these new features along with the simplified API.
The changes here have been tested on my nRF52840-DK.
656: stm32: Refactor DMA interrupts r=Dirbaio a=GrantM11235
Previously, every dma interrupt handler called the same `on_irq`
function which had to check the state of every dma channel.
Now, each dma interrupt handler only calls an `on_irq` method for its
corresponding channel or channels.
Co-authored-by: huntc <huntchr@gmail.com>
Co-authored-by: Grant Miller <GrantM11235@gmail.com>
Starting the sampling task prior to starting the SAADC peripheral can lead to unexpected buffer behaviour with multiple channels. We now provide an init callback at the point where the SAADC has started for the first time. This callback can be used to kick off sampling via PPI.
We also need to trigger the SAADC to start sampling the next buffer when the previous one is ended so that we do not drop samples - the major benefit of double buffering.
As a bonus we provide a calibrate method as it is recommended to use before starting up the sampling.
The example has been updated to illustrate these new features.
608: stm32f4: add adc + example r=Dirbaio a=ain101
Example tested on stm32f407vg Discovery Board.
minimal adc: no vref, dma, complex sequence
Co-authored-by: Frederik <frederik@frederik.at>
613: Rust stable support r=Dirbaio a=Dirbaio
This PR adds (limited) stable Rust support!
The drawbacks are:
- No `#[embassy::task]`, `#[embassy::main]`. (requires `type_alias_impl_trait`). You have to manually allocate the tasks somewhere they'll live forever. See [example](https://github.com/embassy-rs/embassy/blob/master/examples/nrf/src/bin/raw_spawn.rs)
- No async trait impls (requires GATs). Note that the full API surface of HALs is still available through inherent methods: #552#581
- Some stuff is not constructible in const (requires `const_fn_trait_bound`), although there's an (ugly) workaround for the generic `Mutex`.
So it's not that bad in the end, it's fully usable for shipping production-ready firmwares. We'll still recommend nightly as the default, until GATs and `type_alias_impl_trait` are stable.
Co-authored-by: Dario Nieuwenhuis <dirbaio@dirbaio.net>
607: stm32: Add standard crate-wide macros for pin/dma traits r=Dirbaio a=Dirbaio
All drivers will declare the traits using these macros.
This has a few implications:
- ALL drivers will have an Instance trait, even for drivers that usually have only one instance (for example crc, eth)
- It's no longer possible to have a fn configure() in pin traits, drivers will have to do that some other way
In the future, build.rs will generate all the impls instead of macrotables.
Pin/Dma traits are no longer explicitly sealed, since gpio::Pin and dma::Channel are already sealed, which has the same effect. This means the `af_num()` and `request()` funcs are now public, but IMO that's okay, they're unlikely to change.
Co-authored-by: Dario Nieuwenhuis <dirbaio@dirbaio.net>
Embassy-boot is a simple bootloader that works together with an
application to provide firmware update capabilities with a minimal risk.
The bootloader consists of a platform-independent part, which implements
the swap algorithm, and a platform-dependent part (currently only for
nRF) that provides addition functionality such as watchdog timers
softdevice support.
602: Add stm32 USB OTG peripherals r=Dirbaio a=chemicstry
Fixes#557. This is similar to #580, but for synopsys IP.
I could add examples to other chips, but I have no way of testing them. The F4 example is tested and working.
Co-authored-by: chemicstry <chemicstry@gmail.com>
591: PWM WS2812B example and flexible sequence config r=Dirbaio a=huntc
I've permitted the PWM sequences to be mutated on stopping the PWM by associating them with a new `SingleSequencer` structure. This is so that we can perform effects on the LEDs (and other use-cases, I'm sure!). The example has been updated to illustrate the use of this by flashing a WS2812B LED.
There's also a `Sequencer` structure for more sophisticated PWM interactions, along with a `pwm_double_sequence` example to illustrate.
These changes should make it possible to attain all of the nRF PWM functionality available.
Co-authored-by: huntc <huntchr@gmail.com>
This approach owns the sequence buffers which, while introducing an extra move, it eliminates the need to guard the lifetime of the sequence buffer. Given ownership, the buffer will be retained until the PWM sequence task is stopped.
Demonstrates how to set the colour of a WS2812B to blue using PWM, and the use of multiple sequences along with their own config. This required an API change.
I had introduced a small bug in my last PR where I assigned the sequence before stopping the PWM. I now stop the PWM before doing that now.
Also, corrected a math comment.
585: Permit many sequences to be passed r=huntc a=huntc
Sequences are now passed in via the start method to avoid having to stop the PWM and restart it. Sequences continue to be constrained with the same lifetime of the Pwm struct itself. The pwm_sequence example has been extended to illustrate multiple sequences being passed around.
Co-authored-by: huntc <huntchr@gmail.com>
Sequences are now passed in via the start method to avoid having to stop the PWM and restart it. Sequences continue to be constrained with the same lifetime of the Pwm object itself. The pwm_sequence example has been extended to illustrate multiple sequences being passed around.
Unsafe is not required here given that all futures are required to live longer than their global peripheral instances. There are other occurrences of unsafe being used on new that should be removed. I started to do that but then went down a bit of a rabbit hole.
539: nrf: async usb r=Dirbaio a=jacobrosenthal
Frankensteined together from this old pr https://github.com/embassy-rs/embassy/pull/115 and nrf-usdb
~Doesnt currently work..~
Co-authored-by: Jacob Rosenthal <jacobrosenthal@gmail.com>
545: Add adapter for implementing async traits for blocking types r=lulf a=lulf
This allows writing drivers relying on async traits, while still
functioning with implementations that already implement the embedded-hal
traits.
Co-authored-by: Ulf Lilleengen <lulf@redhat.com>
563: Initial ADC support for on STM32F1xx r=Dirbaio a=sjoerdsimons
Add an ADC implementation for F1 based chips. Primarily tested using ADC1, proper functionality for ADC2 probably needs some extra work as it's mainly a slave and can't e.g. measure vrefint by itself.
Needs https://github.com/embassy-rs/stm32-data/pull/115
Co-authored-by: Sjoerd Simons <sjoerd@collabora.com>
Co-authored-by: Dario Nieuwenhuis <dirbaio@dirbaio.net>
This allows writing drivers relying on async traits, while still
functioning with implementations that already implement the embedded-hal
traits.
Add examples to stm32l4 for using this feature.
544: Introduces split on the nRF Uarte r=Dirbaio a=huntc
A new `split` method is introduced such that the Uarte tx and rx can be used from separate tasks. An MPSC is used in an example to illustrate how data may be passed between these tasks.
The approach taken within the `Uarte` struct is to split into tx and rx fields on calling `Uarte::new`. These fields are returned given a call to `Uarte::split`, but otherwise, if that call isn't made, then the API remains as it was before.
Here's a snippet from a new example introduced:
```rust
#[embassy::main]
async fn main(spawner: Spawner, p: Peripherals) {
// ...
let uart = uarte::Uarte::new(p.UARTE0, irq, p.P0_08, p.P0_06, NoPin, NoPin, config);
let (mut tx, rx) = uart.split();
// ...
// Spawn a task responsible purely for reading
unwrap!(spawner.spawn(reader(rx, s)));
// ...
// Continue reading in this main task and write
// back out the buffer we receive from the read
// task.
loop {
if let Some(buf) = r.recv().await {
info!("writing...");
unwrap!(tx.write(&buf).await);
}
}
}
#[embassy::task]
async fn reader(mut rx: UarteRx<'static, UARTE0>, s: Sender<'static, Noop, [u8; 8], 1>) {
let mut buf = [0; 8];
loop {
info!("reading...");
unwrap!(rx.read(&mut buf).await);
unwrap!(s.send(buf).await);
}
}
```
Co-authored-by: huntc <huntchr@gmail.com>
540: Initial support for STM32F3 r=Dirbaio a=VasanthakumarV
The [companion PR](https://github.com/embassy-rs/stm32-data/pull/109) in `stm32-data` should be merged before this PR.
The examples were tested on an STM32F303VC MCU.
Co-authored-by: VasanthakumarV <vasanth260m12@gmail.com>
Co-authored-by: Dario Nieuwenhuis <dirbaio@dirbaio.net>
A new `split` method is introduced such that the Uarte tx and rx can be used from separate tasks. An MPSC is used to illustrate how data may be passed between these tasks.
542: nrf/gpiote: remove PortInput, move impls to Input/FlexPin. r=Dirbaio a=Dirbaio
`PortInput` is just a dumb wrapper around `Input`, it has no reason whatsoever to exist. This PR moves the `wait_for_x` functionality to `Input` directly.
It also adds it to `FlexPin` for completeness and consistency with `Input`.
(The reason `PortInput` exists is a while ago `GPIOTE` was an owned singleton that you had to initialize, so `PortInput::new()` would require it to enforce it's been initialized. This doesn't apply anymore now that GPIOTE is "global")
Co-authored-by: Dario Nieuwenhuis <dirbaio@dirbaio.net>
As per Tokio and others, this commit provides a `poll_flush` method on `AsyncWrite` so that a best-effort attempt at wakening once all bytes are flushed can be made.
The constructors themselves are not strictly unsafe. Interactions with DMA can be generally unsafe if a future is dropped, but that's a separate issue. It is important that we use the `unsafe` keyword diligently as it can lead to confusion otherwise.
486: Pwm ppi events r=Dirbaio a=jacobrosenthal
More PWM yak shaving. I was going to do some safe pwm ppi events stuff but I just dont think it fits this api design.. ppi is just very low level, im not sure how safe it will be in general
* first we should probably have borrows of handlers for ppi with lifetime of the peripheral? hal does eb4ba6ae42/nrf-hal-common/src/pwm.rs (L714-L716)
* in general having access to tasks can put the state in some configuration the api doesnt understand anymore. for `SequencePwm` ideally id hand you back either only seq_start0 or seq_start1 because youd only use one based on if your `Times` is even or odd.. but again we only know that with this api AFTER start has been called. I dont think were ready for typestates
SO I figured why not add the pwm ppi events but make them unsafe and commit this example since I started it.
Somewhat related drop IS removing the last duty cycle from the pin correctly, but stop DOES NOT..the only thing that sets the pin back is pin.conf() as far as I can tell, so I tried to document that better and got rid of stop for the `SimplePwm` again since that doesnt need it then. However its ackward we dont have a way to unset the pwm without setting a new sequence of 0s, or dropping the peripheral
Co-authored-by: Jacob Rosenthal <jacobrosenthal@gmail.com>
It is basically impossible to directly convert that example to a sequence for various reasons. You cant have multiple channels on same buffer with one sequence instance for starters, also at that clock rate and max_duty 1 period is far longer than the 3ms it was using, which would require using a new max_duty and thus require regenerating the sine table which makes it not representitive of the original example anymore
455: simple_playback api from nrf sdk r=Dirbaio a=jacobrosenthal
Port of the nrf_drv_pwm_simple_playback call from the nordic sdk that allows you to set up a sequence to play across leds with no interaction necessary using the 'shorts' registers to trigger looping sequences
Co-authored-by: Jacob Rosenthal <jacobrosenthal@gmail.com>
482: Add MCO peripheral. r=Dirbaio a=matoushybl
This PR adds an abstraction over STM32 RCC feature called MCO (Microcontroller Clock Output). The clock output can bind to several clock sources and then can be scaled using a prescaler.
Given that from the embassy ecosystem the RCC is generaly invisible to the user, the MCO was implemented as a separate peripheral bound to the pin where the clock should appear.
Co-authored-by: Matous Hybl <hyblmatous@gmail.com>
Rustflags apply to ALL the crates in the graph, while we only need
them for the toplevel crate which is the only one getting linked.
Rustflags are not equal for all crates, this caused cargo to re-build the
same dependency crate multiple times uselessly. After this change, deps
are reused more, making builds faster.
Note that this only applies when sharing the target/ dir for multiple crates
in the repo which is not the default.
- Removed ConfigurableChannel and added capacity numbers to the channels
- Replaced the PPI api with a new one using the DPPI terminology (publish & subscribe)
- Updated all tasks and event registers for DPPI
456: Fix L4 clock setup for MSI and PLL to allow RNG operation r=Dirbaio a=lulf
Example is tested on STM32L475VG.
Co-authored-by: Ulf Lilleengen <lulf@redhat.com>
444: nrf: add NVMC driver. r=lulf a=Dirbaio
I haven't implemented `embassy_traits::Flash` because I want to change it to match embedded_storage, which is much better designed.
Either way, NVMC can't do async anyway, so the best we could do is implementing the async trait in a blocking way...
Co-authored-by: Dario Nieuwenhuis <dirbaio@dirbaio.net>
440: Add i2c example for L4 r=Dirbaio a=lulf
Tested to work on STM32 IOT01A (STM32L475VG) board.
Co-authored-by: Ulf Lilleengen <ulf.lilleengen@gmail.com>
425: Implements continuous sampling for the nRF SAADC r=huntc a=huntc
Implements continuous sampling for the nRF SAADC and also renames `OneShot` to `Saadc`. The one-shot behaviour is retained with the `sample` method and a new `run_sampler` method is provided for efficiently (i.e. zero copying) sampler processing. A double buffer is used for continuously sampling, which is swapped appropriately.
A sample frequency is provided and will set the internal timer of the SAADC when there is just one channel being sampled. Otherwise, PPI will be used to hook up the TIMER peripheral to drive the sampling task. Two methods are provided for this: `run_task_sampler` and `run_task_sampler` with the latter available where the compiler sees that just one channel is configured. Note that we set up the PPI and timer behaviour outside of the `Saadc` for maximum flexibility.
A callback is provided to the `run_sampler` method. This is a synchronous callback that should return in a reasonably short space of time. The SAADC could stall if it does not. A reasonable practice is to perform a small amount of processing within the callback to yield a signal, perhaps via `mpsc`. In the case of `mpsc`, the `try_send` method becomes useful.
A new example has been provided to illustrate continuous sampling, along with multiple channels and external timing:
```rust
#[embassy::main]
async fn main(_spawner: Spawner, mut p: Peripherals) {
let config = Config::default();
let channel_1_config = ChannelConfig::single_ended(&mut p.P0_02);
let channel_2_config = ChannelConfig::single_ended(&mut p.P0_03);
let channel_3_config = ChannelConfig::single_ended(&mut p.P0_04);
let mut saadc = Saadc::new(
p.SAADC,
interrupt::take!(SAADC),
config,
[channel_1_config, channel_2_config, channel_3_config],
);
let mut timer = Timer::new(p.TIMER0);
timer.set_frequency(Frequency::F1MHz);
timer.cc(0).write(100); // We want to sample at 10KHz
timer.cc(0).short_compare_clear();
let mut ppi = Ppi::new(p.PPI_CH0);
ppi.set_event(timer.cc(0).event_compare());
ppi.set_task(saadc.task_sample());
ppi.enable();
timer.start();
let mut bufs = [[[0; 3]; 50]; 2];
let mut c = 0;
let mut a: i32 = 0;
saadc
.run_task_sampler(&mut bufs, move |buf| {
for b in buf {
a += b[0] as i32;
}
c += buf.len();
if c > 10000 {
a = a / c as i32;
info!("channel 1: {=i32}", a);
c = 0;
a = 0;
}
SamplerState::Sampled
})
.await;
}
```
Co-authored-by: huntc <huntchr@gmail.com>
Implements continuous sampling for the nRF SAADC and also renames `OneShot` to `Saadc`. The one-shot behaviour is retained with the `sample` method and a new `run_sampler` method is provided for efficiently (i.e. zero copying) sampler processing. A double buffer is used for continuously sampling, which wlll be swapped once sampling has taken place.
A sample frequency is provided and will set the internal timer of the SAADC when there is just the one channel being sampled. Otherwise, PPI will be used to hook up the TIMER peripheral to drive the sampling task.
One-shot mode now permits the sampling of differential pins, and the sampling of multiple pins simultaneously.
A new ChannelConfig structure has been introduced so that multiple channels can be configured individually. Further, the `sample` method now accepts a buffer into which samples are written.
Along the way, I've reset some default configuration to align with Nordic's settings in their nrfx saadc driver. Specifically, the channel gain defaults to 6 (from 4) and the time defaults to 10us (from 20us).
This crate contains async radio drivers for various lora drivers that
work with embassy timers. The code is imported from Drogue Device (
https://github.com/drogue-iot/drogue-device)
The radio drivers integrate with the async LoRaWAN MAC layer in the
lorawan-device crate.
Also added is an example for the STM32WL55 and for STM32L0 (requires
the LoRa Discovery board) for LoRaWAN. Future work is to make the
underlying radio drivers using fully async SPI when communicating
with the peripheral.
* Adds an executor for WASM runtimes based on wasm_bindgen.
* Add time driver based on JS time handling.
* Add example that can run in browser locally.
* Update to critical-section version that supports 'std' flag
Based on the HAL from stm32wl, the peripheral driver has been
modified to fit into embassy, using the embassy APIs, providing
operation of the radio peripheral.
The initial version does not offer any async APIs, but the example
shows how the radio IRQ can be used to perform async TX of the radio.
* Generate a core index put into the PAC for the peripherals to use as
index into registers.
* Add EXTI v2 which uses CORE_INDEX to index exti registers
* Add IRQ-driven buffered USART implementation for STM32 v2 usart
* Implementation based on nRF UARTE, but simplified to not use DMA to
avoid complex interaction between DMA and USART.
* Implementation of AsyncBufRead and AsyncWrite traits
* Some unit tests to ring buffer
* Update polyfill version
* Update sub module to get usart IRQ fix
Previously the cargo configurations of all of the example projects had
`build-std = ["core"]`, which forces compilation of `core` as a
code-size optimisation. However, this is strictly unnecessary and will
currently break for users who do not use `rustup` directly (e.g. nix
users).
Includes the addition of a `dbgmcu!(...)` macro table which currently takes
the form of
(cr, $fn_name:ident)
where `$fn_name` is something like `set_dbgsleep_d1` etc.
The method is unsafe, since it's performing unsafe PAC operations.
Two examples modified to demonstrate its usage.
An MPSC inspired by Tokio and Crossbeam. The MPSC is designed to support both single and multi core processors, with only single core implemented at this time. The allocation of the channel’s buffer is inspired by the const generic parameters that Heapless provides.