Skip to content

0.22.0

Latest
Compare
Choose a tag to compare
@jessebraham jessebraham released this 20 Nov 09:41
· 37 commits to main since this release
bdfec37

Please note that only changes to the esp-hal package are tracked in these release notes.

Migration Guide

IO changes

GPIO pins are now accessible via Peripherals

 let peripherals = esp_hal::init(Default::default());
-let io = Io::new(peripherals.GPIO, peripherals.IOMUX);
-let pin = io.pins.gpio5;
+let pin = peripherals.GPIO5;

Io constructor changes

  • new_with_priority and new_no_bind_interrupts have been removed.
    Use set_priority to configure the GPIO interrupt priority.
    We no longer overwrite interrupt handlers set by user code during initialization.
  • new no longer takes peripherals.GPIO

Removed async-specific constructors

The following async-specific constuctors have been removed:

  • configure_for_async DMA channel constructors
  • TwaiConfiguration::new_async and TwaiConfiguration::new_async_no_transceiver
  • I2c::new_async
  • LcdCam::new_async
  • UsbSerialJtag::new_async
  • Rsa::new_async
  • Rmt::new_async
  • Uart::new_async, Uart::new_async_with_config
  • UartRx::new_async, UartRx::new_async_with_config
  • UartTx::new_async, UartTx::new_async_with_config

You can use the blocking counterparts, then call into_async on the returned peripheral instead.

-let mut config = twai::TwaiConfiguration::new_async(
+let mut config = twai::TwaiConfiguration::new(
     peripherals.TWAI0,
     loopback_pin.peripheral_input(),
     loopback_pin,
     twai::BaudRate::B1000K,
     TwaiMode::SelfTest,
-);
+).into_async();

Some drivers were implicitly configured to the asyncness of the DMA channel used to construct them.
This is no longer the case, and the following drivers will always be created in blocking mode:

  • i2s::master::I2s
  • spi::master::SpiDma and spi::master::SpiDmaBus

Peripheral types are now optional

You no longer have to specify the peripheral instance in the driver's type for the following
peripherals:

  • SPI (both master and slave)
  • I2S
  • I2C
  • TWAI
  • UART
-Spi<'static, SPI2, FullDuplexMode>
+Spi<'static, FullDuplexMode>

-SpiDma<'static, SPI2, HalfDuplexMode, Blocking>
+SpiDma<'static, HalfDuplexMode, Blocking>

-I2sTx<'static, I2S0, Async>
+I2sTx<'static, Async>

Note that you may still specify the instance if you need to. To do this, we provide _typed
versions of the constructors (for example: new_typed, new_half_duplex_typed). Please note that
the peripheral instance has been moved to the last generic parameter position.

let spi: Spi<'static, FullDuplexMode, SPI2> = Spi::new_typed(peripherals.SPI2, 1.MHz(), SpiMode::Mode0);

I2C changes

The I2C master driver and related types have been moved to esp_hal::i2c::master.

The with_timeout constructors have been removed. new and new_typed now take a Config struct
with the available configuration options.

  • The default configuration is now:
    • bus frequency: 100 kHz
    • timeout: about 10 bus clock cycles

The constructors no longer take pins. Use with_sda and with_scl instead.

-use esp_hal::i2c::I2c;
+use esp_hal::i2c::{Config, I2c};
-let i2c = I2c::new_with_timeout(peripherals.I2C0, io.pins.gpio4, io.pins.gpio5, 100.kHz(), timeout);
+I2c::new_with_config(
+    peripherals.I2C0,
+    {
+        let mut config = Config::default();
+        config.frequency = 100.kHz();
+        config.timeout = timeout;
+        config
+    },
+)
+.with_sda(io.pins.gpio4)
+.with_scl(io.pins.gpio5);

The calculation of I2C timeout has changed

Previously, I2C timeouts were counted in increments of I2C peripheral clock cycles. This meant that
the configure value meant different lengths of time depending on the device. With this update, the
I2C configuration now expects the timeout value in number of bus clock cycles, which is consistent
between devices.

ESP32 and ESP32-S2 use an exact number of clock cycles for its timeout. Other MCUs, however, use
the 2^timeout value internally, and the HAL rounds up the timeout to the next appropriate value.

Changes to half-duplex SPI

The HalfDuplexMode and FullDuplexMode type parameters have been removed from SPI master and slave
drivers. It is now possible to execute half-duplex and full-duplex operations on the same SPI bus.

