Skip to content

v1.0.0-beta.0

Latest
Compare
Choose a tag to compare
@MabezDev MabezDev released this 24 Feb 19:07
· 135 commits to main since this release
fd2bdef

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

Migration Guide from v0.23.x to v1.0.0-beta.0

Driver stability

Unstable parts of esp-hal are gated behind the unstable feature. Previously, this feature
was enabled by default, but starting with this release, it is no longer the case.
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 be changed or removed at any time.

Please refer to the documentation to see which APIs are marked as unstable.

 esp-hal = { version = "1.0.0-beta.0" , features = [
   "esp32c6",
+  "unstable"
 ]}

Async drivers can no longer be sent between cores and executors

To work around this limitation, send the blocking driver, and configure it into Async mode
in the target context.

 #[embassy_executor::task]
-async fn interrupt_driven_task(mut spi: Spi<'static, Async>) {
+async fn interrupt_driven_task(spi: Spi<'static, Blocking>) {
+    let mut spi = spi.into_async();
     ...
 }

 let spi = Spi::new(...)
     .unwrap()
     // ...
-    .into_async();

 send_spawner.spawn(interrupt_driven_task(spi)).unwrap();

RMT changes

Configurations structs now support the builder-lite pattern

The TxChannelConfig and RxChannelConfig structs now support the builder-lite pattern.
Thus, explicit initialization of all fields can be replaced by only the necessary setter methods:

  let mut channel = rmt
      .channel0
      .configure(
          peripherals.GPIO1,
-         TxChannelConfig {
-             clk_divider: 1,
-             idle_output_level: false,
-             idle_output: false,
-             carrier_modulation: false,
-             carrier_high: 1,
-             carrier_low: 1,
-             carrier_level: false,
-         },
+          TxChannelConfig::default().with_clk_divider(1)
      )
     .unwrap();

Some configuration fields now take gpio::Level instead of bool

Fields related to the carrier level in the channel configuration structs now
take the more descriptive gpio::Level type instead of a plain bool.

  let mut tx_channel = rmt
      .channel0
      .configure(
          peripherals.GPIO1,
          TxChannelConfig::default()
              .with_clk_divider(1)
-             .with_idle_output_level(false)
+             .with_idle_output_level(Level::Low)
-             .with_carrier_level(true)
+             .with_carrier_level(Level::High)
      )
     .unwrap();

  let mut rx_channel = rmt
      .channel1
      .configure(
          peripherals.GPIO2,
          RxChannelConfig::default()
              .with_clk_divider(1)
              .with_carrier_modulation(true)
              .with_carrier_high(1)
              .with_carrier_low(1)
-             .with_carrier_level(false),
+             .with_carrier_level(Level::Low),
      )
     .unwrap();

PulseCode now uses gpio::Level instead of bool to specify output levels

The more descriptive gpio::Level enum is now used to specify output levels of PulseCode:

+ use esp_hal::gpio::Level;
+
- let code = PulseCode::new(true, 200, false, 50);
+ let code = PulseCode::new(Level::High, 200, Level::Low, 50);

Global driver changes

The _bytes postfix of driver methods that take a byte slice have been removed.

- uart0.write_bytes(b"Hello world!")?;
+ uart0.write(b"Hello world!")?;

The peripherals::Interrupts enum is no longer available. Users (mostly third party driver
developers) will need to use the PAC crates directly.

UART changes

Uart write is now blocking and return the number of bytes written. read will block until it fills at least one byte into the buffer with received bytes, use read_buffered_bytes to read the available bytes without blocking.

e.g.

- uart.write(0x42).ok();
- let read = block!(ctx.uart.read());
+ let data: [u8; 1] = [0x42];
+ uart.write(&data).unwrap();
+ let mut byte = [0u8; 1];
+ uart.read(&mut byte).unwrap();

UART errors have been split into TxError and RxError.

read_* and write_* functions now return different types. In practice this means you no longer
need to check for RX errors that can't be returned by write_*.

The error type used by embedded-io has been updated to reflect this. A new IoError enum has been
added for embedded-io errors associated to the unsplit Uart driver. On Uart (but not UartRx
or UartTx) TX-related trait methods return IoError::Tx(TxError), while RX-related methods return
IoError::Rx(RxError).

UART halves have their configuration split, too

Uart::Config structure now contains separate RxConfig and TxConfig:

- let config = Config::default().with_rx_fifo_full_threshold(30);
+ let config = Config::default()
+     .with_rx(RxConfig::default()
+       .with_fifo_full_threshold(30)
+ );

timer::wait is now blocking

periodic.start(100.millis()).unwrap();
- nb::block!(periodic.wait()).unwrap();
+ periodic.wait();

SPI Changes

spi::DataMode changed the meaning of DataMode::Single - it now means 3-wire SPI (using one data line).

Use DataMode::SingleTwoDataLines to get the previous behavior.

- DataMode::Single,
+ DataMode::SingleTwoDataLines,

Spi now offers both, with_mosi and with_sio0. Consider using with_sio for half-duplex SPI except for [DataMode::SingleTwoDataLines] or for a mixed-bus.

Removed flip-link Feature

The flip-link feature is removed and replaced by the ESP_HAL_CONFIG_FLIP_LINK option.

Cargo.toml

- esp-hal = { version = "0.23.0", features = ["flip-link"]}
+ esp-hal = "0.23.0"

config/config.toml

[env]
+ ESP_HAL_CONFIG_FLIP_LINK = "true"

Removed psram-quad/prsram-octal Feature

The features psram-quad/prsram-octal are replaced by a single psram feature and an additional config option (ESP_HAL_CONFIG_PSRAM_MODE).

ESP_HAL_CONFIG_PSRAM_MODE defaults to quad and (for ESP32-S3) also allows octal.

Cargo.toml

- esp-hal = { version = "0.23.0", features = ["psram-octal"]}
+ esp-hal = { version = "0.23.0", features = ["psram"]}

config/config.toml

[env]
+ ESP_HAL_CONFIG_PSRAM_MODE = "octal"

PARL_IO changes

Parallel IO now uses the newer DMA Move API.

Changes on the TX side

  let (_, _, tx_buffer, tx_descriptors) = dma_buffers!(0, 32000);
+ let mut dma_tx_buf = DmaTxBuf::new(tx_descriptors, tx_buffer).unwrap();

- let transfer = parl_io_tx.write_dma(&tx_buffer).unwrap();
- transfer.wait().unwrap();
+ let transfer = parl_io_tx.write(dma_tx_buf.len(), dma_tx_buf).unwrap();
+ (result, parl_io_tx, dma_tx_buf) = transfer.wait();
+ result.unwrap();

Changes on the RX side

  let (rx_buffer, rx_descriptors, _, _) = dma_buffers!(32000, 0);
+ let mut dma_rx_buf = DmaRxBuf::new(rx_descriptors, rx_buffer).unwrap();
- let transfer = parl_io_rx.read_dma(&mut rx_buffer).unwrap();
- transfer.wait().unwrap();
+ let transfer = parl_io_rx.read(Some(dma_rx_buf.len()), dma_rx_buf).unwrap();
+ (_, parl_io_rx, dma_rx_buf) = transfer.wait();

On the RX side, the EofMode is now decided at transfer time, rather than config time.

  • EofMode::ByteLen -> Some(<number of bytes to receive>)
  • EofMode::EnableSignal -> None

GPIO changes

GPIO drivers now take configuration structs.

- Input::new(peripherals.GPIO0, Pull::Up);
+ Input::new(peripherals.GPIO0, InputConfig::default().with_pull(Pull::Up));
 
- Output::new(peripherals.GPIO0, Level::Low);
+ Output::new(peripherals.GPIO0, Level::Low, OutputConfig::default());

The OutputOpenDrain driver has been removed. You can use Output instead with
DriveMode::OpenDrain. The input-related methods of OutputOpenDrain (level,
is_high, is_low) are available through the (unstable) Flex driver.

- OutputOpenDrain::new(peripherals.GPIO0, Level::Low);
+ Output::new(
     peripherals.GPIO0,
     Level::Low,
     OutputConfig::default()
         .with_drive_mode(DriveMode::OpenDrain),
 );

AES DMA driver changes

AES now uses the newer DMA move API.

  let (output, rx_descriptors, input, tx_descriptors) = dma_buffers!(32000);
+ let mut output = DmaRxBuf::new(rx_descriptors, output).unwrap();
+ let mut input = DmaTxBuf::new(tx_descriptors, input).unwrap();

  let mut aes = Aes::new(peripherals.AES).with_dma(
      dma_channel,
-     rx_descriptors,
-     tx_descriptors,
  );

  let transfer = aes
      .process(
-         &input,
-         &mut output,
+         output.len().div_ceil(16), // Number of blocks
+         output,
+         input,
          Mode::Encryption128,
          CipherMode::Ecb,
          keybuf,
      )
+     .map_err(|e| e.0)
      .unwrap();
  transfer.wait();

I2C Changes

All async functions now include the _async postfix. Additionally the non-async functions are now available in async-mode.

- let result = i2c.write_read(0x77, &[0xaa], &mut data).await;
+ let result = i2c.write_read_async(0x77, &[0xaa], &mut data).await;

ADC Changes

The ADC driver has gained a new Async/Blocking mode parameter.
NOTE: Async support is only supported in ESP32C3 and ESP32C6 for now

- Adc<'d, ADC>
+ Adc<'d, ADC, Blocking>

time API changes

ESP-HAL no longer publicly exposes fugit and no longer exposes the concept of a tick.
This comes with a number of changes:

  • The RateExtU32 and similar traits are no longer used, which means .kHz() and similar suffix
    conversions are no longer available. A number of matching constructors are available. For example,
    instead of 1.MHz() you need to write Rate::from_mhz(1).
  • Methods on esp_hal::time types are named differently.
    • Getters are prefixed with as_, e.g. Duration::as_secs.
    • Constructors are prefixed with from, e.g. Rate::from_mhz.
    • A number of functions that convert from a number into a time type (e.g. Duration::from_ticks)
      are not available. Use conversions from physical units of time, like Duration::from_millis.