10 KiB
Migration Guide from 0.22.x to v1.0.0-beta.0
Starting with this release, unstable parts of esp-hal will be gated behind the unstable feature.
The unstable feature itself is unstable, we might change the way we hide APIs without notice.
Unstable APIs are not covered by semver guarantees, they may break even between patch releases.
Please refer to the documentation to see which APIs are marked as unstable.
DMA changes
Accessing channel objects
DMA channels are now available through the Peripherals struct, which is returned
by esp_hal::init(). The channels themselves have been renamed to match other peripheral singletons.
- ESP32-C2, C3, C6, H2 and S3:
channelX -> DMA_CHX - ESP32 and S2:
spiXchannel -> DMA_SPIX,i2sXchannel -> DMA_I2SX
-let dma = Dma::new(peripherals.DMA);
-let channel = dma.channel2;
+let channel = peripherals.DMA_CH2;
Channel configuration changes
configure_for_asyncandconfigurehave been removed- PDMA devices (ESP32, ESP32-S2) provide no channel configurability
- GDMA devices provide
set_priorityto change DMA in/out channel priority
let mut spi = Spi::new_with_config(
peripherals.SPI2,
Config::default(),
)
// other setup
-.with_dma(dma_channel.configure(false, DmaPriority::Priority0));
+.with_dma(dma_channel);
+dma_channel.set_priority(DmaPriority::Priority1);
let mut spi = Spi::new_with_config(
peripherals.SPI2,
Config::default(),
)
// other setup
-.with_dma(dma_channel.configure(false, DmaPriority::Priority1));
+.with_dma(dma_channel);
Burst mode configuration
Burst mode is now a property of buffers, instead of DMA channels. Configuration can be done by
calling set_burst_config on buffers that support it. The configuration options and the
corresponding BurstConfig type are device specfic.
Usability changes affecting applications
Individual channels are no longer wrapped in Channel, but they implement the DmaChannel trait.
This means that if you want to split them into an rx and a tx half (which is only supported on
the H2, C6 and S3 currently), you can't move out of the channel but instead you need to call
the split method.
-let tx = channel.tx;
+use esp_hal::dma::DmaChannel;
+let (rx, tx) = channel.split();
The Channel types remain available for use in peripheral drivers.
It is now simpler to work with DMA channels in generic contexts. esp-hal now provides convenience
traits and type aliasses to specify peripheral compatibility. The ChannelCreator types have been
removed, further simplifying use.
For example, previously you may have needed to write something like this to accept a DMA channel in a generic function:
fn new_foo<'d, T>(
dma_channel: ChannelCreator<2>, // It wasn't possible to accept a generic ChannelCreator.
peripheral: impl Peripheral<P = T> + 'd,
)
where
T: SomePeripheralInstance,
ChannelCreator<2>: DmaChannelConvert<<T as DmaEligible>::Dma>,
{
let dma_channel = dma_channel.configure_for_async(false, DmaPriority::Priority0);
let driver = PeripheralDriver::new(peripheral, config).with_dma(dma_channel);
// ...
}
From now on a similar, but more flexible implementation may look like:
fn new_foo<'d, T, CH>(
dma_channel: impl Peripheral<P = CH> + 'd,
peripheral: impl Peripheral<P = T> + 'd,
)
where
T: SomePeripheralInstance,
CH: DmaChannelFor<T>,
{
// Optionally: dma_channel.set_priority(DmaPriority::Priority2);
let driver = PeripheralDriver::new(peripheral, config).with_dma(dma_channel);
// ...
}
Usability changes affecting third party peripheral drivers
If you are writing a driver and need to store a channel in a structure, you can use one of the
ChannelFor type aliasses.
struct Aes<'d> {
- channel: ChannelTx<'d, Blocking, <AES as DmaEligible>::Dma>,
+ channel: ChannelTx<'d, Blocking, PeripheralTxChannel<AES>>,
}
Timer changes
The low level timers, SystemTimer and TimerGroup are now "dumb". They contain no logic for operating modes or trait implementations (except the low level Timer trait).
Timer drivers - OneShotTimer & PeriodicTimer
Both drivers now have a Mode parameter. Both also type erase the underlying driver by default, call new_typed to retain the type.
- OneShotTimer<'static, systimer::Alarm>;
+ OneShotTimer<'static, Blocking>;
- PeriodicTimer<'static, systimer::Alarm>;
+ PeriodicTimer<'static, Blocking>;
SystemTimer
let systimer = SystemTimer::new(peripherals.SYSTIMER);
- static UNIT0: StaticCell<SpecificUnit<'static, 0>> = StaticCell::new();
- let unit0 = UNIT0.init(systimer.unit0);
- let frozen_unit = FrozenUnit::new(unit0);
- let alarm0 = Alarm::new(systimer.comparator0, &frozen_unit);
- alarm0.set_period(1u32.secs());
+ let alarm0 = systimer.alarm0;
+ let mut timer = PeriodicTimer::new(alarm0);
+ timer.start(1u64.secs());
TIMG
Timer group timers have been type erased.
- timg::Timer<timg::Timer0<crate::peripherals::TIMG0>, Blocking>
+ timg::Timer
ETM usage has changed
Timer dependant ETM events should be created prior to initializing the timer with the chosen driver.
let task = ...; // ETM task
let syst = SystemTimer::new(peripherals.SYSTIMER);
let alarm0 = syst.alarm0;
- alarm0.load_value(1u64.millis()).unwrap();
- alarm0.start();
- let event = Event::new(&mut alarm0);
+ let event = Event::new(&alarm0);
+ let timer = OneShotTimer::new(alarm0);
+ timer.schedule(1u64.millis()).unwrap();
let _configured_channel = channel0.setup(&event, &task);
PSRAM is now initialized automatically
Calling esp_hal::initialize will now configure PSRAM if either the quad-psram or octal-psram
is enabled. To retrieve the address and size of the initialized external memory, use
esp_hal::psram::psram_raw_parts, which returns a pointer and a length.
-let peripherals = esp_hal::init(esp_hal::Config::default());
-let (start, size) = esp_hal::psram::init_psram(peripherals.PSRAM, psram_config);
+let peripherals = esp_hal::init({
+ let mut config = esp_hal::Config::default();
+ config.psram = psram_config;
+ config
+});
+let (start, size) = esp_hal::psram::psram_raw_parts(&peripherals.PSRAM, psram);
The usage of esp_alloc::psram_allocator! remains unchanged.
embedded-hal 0.2.* is not supported anymore.
As per https://github.com/rust-embedded/embedded-hal/pull/640, our driver no longer implements traits from embedded-hal 0.2.x.
Analogs of all traits from the above mentioned version are available in embedded-hal 1.x.x
- use embedded_hal_02::can::Frame;
+ use embedded_can::Frame;
- use embedded_hal_02::digital::v2::OutputPin;
- use embedded_hal_02::digital::v2::ToggleableOutputPin;
+ use embedded_hal::digital::OutputPin;
+ use embedded_hal::digital::StatefulOutputPin;
- use embedded_hal_02::serial::{Read, Write};
+ use embedded_hal_nb::serial::{Read, Write};
You might also want to check the full official embedded-hal migration guide:
https://github.com/rust-embedded/embedded-hal/blob/master/docs/migrating-from-0.2-to-1.0.md
Interrupt related reshuffle
- use esp_hal::InterruptConfigurable;
- use esp_hal::DEFAULT_INTERRUPT_HANDLER;
+ use esp_hal::interrupt::InterruptConfigurable;
+ use esp_hal::interrupt::DEFAULT_INTERRUPT_HANDLER;
Driver constructors now take a configuration and are fallible
The old new_with_config constructor have been removed, and new constructors now always take
a configuration structure. They have also been updated to return a ConfigError if the configuration
is not compatible with the hardware.
-let mut spi = Spi::new_with_config(
+let mut spi = Spi::new(
peripherals.SPI2,
Config {
frequency: 100.kHz(),
mode: SpiMode::Mode0,
..Config::default()
},
-);
+)
+.unwrap();
let mut spi = Spi::new(
peripherals.SPI2,
+ Config::default(),
-);
+)
+.unwrap();
LCD_CAM configuration changes
camnow has aConfigstrurct that contains frequency, bit/byte order, VSync filter options.- DPI, I8080:
frequencyhas been moved intoConfig.
+let mut cam_config = cam::Config::default();
+cam_config.frequency = 1u32.MHz();
cam::Camera::new(
lcd_cam.cam,
dma_rx_channel,
pins,
- 1u32.MHz(),
+ cam_config,
)
SpiDma now requires you specify the transfer length explicitly
dma_tx_buf.set_length(5 /* or greater */);
- spi_dma.write(dma_tx_buf);
+ spi_dma.write(5, dma_tx_buf);
dma_rx_buf.set_length(5 /* or greater */);
- spi_dma.read(dma_rx_buf);
+ spi_dma.read(5, dma_rx_buf);
dma_rx_buf.set_length(5 /* or greater */);
dma_tx_buf.set_length(5 /* or greater */);
- spi_dma.transfer(dma_rx_buf, dma_tx_buf);
+ spi_dma.transfer(5, dma_rx_buf, 5, dma_tx_buf);
I2C Error changes
To avoid abbreviations and contractions (as per the esp-hal guidelines), some error variants have changed
- Error::ExecIncomplete
+ Error::ExecutionIncomplete
- Error::CommandNrExceeded
+ Error::CommandNumberExceeded
- Error::ExceedingFifo
+ Error::FifoExceeded
- Error::TimeOut
+ Error::Timeout
- Error::InvalidZeroLength
+ Error::ZeroLengthInvalid
The crate prelude has been removed
The reexports that were previously part of the prelude are available through other paths:
nbis no longer re-exported. Please import thenbcrate if you need it.ExtU64andRateExtU32have been moved toesp_hal::timeClockandCpuClock:esp_hal::clock::{Clock, CpuClock}- The following traits need to be individually imported when needed:
esp_hal::analog::dac::Instanceesp_hal::gpio::Pinesp_hal::ledc::channel::ChannelHWesp_hal::ledc::channel::ChannelIFaceesp_hal::ledc::timer::TimerHWesp_hal::ledc::timer::TimerIFaceesp_hal::timer::timg::TimerGroupInstanceesp_hal::timer::Timeresp_hal::interrupt::InterruptConfigurable
- The
entrymacro can be imported asesp_hal::entry, while other macros are found underesp_hal::macros