Driver construction

  • The Spi::new_half_duplex constructor has been removed. Use new (or new_typed) instead.
  • The with_pins methods have been removed. Use the individual with_* functions instead.
  • The with_mosi and with_miso functions now take input-output peripheral signals to support half-duplex mode.
- let mut spi = Spi::new_half_duplex(peripherals.SPI2, 100.kHz(), SpiMode::Mode0)
-     .with_pins(sck, mosi, miso, sio2, sio3, cs);
+ let mut spi = Spi::new(peripherals.SPI2, 100.kHz(), SpiMode::Mode0)
+     .with_sck(sck)
+     .with_cs(cs)
+     .with_mosi(mosi)
+     .with_miso(miso)
+     .with_sio2(sio2)
+     .with_sio3(sio3);

Transfer functions

The Spi<'_, SPI, HalfDuplexMode>::read and Spi<'_, SPI, HalfDuplexMode>::write functions have been replaced by
half_duplex_read and half_duplex_write.

 let mut data = [0u8; 2];
 let transfer = spi
-    .read(
+    .half_duplex_read(
         SpiDataMode::Single,
         Command::Command8(0x90, SpiDataMode::Single),
         Address::Address24(0x000000, SpiDataMode::Single),
         0,
         &mut data,
     )
     .unwrap();

 let transfer = spi
-    .write(
+    .half_duplex_write(
         SpiDataMode::Quad,
         Command::Command8(write as u16, command_data_mode),
         Address::Address24(
             write as u32 | (write as u32) << 8 | (write as u32) << 16,
             SpiDataMode::Quad,
         ),
         0,
         dma_tx_buf,
     )
     .unwrap();

Slave-mode SPI

Driver construction

The constructors no longer accept pins. Use the with_pin_name setters instead.

 let mut spi = Spi::new(
     peripherals.SPI2,
-    sclk,
-    mosi,
-    miso,
-    cs,
     SpiMode::Mode0,
-);
+)
+.with_sclk(sclk)
+.with_mosi(mosi)
+.with_miso(miso)
+.with_cs(cs);

UART event listening

The following functions have been removed:

  • listen_at_cmd
  • unlisten_at_cmd
  • listen_tx_done
  • unlisten_tx_done
  • listen_rx_fifo_full
  • unlisten_rx_fifo_full
  • at_cmd_interrupt_set
  • tx_done_interrupt_set
  • rx_fifo_full_interrupt_set
  • reset_at_cmd_interrupt
  • reset_tx_done_interrupt
  • reset_rx_fifo_full_interrupt

You can now use the UartInterrupt enum and the corresponding listen, unlisten, interrupts and clear_interrupts functions.

Use interrupts in place of <INTERRUPT>_interrupt_set and clear_interrupts in place of the old reset_ functions.

UartInterrupt:

  • AtCmd
  • TxDone
  • RxFifoFull

Checking interrupt bits is now done using APIs provided by enumset. For example, to see if
a particular interrupt bit is set, use contains:

-serial.at_cmd_interrupt_set()
+serial.interupts().contains(UartInterrupt::AtCmd)

You can now listen/unlisten multiple interrupt bits at once:

-uart0.listen_at_cmd();
-uart0.listen_rx_fifo_full();
+uart0.listen(UartInterrupt::AtCmd | UartConterrupt::RxFifoFull);

I2S changes

The I2S driver has been moved to i2s::master

-use esp_hal::i2s::{DataFormat, I2s, Standard};
+use esp_hal::i2s::master::{DataFormat, I2s, Standard};

Removed i2s traits

The following traits have been removed:

  • I2sWrite
  • I2sWriteDma
  • I2sRead
  • I2sReadDma
  • I2sWriteDmaAsync
  • I2sReadDmaAsync

You no longer have to import these to access their respective APIs. If you used these traits
in your functions as generic parameters, you can use the I2s type directly instead.

For example:

-fn foo(i2s: &mut impl I2sWrite) {
+fn foo(i2s: &mut I2s<'_, I2S0, Blocking>) {
     // ...
 }

DMA related changes

Circular DMA transfer's available returns Result<usize, DmaError> now

In case of any error you should drop the transfer and restart it.

     loop {
-        let avail = transfer.available();
+        let avail = match transfer.available() {
+            Ok(avail) => avail,
+            Err(_) => {
+                core::mem::drop(transfer);
+                transfer = i2s_tx.write_dma_circular(&tx_buffer).unwrap();
+                continue;
+            },
+        };

Channel, ChannelRx and ChannelTx types have changed

  • Channel's Async/Blocking mode has been moved before the channel instance parameter.
  • ChannelRx and ChannelTx have gained a new Async/Blocking mode parameter.
-Channel<'d, DmaChannel0, Async>
+Channel<'d, Async, DmaChannel0>

-ChannelRx<'d, DmaChannel0>
+ChannelRx<'d, Async, DmaChannel0>

-ChannelTx<'d, DmaChannel0>
+ChannelTx<'d, Async, DmaChannel0>

Removed peripheral_input and into_peripheral_output from GPIO pin types

Creating peripheral interconnect signals now consume the GPIO pin used for the connection.

The previous signal function have been replaced by split. This change affects the following APIs:

  • GpioPin
  • AnyPin
-let input_signal = gpioN.peripheral_input();
-let output_signal = gpioN.into_peripheral_output();
+let (input_signal, output_signal) = gpioN.split();

into_peripheral_output, split (for output pins only) and peripheral_input have been added to
the GPIO drivers (Input, Output, OutputOpenDrain and Flex) instead.

ETM changes

  • The types are no longer prefixed with GpioEtm, TimerEtm or SysTimerEtm. You can still use
    import aliasses in case you need to differentiate due to name collisions
    (e.g. use esp_hal::gpio::etm::Event as GpioEtmEvent).
  • The old task and event types have been replaced by Task and Event.
  • GPIO tasks and events are no longer generic.

Changes to peripheral configuration

The uart::config module has been removed

The module's contents have been moved into uart.

-use esp_hal::uart::config::Config;
+use esp_hal::uart::Config;

If you work with multiple configurable peripherals, you may want to import the uart module and
refer to the Config struct as uart::Config.

SPI drivers can now be configured using spi::master::Config

  • The old methods to change configuration have been removed.
  • The new and new_typed constructor no longer takes frequency and mode.
  • The default configuration is now:
    • bus frequency: 1 MHz
    • bit order: MSB first
    • mode: SPI mode 0
  • There are new constructors (new_with_config, new_typed_with_config) and a new apply_config method to apply custom configuration.
-use esp_hal::spi::{master::Spi, SpiMode};
+use esp_hal::spi::{master::{Config, Spi}, SpiMode};
-Spi::new(SPI2, 100.kHz(), SpiMode::Mode1);
+Spi::new_with_config(
+    SPI2,
+    Config {
+        frequency: 100.kHz(),
+        mode: SpiMode::Mode0,
+        ..Config::default()
+    },
+)

LCD_CAM changes

I8080 driver split set_byte_order() into set_8bits_order() and set_byte_order().

If you were using an 8-bit bus.

- i8080.set_byte_order(ByteOrder::default());
+ i8080.set_8bits_order(ByteOrder::default());

If you were using an 16-bit bus, you don't need to change anything, set_byte_order() now works correctly.

If you were sharing the bus between an 8-bit and 16-bit device, you will have to call the corresponding method when
you switch between devices. Be sure to read the documentation of the new methods.

Mixed mode constructors

It is no longer possible to construct I8080 or Camera with an async-mode DMA channel.
Convert the DMA channel into blocking before passing it to these constructors.

 let lcd_cam = LcdCam::new(peripherals.LCD_CAM);
 let channel = ctx
     .dma
     .channel0
-    .configure(false, DmaPriority::Priority0)
-    .into_async();
+    .configure(false, DmaPriority::Priority0);

 let i8080 = I8080::new(
     lcd_cam.lcd,
     channel.tx,
     pins,
     20.MHz(),
     Config::default(),
 );

rmt::Channel::transmit now returns Result, PulseCode is now u32

When trying to send a one-shot transmission will fail if it doesn't end with an end-marker.

-    let mut data = [PulseCode {
-        level1: true,
-        length1: 200,
-        level2: false,
-        length2: 50,
-    }; 20];
-
-    data[data.len() - 2] = PulseCode {
-        level1: true,
-        length1: 3000,
-        level2: false,
-        length2: 500,
-    };
-    data[data.len() - 1] = PulseCode::default();
+    let mut data = [PulseCode::new(true, 200, false, 50); 20];
+    data[data.len() - 2] = PulseCode::new(true, 3000, false, 500);
+    data[data.len() - 1] = PulseCode::empty();

-        let transaction = channel.transmit(&data);
+        let transaction = channel.transmit(&data).unwrap();

The parl_io::NoClkPin and no_clk_pin() have been removed

You can use gpio::NoPin instead.

 use esp_hal:: {
-   parl_io::no_clk_pin,
+   gpio::NoPin,
 }

-parl_io.rx.with_config(&mut rx_pins, no_clk_pin(), BitPackOrder::Msb, Some(0xfff))
+let mut rx_clk_pin = NoPin;
+parl_io.rx.with_config(&mut rx_pins, &mut rx_clk_pin, BitPackOrder::Msb, Some(0xfff))

get_ prefixes have been removed from functions

In order to better comply with the Rust API Guidelines getter names convention, we have removed the get_ prefixes from all functions which previously had it. Due to the number of changes it's not practical to list all changes here, however if a function previous began with get_, you can simply remove this prefix.

The get_core() function has been removed in favour of Cpu::current()

- let core = esp_hal::get_core();
+ let core = esp_hal::Cpu::current();

Changelog

Added

  • A new config option PLACE_SWITCH_TABLES_IN_RAM to improve performance (especially for interrupts) at the cost of slightly more RAM usage (#2331)
  • A new config option PLACE_ANON_IN_RAM to improve performance (especially for interrupts) at the cost of RAM usage (#2331)
  • Add burst transfer support to DMA buffers (#2336)
  • AnyPin now implements From<GpioPin<N>>. (#2326)
  • Added AnySpi and AnySpiDmaChannel. (#2334)
  • Added AnyI2s and AnyI2sDmaChannel. (#2367)
  • Added AnyTwai. (#2359)
  • Added AnyUart. (#2381)
  • Pins::steal() to unsafely obtain GPIO. (#2335)
  • I2c::with_timeout (#2361)
  • Spi::half_duplex_read and Spi::half_duplex_write (#2373)
  • Add RGB/DPI driver (#2415)
  • Add DmaLoopBuf (#2415)
  • Cpu::COUNT and Cpu::current() (#2411)
  • UartInterrupt and related functions (#2406)
  • I2S Parallel output driver for ESP32. (#2348, #2436, #2472)
  • Add an option to configure WDT action (#2330)
  • DmaDescriptor is now Send (#2456)
  • into_async and into_blocking functions for most peripherals (#2430, #2461)
  • API mode type parameter (currently always Blocking) to master::Spi and slave::Spi (#2430)
  • gpio::{GpioPin, AnyPin, Flex, Output, OutputOpenDrain}::split() to obtain peripheral interconnect signals. (#2418)
  • gpio::Input::{split(), into_peripheral_output()} when used with output pins. (#2418)
  • gpio::Output::peripheral_input() (#2418)
  • {Uart, UartRx, UartTx}::apply_config() (#2449)
  • {Uart, UartRx, UartTx} now implement embassy_embedded_hal::SetConfig (#2449)
  • GPIO ETM tasks and events now accept InputSignal and OutputSignal (#2427)
  • spi::master::Config and {Spi, SpiDma, SpiDmaBus}::apply_config (#2448)
  • embassy_embedded_hal::SetConfig is now implemented for spi::master::{Spi, SpiDma, SpiDmaBus}, i2c::master::I2c (#2448, #2477)
  • slave::Spi::{with_mosi(), with_miso(), with_sclk(), with_cs()} functions (#2485)
  • I8080: Added set_8bits_order() to set the byte order in 8-bit mode (#2487)
  • I2c::{apply_config(), with_sda(), with_scl()} (#2477)
  • ESP32-S2: Added missing GPIO alternate functions (#2512)

Changed

  • Peripheral type erasure for SPI (#2334)
  • Peripheral type erasure for I2S (#2367)
  • Peripheral type erasure for I2C (#2361)
  • Peripheral type erasure for TWAI (#2359)
  • The SPI driver has been rewritten to allow using half-duplex and full-duplex functionality on the same bus. See the migration guide for details. (#2373)
  • Renamed SpiDma functions: dma_transfer to transfer, dma_write to write, dma_read to read. (#2373)
  • Peripheral type erasure for UART (#2381)
  • Changed listening for UART events (#2406)
  • Circular DMA transfers now correctly error, available returns Result<usize,DmaError> now (#2409)
  • Interrupt listen/unlisten/clear functions now accept any type that converts into EnumSet (i.e. single interrupt flags). (#2442)
  • SPI interrupt listening is now only available in Blocking mode. The set_interrupt_handler is available via InterruptConfigurable (#2442)
  • Allow users to create DMA Preparations (#2455)
  • The rmt::asynch::RxChannelAsync and rmt::asynch::TxChannelAsync traits have been moved to rmt (#2430)
  • Calling AnyPin::output_signals on an input-only pin (ESP32 GPIO 34-39) will now result in a panic. (#2418)
  • UART configuration types have been moved to esp_hal::uart (#2449)
  • spi::master::Spi::new() no longer takes frequency and mode as a parameter. (#2448)
  • Peripheral interconnections via GPIO pins now use the GPIO matrix. (#2419)
  • The I2S driver has been moved to i2s::master (#2472)
  • slave::Spi constructors no longer take pins (#2485)
  • The I2c master driver has been moved from esp_hal::i2c to esp_hal::i2c::master. (#2476)
  • I2c SCL timeout is now defined in bus clock cycles. (#2477)
  • Trying to send a single-shot RMT transmission will result in an error now, RMT deals with u32 now, PulseCode is a convenience trait now (#2463)
  • Removed get_ prefixes from functions (#2528)
  • The Camera and I8080 drivers' constructors now only accepts blocking-mode DMA channels. (#2519)

Fixed

Removed

  • The i2s::{I2sWrite, I2sWriteDma, I2sRead, I2sReadDma, I2sWriteDmaAsync, I2sReadDmaAsync} traits have been removed. (#2316)
  • The ledc::ChannelHW trait is no longer generic. (#2387)
  • The I2c::new_with_timeout constructors have been removed (#2361)
  • I2c::new() no longer takes frequency and pins as parameters. (#2477)
  • The spi::master::HalfDuplexReadWrite trait has been removed. (#2373)
  • The Spi::with_pins methods have been removed. (#2373)
  • The Spi::new_half_duplex constructor have been removed. (#2373)
  • The HalfDuplexMode and FullDuplexMode parameters have been removed from Spi. (#2373)
  • Removed the output pin type parameter from ledc::{Channel, ChannelIFace} (#2388)
  • Removed the output pin type parameter from mcpwm::operator::{PwmPin, LinkedPins} (#2388)
  • Removed the output pin type parameter from parl_io::{ClkOutPin, ClkInPin, RxClkInPin} (#2388)
  • Removed the valid pin type parameter from parl_io::{TxPinConfigWithValidPin, RxPinConfigWithValidPin} (#2388)
  • Removed the pin type parameters from parl_io::{TxOneBit, TxTwoBits, TxFourBits, TxEightBits, TxSixteenBits} (#2388)
  • Removed the pin type parameters from parl_io::{RxOneBit, RxTwoBits, RxFourBits, RxEightBits, RxSixteenBits} (#2388)
  • Removed the pin type parameters from lcd_cam::lcd::i8080::{TxEightBits, TxSixteenBits} (#2388)
  • Removed the pin type parameters from lcd_cam::cam::{RxEightBits, RxSixteenBits} (#2388)
  • Most of the async-specific constructors (new_async, new_async_no_transceiver) have been removed. (#2430)
  • The configure_for_async DMA functions have been removed (#2430)
  • The Uart::{change_baud, change_stop_bits} functions have been removed (#2449)
  • gpio::{Input, Output, OutputOpenDrain, Flex, GpioPin}::{peripheral_input, into_peripheral_output} have been removed. (#2418)
  • The GpioEtm prefix has been removed from gpio::etm types (#2427)
  • The TimerEtm prefix has been removed from timer::timg::etm types (#2427)
  • The SysTimerEtm prefix has been removed from timer::systimer::etm types (#2427)
  • The GpioEtmEventRising, GpioEtmEventFalling, GpioEtmEventAny types have been replaced with Event (#2427)
  • The TaskSet, TaskClear, TaskToggle types have been replaced with Task (#2427)
  • {Spi, SpiDma, SpiDmaBus} configuration methods (#2448)
  • Io::new_with_priority and Io::new_no_bind_interrupt. (#2486)
  • parl_io::{no_clk_pin(), NoClkPin} (#2531)
  • Removed get_core function in favour of Cpu::current (#2533)