Compare commits

...

28 Commits
main ... lld2

Author SHA1 Message Date
Scott Mabin
f15621244b debugging, found dodgy relocs 2023-07-12 10:43:16 +01:00
Dániel Buga
d19e5aef54 Simplify user-facing DMA channel types (#626)
* Introduce a trait for DMA channels

This trait is then used to hold types related to the particular DMA channel. This change allows us to simplify user-facing types.

* Remove private type from I2s

* Remove redundant spi3 example, update examples

* Merge markdown sections

* Add changelog entry
2023-07-04 11:47:21 +01:00
Jesse Braham
27c0aa471f Miscellaneous fixes/improvements (#627)
* Un-comment remaining device peripheral definitions for ESP32-H2

* Re-work `RadioExt` implementations, add support for ESP32-H2

* README updates for ESP32-C6/H2

* Update CHANGELOG
2023-07-04 11:47:21 +01:00
Dániel Buga
d8dbf520fb Remove redundant trait bounds 2023-07-04 11:47:21 +01:00
Dániel Buga
4e36d3b3b9 Fix typos 2023-07-04 11:47:21 +01:00
Dániel Buga
d255c4c4af Add changelog entry 2023-07-04 11:47:21 +01:00
Dániel Buga
559d00703d Update PDMA descriptor docs 2023-07-04 11:47:21 +01:00
Dániel Buga
14823d669f Prevent constructing some types 2023-07-04 11:47:21 +01:00
Dániel Buga
9570a660a1 Add an example to test the prelude 2023-07-04 11:47:21 +01:00
Dániel Buga
89c6f37c3f Add WithDmaSpi3 to prelude on espd32s3 2023-07-04 11:47:21 +01:00
Alex Johnson
9f7565440a Async serial uart read (#620)
* implement embassy async uart read

* Add embassy async read support for uart

* changes based on review

* fix CI failures

* change review #2

* fixed re-opened PR number

* changes review no.3

---------

Co-authored-by: Scott Mabin <scott@mabez.dev>
2023-07-04 11:47:21 +01:00
Dániel Buga
226bdc3038 Correct DMA descriptor docs, math (#622) 2023-07-04 11:47:21 +01:00
bjoernQ
d95be13c4d Avoid SDA/SCL low during pin config 2023-07-04 11:47:21 +01:00
Jordan Halase
28fafa05e1 Add MD5 functionality from ESP ROM (#618)
* Add ROM MD5 definitions in linker and devices

* Add initial MD5 support

* Implement traits and add comments to MD5 module

* Add MD5 example to ESP32-C3

* Test MD5 context on the quick brown fox

* Implemenr From<Context> for Digest

* Add MD5 to the rest of the examples

* Add docs for MD5

* Remove #[repr(transparent)] from md5::Digest

* Update CHANGELOG.md
2023-07-04 11:47:21 +01:00
bjoernQ
b5fe37e6e7 Update CHANGELOG.md 2023-07-04 11:47:21 +01:00
bjoernQ
61b57e722e Avoid overlapping .data / .rwtext 2023-07-04 11:47:21 +01:00
Scott Mabin
510dba03b4 Fix insertion location of trap section in ram (#605)
* Fix insertion location of trap section in ram

* Apply fixes for db and mcuboot

* Add changelog
2023-07-04 11:47:21 +01:00
Jesse Braham
0b26d3851c Clean up re-exports and make small improvements to documentation (#607)
* Create issue_handler.yml

* No longer re-export `embedded-hal`, hide exported macros in documentation

* Add simple package-level documentation for each HAL package

* Clean up/simplify re-exports

* Fix the examples that I broke

* Ensure top-level modules/types/functions have doc comments

* Update CHANGELOG

* Re-export the `soc::psram` module where available

---------

Co-authored-by: Sergio Gasquez Arcos <sergio.gasquez@gmail.com>
2023-07-04 11:47:21 +01:00
Sergio Gasquez Arcos
a72d292a74 Create issue_handler.yml 2023-07-04 11:47:21 +01:00
Jesse Braham
c38ed67fb0 Fix the octal_psram example for ESP32-S3, check example in CI 2023-07-04 11:47:21 +01:00
Kirill Mikhailov
14f46371eb Fix: incorrect variable access (#603)
* Fix: incorrect variable access 


Added the change to the Changelog


Fix: typo

* Additional details for the CHANGELOG entry
2023-07-04 11:47:21 +01:00
Björn Quentin
0c1d59b553 ESP32-S3 Octal SPIRAM Support (#610)
* ESP32-S3 Octal SPIRAM Support

* Adjust some code comments
2023-07-04 11:47:21 +01:00
bjoernQ
a4bc624e2d Fix ESP32-S3 PSRAM start address calculation 2023-07-04 11:47:21 +01:00
Jordan Halase
1cfc3eccb5 Fix rom::crc docs (#611)
* Fix rom::crc docs

* Make ROM mod.rs consistent with esp-idf-hal
2023-07-04 11:47:21 +01:00
Jesse Braham
b51a5ed1fa Use both timers in TIMG0 for embassy time driver when able (#609)
* Use both timers in `TIMG0` for embassy time driver when able

* Update CHANGELOG
2023-07-04 11:47:21 +01:00
Jesse Braham
8a958e92bc If the embassy feature is enabled, ensure that a time driver implementation is available (#608) 2023-07-04 11:47:21 +01:00
Scott Mabin
c0ef68115f Non interrupt examples are working, but interrupt ones just hang... 2023-06-21 15:40:51 +02:00
Scott Mabin
978ae3c451 start but not working 2023-06-21 13:44:45 +02:00
140 changed files with 2278577 additions and 734 deletions

View File

@ -313,6 +313,8 @@ jobs:
run: cd esp32s3-hal/ && cargo check --example=embassy_serial --features=embassy,embassy-time-timg0,async run: cd esp32s3-hal/ && cargo check --example=embassy_serial --features=embassy,embassy-time-timg0,async
- name: check esp32s3-hal (async, i2c) - name: check esp32s3-hal (async, i2c)
run: cd esp32s3-hal/ && cargo check --example=embassy_i2c --features=embassy,embassy-time-timg0,async run: cd esp32s3-hal/ && cargo check --example=embassy_i2c --features=embassy,embassy-time-timg0,async
- name: check esp32s3-hal (octal psram)
run: cd esp32s3-hal/ && cargo check --example=octal_psram --features=opsram_2m --release # This example requires release!
esp-riscv-rt: esp-riscv-rt:
runs-on: ubuntu-latest runs-on: ubuntu-latest

16
.github/workflows/issue_handler.yml vendored Normal file
View File

@ -0,0 +1,16 @@
name: Add new issues to project
on:
issues:
types:
- opened
jobs:
add-to-project:
name: Add issue to project
runs-on: ubuntu-latest
steps:
- uses: actions/add-to-project@v0.5.0
with:
project-url: https://github.com/orgs/esp-rs/projects/2
github-token: ${{ secrets.PAT }}

View File

@ -11,48 +11,41 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Added ### Added
- Add `WithDmaSpi3` to prelude for ESP32S3 (#623)
- Add bare-bones PSRAM support for ESP32 (#506) - Add bare-bones PSRAM support for ESP32 (#506)
- Add initial support for the ESP32-H2 (#513) - Add initial support for the ESP32-H2 (#513, #526, #527, #528, #530, #538, #544, #548, #551, #556, #560, #566, #549, #564, #569, #576, #577, #589, #591, #597)
- Add bare-bones PSRAM support for ESP32-S3 (#517) - Add bare-bones PSRAM support for ESP32-S3 (#517)
- Add async support to the I2C driver (#519) - Add async support to the I2C driver (#519)
- Add initial support for RSA in ESP32-H2 (#526)
- Add initial support for SHA in ESP32-H2 (#527)
- Add initial support for AES in ESP32-H2 (#528)
- Add blinky_erased_pins example for ESP32-H2 (#530)
- Add initial support for I2C in ESP32-H2 (#538)
- Implement Copy and Eq for EspTwaiError (#540) - Implement Copy and Eq for EspTwaiError (#540)
- Add LEDC hardware fade support - Add LEDC hardware fade support (#475)
- Added support for multicore async GPIO (#542) - Added support for multicore async GPIO (#542)
- Add initial support for MCPWM in ESP32-H2 (#544) - Add a fn to poll DMA transfers (#559)
- Add some miscellaneous examples for the ESP32-H2 (#548)
- Add initial support for PCNT in ESP32-H2 (#551)
- Add initial support for RMT in ESP32-H2 (#556)
- Add a fn to poll DMA transfers
- Add initial support for LEDC in ESP32-H2 (#560)
- Add initial support for ASSIST_DEBUG in ESP32-H2 (#566)
- Add all `SPI` examples for the ESP32-H2 (#549)
- Add initial support for ADC in ESP32-H2 (#564)
- Simplify the `Delay` driver, derive `Clone` and `Copy` (#568) - Simplify the `Delay` driver, derive `Clone` and `Copy` (#568)
- Add `embassy_serial` and `embassy_wait` examples for ESP32-H2 (#569)
- Fix Async GPIO not disabling interupts on chips with multiple banks (#572) - Fix Async GPIO not disabling interupts on chips with multiple banks (#572)
- Add unified field-based efuse access - Add unified field-based efuse access (#567)
- Add `timer_interrupt` example in ESP32-H2 and refactor `clk_src` configuration (#576)
- Move `esp-riscv-rt` into esp-hal (#578) - Move `esp-riscv-rt` into esp-hal (#578)
- Add initial implementation of radio clocks for ESP32-H2 (#577) - Add CRC functions from ESP ROM (#587)
- Add initial support for `esp-hal-smartled` in ESP32-H2 (#589)
- Add CRC functions from ESP ROM
- Add initial support for RNG in ESP32-H2 (#591)
- Add a `debug` feature to enable the PACs' `impl-register-debug` feature (#596) - Add a `debug` feature to enable the PACs' `impl-register-debug` feature (#596)
- Add initial support for `I2S` in ESP32-H2 (#597) - Add initial support for `I2S` in ESP32-H2 (#597)
- Fix rom::crc docs
- Add octal PSRAM support for ESP32-S3 (#610)
- Add MD5 functions from ESP ROM (#618)
- Add embassy async `read` support for `uart` (#620)
### Changed ### Changed
- DMA types can no longer be constructed by the user (#625)
- Move core interrupt handling from Flash to RAM for RISC-V chips (ESP32-H2, ESP32-C2, ESP32-C3, ESP32-C6) (#541) - Move core interrupt handling from Flash to RAM for RISC-V chips (ESP32-H2, ESP32-C2, ESP32-C3, ESP32-C6) (#541)
- Change LED pin to GPIO2 in ESP32 blinky example (#581) - Change LED pin to GPIO2 in ESP32 blinky example (#581)
- Udpate ESP32-H2 and C6 ESP32-clocks and remove i2c_clock for all chips but ESP32 (#592) - Update ESP32-H2 and ESP32-C6 clocks and remove `i2c_clock` for all chips but ESP32 (#592)
- Use both timers in `TIMG0` for embassy time driver when able (#609)
- Re-work `RadioExt` implementations, add support for ESP32-H2 (#627)
- Improve examples documentation (#533)
- esp32h2-hal: added README (#585)
### Fixed ### Fixed
- Corrected the expected DMA descriptor counts (#622, #625)
- DMA is supported for SPI3 on ESP32-S3 (#507) - DMA is supported for SPI3 on ESP32-S3 (#507)
- `change_bus_frequency` is now available on `SpiDma` (#529) - `change_bus_frequency` is now available on `SpiDma` (#529)
- Fixed a bug where a GPIO interrupt could erroneously fire again causing the next `await` on that pin to instantly return `Poll::Ok` (#537) - Fixed a bug where a GPIO interrupt could erroneously fire again causing the next `await` on that pin to instantly return `Poll::Ok` (#537)
@ -61,18 +54,20 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- ADC driver will now apply attenuation values to the correct ADC's channels. (#554) - ADC driver will now apply attenuation values to the correct ADC's channels. (#554)
- Sometimes half-duplex non-DMA SPI reads were reading garbage in non-release mode (#552) - Sometimes half-duplex non-DMA SPI reads were reading garbage in non-release mode (#552)
- ESP32-C3: Fix GPIO5 ADC channel id (#562) - ESP32-C3: Fix GPIO5 ADC channel id (#562)
- ESP32-H2: Fix direct-boot feature - ESP32-H2: Fix direct-boot feature (#570)
- ESP32-C6: Support FOSC CLK calibration for ECO1+ chip revisions - ESP32-C6: Support FOSC CLK calibration for ECO1+ chip revisions (#593)
- Fixed CI by pinning the log crate to 0.4.18 (#600) - Fixed CI by pinning the log crate to 0.4.18 (#600)
- ESP32-S3: Fix calculation of PSRAM start address
### Changed - Fixed wrong variable access (FOSC CLK calibration for ESP32-C6 #593)
- Fixed [trap location in ram](https://github.com/esp-rs/esp-hal/pull/605#issuecomment-1604039683) (#605)
- Improve examples documentation (#533) - Fixed a possible overlap of `.data` and `.rwtext` (#616)
- esp32h2-hal: added README (#585) - Avoid SDA/SCL being low while configuring pins for I2C
### Breaking ### Breaking
- Simplified user-facing SpiDma and I2s types (#626)
- Significantly simplified user-facing GPIO pin types. (#553) - Significantly simplified user-facing GPIO pin types. (#553)
- No longer re-export the `soc` module and the contents of the `interrupt` module at the package level (#607)
## [0.9.0] - 2023-05-02 ## [0.9.0] - 2023-05-02

View File

@ -43,7 +43,7 @@ riscv-atomic-emulation-trap = { version = "0.4.0", optional = true }
# Xtensa # Xtensa
xtensa-lx = { version = "0.8.0", optional = true } xtensa-lx = { version = "0.8.0", optional = true }
xtensa-lx-rt = { version = "0.15.0", optional = true } xtensa-lx-rt = { version = "0.15.0", optional = true, path = "/home/mabez/development/rust/embedded/projects/xtensa-lx-rt" }
# Part of `ufmt` containing only `uWrite` trait # Part of `ufmt` containing only `uWrite` trait
ufmt-write = { version = "0.1.0", optional = true } ufmt-write = { version = "0.1.0", optional = true }
@ -82,6 +82,10 @@ psram_2m = []
psram_4m = [] psram_4m = []
psram_8m = [] psram_8m = []
opsram_2m = []
opsram_4m = []
opsram_8m = []
# Implement the `embedded-hal==1.0.0-alpha.x` traits # Implement the `embedded-hal==1.0.0-alpha.x` traits
eh1 = ["embedded-hal-1", "embedded-hal-nb", "embedded-can"] eh1 = ["embedded-hal-1", "embedded-hal-nb", "embedded-can"]

View File

@ -1,4 +1,8 @@
use std::{env, fs, path::PathBuf}; use std::{
env,
fs,
path::{Path, PathBuf},
};
use serde::Deserialize; use serde::Deserialize;
@ -144,13 +148,20 @@ fn main() {
println!("cargo:rustc-cfg={peripheral}"); println!("cargo:rustc-cfg={peripheral}");
} }
// check PSRAM features are only given if the target supports PSRAM // Check PSRAM features are only given if the target supports PSRAM
if !&device.peripherals.contains(&String::from("psram")) if !&device.peripherals.contains(&String::from("psram"))
&& (cfg!(feature = "psram_2m") || cfg!(feature = "psram_4m") || cfg!(feature = "psram_8m")) && (cfg!(feature = "psram_2m") || cfg!(feature = "psram_4m") || cfg!(feature = "psram_8m"))
{ {
panic!("The target does not support PSRAM"); panic!("The target does not support PSRAM");
} }
// If the `embassy` feature is enabled, ensure that a time driver implementation
// is available
#[cfg(feature = "embassy")]
{
assert_unique_used_features!("embassy-time-systick", "embassy-time-timg0");
}
// Place all linker scripts in `OUT_DIR`, and instruct Cargo how to find these // Place all linker scripts in `OUT_DIR`, and instruct Cargo how to find these
// files: // files:
let out = PathBuf::from(env::var_os("OUT_DIR").unwrap()); let out = PathBuf::from(env::var_os("OUT_DIR").unwrap());
@ -169,10 +180,7 @@ fn main() {
gen_efuse_table(device_name, out); gen_efuse_table(device_name, out);
} }
fn copy_dir_all( fn copy_dir_all(src: impl AsRef<Path>, dst: impl AsRef<Path>) -> std::io::Result<()> {
src: impl AsRef<std::path::Path>,
dst: impl AsRef<std::path::Path>,
) -> std::io::Result<()> {
fs::create_dir_all(&dst)?; fs::create_dir_all(&dst)?;
for entry in fs::read_dir(src)? { for entry in fs::read_dir(src)? {
let entry = entry?; let entry = entry?;
@ -186,10 +194,10 @@ fn copy_dir_all(
Ok(()) Ok(())
} }
fn gen_efuse_table(device_name: &str, out_dir: impl AsRef<std::path::Path>) { fn gen_efuse_table(device_name: &str, out_dir: impl AsRef<Path>) {
use std::io::{BufRead, Write}; use std::io::{BufRead, Write};
let src_path = std::path::PathBuf::from(format!("src/soc/{device_name}/efuse.csv")); let src_path = PathBuf::from(format!("src/soc/{device_name}/efuse.csv"));
let out_path = out_dir.as_ref().join("efuse_fields.rs"); let out_path = out_dir.as_ref().join("efuse_fields.rs");
println!("cargo:rerun-if-changed={}", src_path.display()); println!("cargo:rerun-if-changed={}", src_path.display());

View File

@ -61,6 +61,7 @@ peripherals = [
# ROM capabilities # ROM capabilities
"rom_crc_le", "rom_crc_le",
"rom_crc_be", "rom_crc_be",
"rom_md5_bsd",
# Wakeup SOC based on ESP-IDF: # Wakeup SOC based on ESP-IDF:
"pm_support_ext0_wakeup", "pm_support_ext0_wakeup",

View File

@ -42,6 +42,7 @@ peripherals = [
# ROM capabilities # ROM capabilities
"rom_crc_le", "rom_crc_le",
"rom_crc_be", "rom_crc_be",
"rom_md5_mbedtls",
# Wakeup SOC based on ESP-IDF: # Wakeup SOC based on ESP-IDF:
"pm_support_wifi_wakeup", "pm_support_wifi_wakeup",

View File

@ -54,6 +54,7 @@ peripherals = [
# ROM capabilities # ROM capabilities
"rom_crc_le", "rom_crc_le",
"rom_crc_be", "rom_crc_be",
"rom_md5_bsd",
# Wakeup SOC based on ESP-IDF: # Wakeup SOC based on ESP-IDF:
"pm_support_wifi_wakeup", "pm_support_wifi_wakeup",

View File

@ -83,6 +83,7 @@ peripherals = [
# ROM capabilities # ROM capabilities
"rom_crc_le", "rom_crc_le",
"rom_crc_be", "rom_crc_be",
"rom_md5_bsd",
# Wakeup SOC based on ESP-IDF: # Wakeup SOC based on ESP-IDF:
"pm_support_wifi_wakeup", "pm_support_wifi_wakeup",

View File

@ -8,13 +8,13 @@ peripherals = [
"apb_saradc", "apb_saradc",
"assist_debug", "assist_debug",
"dma", "dma",
# "ds", "ds",
# "ecc", "ecc",
"efuse", "efuse",
"gpio", "gpio",
# "hmac", "hmac",
# "hp_apm", "hp_apm",
# "hp_sys", "hp_sys",
"i2c0", "i2c0",
"i2c1", "i2c1",
"i2s0", "i2s0",
@ -22,20 +22,20 @@ peripherals = [
"intpri", "intpri",
"io_mux", "io_mux",
"ledc", "ledc",
# "lp_ana", "lp_ana",
# "lp_aon", "lp_aon",
# "lp_apm", "lp_apm",
"lp_clkrst", "lp_clkrst",
# "lp_peri", "lp_peri",
# "lp_timer", "lp_timer",
"lp_wdt", "lp_wdt",
"mcpwm0", "mcpwm0",
"mem_monitor", "mem_monitor",
"modem_lpcon", "modem_lpcon",
"modem_syscon", "modem_syscon",
# "otp_debug", "otp_debug",
# "parl_io", "parl_io",
# "pau", "pau",
"pcnt", "pcnt",
"pcr", "pcr",
"pmu", "pmu",
@ -43,19 +43,19 @@ peripherals = [
"rng", "rng",
"rsa", "rsa",
"sha", "sha",
# "soc_etm", "soc_etm",
"spi0", "spi0",
"spi1", "spi1",
"spi2", "spi2",
"systimer", "systimer",
# "tee", "tee",
"timg0", "timg0",
"timg1", "timg1",
# "trace", "trace",
# "twai0", # "twai0",
"uart0", "uart0",
"uart1", "uart1",
# "uhci0", "uhci0",
"usb_device", "usb_device",
# Additional peripherals defined by us (the developers): # Additional peripherals defined by us (the developers):
@ -72,4 +72,5 @@ peripherals = [
# ROM capabilities # ROM capabilities
"rom_crc_le", "rom_crc_le",
"rom_crc_be", "rom_crc_be",
"rom_md5_bsd",
] ]

View File

@ -57,6 +57,7 @@ peripherals = [
# ROM capabilities # ROM capabilities
"rom_crc_le", "rom_crc_le",
"rom_md5_bsd",
# Wakeup SOC based on ESP-IDF: # Wakeup SOC based on ESP-IDF:
"pm_support_ext0_wakeup", "pm_support_ext0_wakeup",

View File

@ -70,6 +70,7 @@ peripherals = [
# ROM capabilities # ROM capabilities
"rom_crc_le", "rom_crc_le",
"rom_crc_be", "rom_crc_be",
"rom_md5_bsd",
# Wakeup SOC based on ESP-IDF: # Wakeup SOC based on ESP-IDF:
"pm_support_ext0_wakeup", "pm_support_ext0_wakeup",

View File

@ -2,7 +2,7 @@
SECTIONS { SECTIONS {
.rodata_dummy (NOLOAD) : .rodata_dummy (NOLOAD) : ALIGN(4)
{ {
/* This dummy section represents the .flash.text section but in RODATA. /* This dummy section represents the .flash.text section but in RODATA.
* Thus, it must have its alignment and (at least) its size. * Thus, it must have its alignment and (at least) its size.
@ -14,7 +14,7 @@ SECTIONS {
/* Create an empty gap as big as .text section */ /* Create an empty gap as big as .text section */
. = SIZEOF(.text); . = . + SIZEOF(.text);
/* Prepare the alignment of the section above. Few bytes (0x20) must be /* Prepare the alignment of the section above. Few bytes (0x20) must be
* added for the mapping header. * added for the mapping header.

View File

@ -4,10 +4,10 @@
*/ */
SECTIONS { SECTIONS {
.rtc_fast.dummy (NOLOAD) : .rtc_fast.dummy (NOLOAD) : ALIGN(4)
{ {
_rtc_dummy_start = ABSOLUTE(.); /* needed to make section proper size */ _rtc_dummy_start = ABSOLUTE(.); /* needed to make section proper size */
. = SIZEOF(.rtc_fast.text); . = . + SIZEOF(.rtc_fast.text);
_rtc_dummy_end = ABSOLUTE(.); /* needed to make section proper size */ _rtc_dummy_end = ABSOLUTE(.); /* needed to make section proper size */
} > RTC_FAST_RWDATA } > RTC_FAST_RWDATA
} }

View File

@ -3,15 +3,18 @@
SECTIONS { SECTIONS {
.rodata : ALIGN(4) .rodata : ALIGN(4)
{ {
_rodata_start = ABSOLUTE(.);
. = ALIGN (4); . = ALIGN (4);
_rodata_start = ABSOLUTE(.);
*(.rodata .rodata.*) *(.rodata .rodata.*)
*(.srodata .srodata.*) *(.srodata .srodata.*)
_rodata_end = ABSOLUTE(.); _rodata_end = ABSOLUTE(.);
. = ALIGN(4);
} > RODATA } > RODATA
.rodata.wifi : ALIGN(4) .rodata.wifi : ALIGN(4)
{ {
. = ALIGN(4);
*( .rodata_wlog_*.* ) *( .rodata_wlog_*.* )
. = ALIGN(4);
} > RODATA } > RODATA
} }

View File

@ -3,7 +3,8 @@
SECTIONS { SECTIONS {
.rtc_fast.text : { .rtc_fast.text : {
. = ALIGN(4); . = ALIGN(4);
*(.rtc_fast.literal .rtc_fast.text .rtc_fast.literal.* .rtc_fast.text.*) *(.rtc_fast.literal .rtc_fast.text .rtc_fast.literal.* .rtc_fast.text.*)
. = ALIGN(4);
} > RTC_FAST_RWTEXT AT > RODATA } > RTC_FAST_RWTEXT AT > RODATA
.rtc_fast.data : .rtc_fast.data :
@ -12,6 +13,7 @@ SECTIONS {
_rtc_fast_data_start = ABSOLUTE(.); _rtc_fast_data_start = ABSOLUTE(.);
*(.rtc_fast.data .rtc_fast.data.*) *(.rtc_fast.data .rtc_fast.data.*)
_rtc_fast_data_end = ABSOLUTE(.); _rtc_fast_data_end = ABSOLUTE(.);
. = ALIGN(4);
} > RTC_FAST_RWDATA AT > RODATA } > RTC_FAST_RWDATA AT > RODATA
.rtc_fast.bss (NOLOAD) : .rtc_fast.bss (NOLOAD) :
@ -20,11 +22,13 @@ SECTIONS {
_rtc_fast_bss_start = ABSOLUTE(.); _rtc_fast_bss_start = ABSOLUTE(.);
*(.rtc_fast.bss .rtc_fast.bss.*) *(.rtc_fast.bss .rtc_fast.bss.*)
_rtc_fast_bss_end = ABSOLUTE(.); _rtc_fast_bss_end = ABSOLUTE(.);
. = ALIGN(4);
} > RTC_FAST_RWDATA } > RTC_FAST_RWDATA
.rtc_fast.noinit (NOLOAD) : .rtc_fast.noinit (NOLOAD) :
{ {
. = ALIGN(4); . = ALIGN(4);
*(.rtc_fast.noinit .rtc_fast.noinit.*) *(.rtc_fast.noinit .rtc_fast.noinit.*)
. = ALIGN(4);
} > RTC_FAST_RWDATA } > RTC_FAST_RWDATA
} }

View File

@ -3,7 +3,8 @@
SECTIONS { SECTIONS {
.rtc_slow.text : { .rtc_slow.text : {
. = ALIGN(4); . = ALIGN(4);
*(.rtc_slow.literal .rtc_slow.text .rtc_slow.literal.* .rtc_slow.text.*) *(.rtc_slow.literal .rtc_slow.text .rtc_slow.literal.* .rtc_slow.text.*)
. = ALIGN(4);
} > rtc_slow_seg AT > RODATA } > rtc_slow_seg AT > RODATA
.rtc_slow.data : .rtc_slow.data :
@ -12,6 +13,7 @@ SECTIONS {
_rtc_slow_data_start = ABSOLUTE(.); _rtc_slow_data_start = ABSOLUTE(.);
*(.rtc_slow.data .rtc_slow.data.*) *(.rtc_slow.data .rtc_slow.data.*)
_rtc_slow_data_end = ABSOLUTE(.); _rtc_slow_data_end = ABSOLUTE(.);
. = ALIGN(4);
} > rtc_slow_seg AT > RODATA } > rtc_slow_seg AT > RODATA
.rtc_slow.bss (NOLOAD) : .rtc_slow.bss (NOLOAD) :
@ -20,11 +22,13 @@ SECTIONS {
_rtc_slow_bss_start = ABSOLUTE(.); _rtc_slow_bss_start = ABSOLUTE(.);
*(.rtc_slow.bss .rtc_slow.bss.*) *(.rtc_slow.bss .rtc_slow.bss.*)
_rtc_slow_bss_end = ABSOLUTE(.); _rtc_slow_bss_end = ABSOLUTE(.);
. = ALIGN(4);
} > rtc_slow_seg } > rtc_slow_seg
.rtc_slow.noinit (NOLOAD) : .rtc_slow.noinit (NOLOAD) :
{ {
. = ALIGN(4); . = ALIGN(4);
*(.rtc_slow.noinit .rtc_slow.noinit.*) *(.rtc_slow.noinit .rtc_slow.noinit.*)
. = ALIGN(4);
} > rtc_slow_seg } > rtc_slow_seg
} }

View File

@ -9,6 +9,7 @@ SECTIONS {
*(.data .data.*); *(.data .data.*);
*(.data1) *(.data1)
_data_end = ABSOLUTE(.); _data_end = ABSOLUTE(.);
. = ALIGN(4);
} > RWDATA AT > RODATA } > RWDATA AT > RODATA
/* LMA of .data */ /* LMA of .data */
@ -32,18 +33,21 @@ SECTIONS {
*(.gnu.linkonce.b.*) *(.gnu.linkonce.b.*)
*(COMMON) *(COMMON)
_bss_end = ABSOLUTE(.); _bss_end = ABSOLUTE(.);
. = ALIGN(4);
} > RWDATA } > RWDATA
.noinit (NOLOAD) : ALIGN(4) .noinit (NOLOAD) : ALIGN(4)
{ {
. = ALIGN(4); . = ALIGN(4);
*(.noinit .noinit.*) *(.noinit .noinit.*)
. = ALIGN(4);
} > RWDATA } > RWDATA
.data.wifi : .data.wifi : ALIGN(4)
{ {
. = ALIGN(4); . = ALIGN(4);
*( .dram1 .dram1.*) *( .dram1 .dram1.*)
. = ALIGN(4);
} > RWDATA AT > RODATA } > RWDATA AT > RODATA
/* must be last segment using RWDATA */ /* must be last segment using RWDATA */

View File

@ -5,9 +5,10 @@ SECTIONS {
{ {
. = ALIGN (4); . = ALIGN (4);
*(.rwtext.literal .rwtext .rwtext.literal.* .rwtext.*) *(.rwtext.literal .rwtext .rwtext.literal.* .rwtext.*)
. = ALIGN(4);
} > RWTEXT } > RWTEXT
.rwtext.wifi : .rwtext.wifi : ALIGN(4)
{ {
. = ALIGN(4); . = ALIGN(4);
*( .wifi0iram .wifi0iram.*) *( .wifi0iram .wifi0iram.*)
@ -16,5 +17,6 @@ SECTIONS {
*( .wifislpiram .wifislpiram.*) *( .wifislpiram .wifislpiram.*)
*( .phyiram .phyiram.*) *( .phyiram .phyiram.*)
*( .iram1 .iram1.*) *( .iram1 .iram1.*)
. = ALIGN(4);
} > RWTEXT AT > RODATA } > RWTEXT AT > RODATA
} }

View File

@ -4,7 +4,9 @@ SECTIONS {
.text : ALIGN(4) .text : ALIGN(4)
{ {
. = ALIGN(4);
*(.literal .text .literal.* .text.*) *(.literal .text .literal.* .text.*)
. = ALIGN(4);
} > ROTEXT } > ROTEXT
} }

View File

@ -9,8 +9,15 @@ use crate::{
macro_rules! impl_channel { macro_rules! impl_channel {
($num: literal) => { ($num: literal) => {
paste::paste! { paste::paste! {
#[non_exhaustive]
pub struct [<Channel $num>] {} pub struct [<Channel $num>] {}
impl ChannelTypes for [<Channel $num>] {
type P = [<SuitablePeripheral $num>];
type Tx<'a> = ChannelTx<'a, [<Channel $num TxImpl>], [<Channel $num>]>;
type Rx<'a> = ChannelRx<'a, [<Channel $num RxImpl>], [<Channel $num>]>;
}
impl RegisterAccess for [<Channel $num>] { impl RegisterAccess for [<Channel $num>] {
fn init_channel() { fn init_channel() {
// nothing special to be done here // nothing special to be done here
@ -365,6 +372,7 @@ macro_rules! impl_channel {
} }
} }
#[non_exhaustive]
pub struct [<Channel $num TxImpl>] {} pub struct [<Channel $num TxImpl>] {}
impl<'a> TxChannel<[<Channel $num>]> for [<Channel $num TxImpl>] { impl<'a> TxChannel<[<Channel $num>]> for [<Channel $num TxImpl>] {
@ -375,6 +383,7 @@ macro_rules! impl_channel {
} }
} }
#[non_exhaustive]
pub struct [<Channel $num RxImpl>] {} pub struct [<Channel $num RxImpl>] {}
impl<'a> RxChannel<[<Channel $num>]> for [<Channel $num RxImpl>] { impl<'a> RxChannel<[<Channel $num>]> for [<Channel $num RxImpl>] {
@ -385,19 +394,21 @@ macro_rules! impl_channel {
} }
} }
#[non_exhaustive]
pub struct [<ChannelCreator $num>] {} pub struct [<ChannelCreator $num>] {}
impl [<ChannelCreator $num>] { impl [<ChannelCreator $num>] {
/// Configure the channel for use /// Configure the channel for use
/// ///
/// Descriptors should be sized as (BUFFERSIZE / 4092) * 3 /// Descriptors should be sized as `((BUFFERSIZE + 4091) / 4092) * 3`. I.e., to
/// transfer buffers of size `1..=4092`, you need 3 descriptors.
pub fn configure<'a>( pub fn configure<'a>(
self, self,
burst_mode: bool, burst_mode: bool,
tx_descriptors: &'a mut [u32], tx_descriptors: &'a mut [u32],
rx_descriptors: &'a mut [u32], rx_descriptors: &'a mut [u32],
priority: DmaPriority, priority: DmaPriority,
) -> Channel<ChannelTx<'a, [<Channel $num TxImpl>], [<Channel $num>]>, ChannelRx<'a, [<Channel $num RxImpl>], [<Channel $num>]>, [<SuitablePeripheral $num>]> { ) -> Channel<'a, [<Channel $num>]> {
let mut tx_impl = [<Channel $num TxImpl>] {}; let mut tx_impl = [<Channel $num TxImpl>] {};
tx_impl.init(burst_mode, priority); tx_impl.init(burst_mode, priority);
@ -431,11 +442,11 @@ macro_rules! impl_channel {
Channel { Channel {
tx: tx_channel, tx: tx_channel,
rx: rx_channel, rx: rx_channel,
_phantom: PhantomData::default(),
} }
} }
} }
#[non_exhaustive]
pub struct [<SuitablePeripheral $num>] {} pub struct [<SuitablePeripheral $num>] {}
impl PeripheralMarker for [<SuitablePeripheral $num>] {} impl PeripheralMarker for [<SuitablePeripheral $num>] {}

View File

@ -1,6 +1,7 @@
//! Direct Memory Access Commons //! Direct Memory Access Commons
//! //!
//! Descriptors should be sized as (BUFFERSIZE / 4092) * 3 //! Descriptors should be sized as `((BUFFERSIZE + 4091) / 4092) * 3`. I.e., to
//! transfer buffers of size `1..=4092`, you need 3 descriptors.
use core::{marker::PhantomData, sync::atomic::compiler_fence}; use core::{marker::PhantomData, sync::atomic::compiler_fence};
@ -347,7 +348,7 @@ where
return Err(DmaError::InvalidDescriptorSize); return Err(DmaError::InvalidDescriptorSize);
} }
if self.descriptors.len() / 3 < len / CHUNK_SIZE { if self.descriptors.len() / 3 < (len + CHUNK_SIZE - 1) / CHUNK_SIZE {
return Err(DmaError::OutOfDescriptors); return Err(DmaError::OutOfDescriptors);
} }
@ -647,7 +648,7 @@ where
return Err(DmaError::InvalidDescriptorSize); return Err(DmaError::InvalidDescriptorSize);
} }
if self.descriptors.len() / 3 < len / CHUNK_SIZE { if self.descriptors.len() / 3 < (len + CHUNK_SIZE - 1) / CHUNK_SIZE {
return Err(DmaError::OutOfDescriptors); return Err(DmaError::OutOfDescriptors);
} }
@ -829,16 +830,20 @@ pub trait RegisterAccess {
fn unlisten_in_eof(); fn unlisten_in_eof();
fn unlisten_out_eof(); fn unlisten_out_eof();
} }
pub trait ChannelTypes {
type P: PeripheralMarker;
type Tx<'a>: Tx;
type Rx<'a>: Rx;
}
/// DMA Channel /// DMA Channel
pub struct Channel<TX, RX, P> pub struct Channel<'d, C>
where where
TX: Tx, C: ChannelTypes,
RX: Rx,
P: PeripheralMarker,
{ {
pub(crate) tx: TX, pub(crate) tx: C::Tx<'d>,
pub(crate) rx: RX, pub(crate) rx: C::Rx<'d>,
_phantom: PhantomData<P>,
} }
/// Trait to be implemented for an in progress dma transfer. /// Trait to be implemented for an in progress dma transfer.

View File

@ -9,8 +9,15 @@ use crate::{
macro_rules! ImplSpiChannel { macro_rules! ImplSpiChannel {
($num: literal) => { ($num: literal) => {
paste::paste! { paste::paste! {
#[non_exhaustive]
pub struct [<Spi $num DmaChannel>] {} pub struct [<Spi $num DmaChannel>] {}
impl ChannelTypes for [<Spi $num DmaChannel>] {
type P = [<Spi $num DmaSuitablePeripheral>];
type Tx<'a> = ChannelTx<'a,[<Spi $num DmaChannelTxImpl>], [<Spi $num DmaChannel>]>;
type Rx<'a> = ChannelRx<'a,[<Spi $num DmaChannelRxImpl>], [<Spi $num DmaChannel>]>;
}
impl RegisterAccess for [<Spi $num DmaChannel>] { impl RegisterAccess for [<Spi $num DmaChannel>] {
fn init_channel() { fn init_channel() {
// (only) on ESP32 we need to configure DPORT for the SPI DMA channels // (only) on ESP32 we need to configure DPORT for the SPI DMA channels
@ -195,6 +202,7 @@ macro_rules! ImplSpiChannel {
} }
} }
#[non_exhaustive]
pub struct [<Spi $num DmaChannelTxImpl>] {} pub struct [<Spi $num DmaChannelTxImpl>] {}
impl<'a> TxChannel<[<Spi $num DmaChannel>]> for [<Spi $num DmaChannelTxImpl>] { impl<'a> TxChannel<[<Spi $num DmaChannel>]> for [<Spi $num DmaChannelTxImpl>] {
@ -205,6 +213,7 @@ macro_rules! ImplSpiChannel {
} }
} }
#[non_exhaustive]
pub struct [<Spi $num DmaChannelRxImpl>] {} pub struct [<Spi $num DmaChannelRxImpl>] {}
impl<'a> RxChannel<[<Spi $num DmaChannel>]> for [<Spi $num DmaChannelRxImpl>] { impl<'a> RxChannel<[<Spi $num DmaChannel>]> for [<Spi $num DmaChannelRxImpl>] {
@ -215,23 +224,21 @@ macro_rules! ImplSpiChannel {
} }
} }
#[non_exhaustive]
pub struct [<Spi $num DmaChannelCreator>] {} pub struct [<Spi $num DmaChannelCreator>] {}
impl [<Spi $num DmaChannelCreator>] { impl [<Spi $num DmaChannelCreator>] {
/// Configure the channel for use /// Configure the channel for use
/// ///
/// Descriptors should be sized as (BUFFERSIZE / 4092) * 3 /// Descriptors should be sized as `((BUFFERSIZE + 4091) / 4092) * 3`. I.e., to
/// transfer buffers of size `1..=4092`, you need 3 descriptors.
pub fn configure<'a>( pub fn configure<'a>(
self, self,
burst_mode: bool, burst_mode: bool,
tx_descriptors: &'a mut [u32], tx_descriptors: &'a mut [u32],
rx_descriptors: &'a mut [u32], rx_descriptors: &'a mut [u32],
priority: DmaPriority, priority: DmaPriority,
) -> Channel< ) -> Channel<'a, [<Spi $num DmaChannel>]> {
ChannelTx<'a,[<Spi $num DmaChannelTxImpl>], [<Spi $num DmaChannel>]>,
ChannelRx<'a,[<Spi $num DmaChannelRxImpl>], [<Spi $num DmaChannel>]>,
[<Spi $num DmaSuitablePeripheral>],
> {
let mut tx_impl = [<Spi $num DmaChannelTxImpl>] {}; let mut tx_impl = [<Spi $num DmaChannelTxImpl>] {};
tx_impl.init(burst_mode, priority); tx_impl.init(burst_mode, priority);
@ -265,7 +272,6 @@ macro_rules! ImplSpiChannel {
Channel { Channel {
tx: tx_channel, tx: tx_channel,
rx: rx_channel, rx: rx_channel,
_phantom: PhantomData::default(),
} }
} }
} }
@ -278,6 +284,12 @@ macro_rules! ImplI2sChannel {
paste::paste! { paste::paste! {
pub struct [<I2s $num DmaChannel>] {} pub struct [<I2s $num DmaChannel>] {}
impl ChannelTypes for [<I2s $num DmaChannel>] {
type P = [<I2s $num DmaSuitablePeripheral>];
type Tx<'a> = ChannelTx<'a,[<I2s $num DmaChannelTxImpl>], [<I2s $num DmaChannel>]>;
type Rx<'a> = ChannelRx<'a,[<I2s $num DmaChannelRxImpl>], [<I2s $num DmaChannel>]>;
}
impl RegisterAccess for [<I2s $num DmaChannel>] { impl RegisterAccess for [<I2s $num DmaChannel>] {
fn init_channel() { fn init_channel() {
// nothing to do // nothing to do
@ -458,18 +470,15 @@ macro_rules! ImplI2sChannel {
impl [<I2s $num DmaChannelCreator>] { impl [<I2s $num DmaChannelCreator>] {
/// Configure the channel for use /// Configure the channel for use
/// ///
/// Descriptors should be sized as (BUFFERSIZE / 4092) * 3 /// Descriptors should be sized as `((BUFFERSIZE + 4091) / 4092) * 3`. I.e., to
/// transfer buffers of size `1..=4092`, you need 3 descriptors.
pub fn configure<'a>( pub fn configure<'a>(
self, self,
burst_mode: bool, burst_mode: bool,
tx_descriptors: &'a mut [u32], tx_descriptors: &'a mut [u32],
rx_descriptors: &'a mut [u32], rx_descriptors: &'a mut [u32],
priority: DmaPriority, priority: DmaPriority,
) -> Channel< ) -> Channel<'a, [<I2s $num DmaChannel>]> {
ChannelTx<'a,[<I2s $num DmaChannelTxImpl>], [<I2s $num DmaChannel>]>,
ChannelRx<'a,[<I2s $num DmaChannelRxImpl>], [<I2s $num DmaChannel>]>,
[<I2s $num DmaSuitablePeripheral>],
> {
let mut tx_impl = [<I2s $num DmaChannelTxImpl>] {}; let mut tx_impl = [<I2s $num DmaChannelTxImpl>] {};
tx_impl.init(burst_mode, priority); tx_impl.init(burst_mode, priority);
@ -503,7 +512,6 @@ macro_rules! ImplI2sChannel {
Channel { Channel {
tx: tx_channel, tx: tx_channel,
rx: rx_channel, rx: rx_channel,
_phantom: PhantomData::default(),
} }
} }
} }
@ -511,11 +519,13 @@ macro_rules! ImplI2sChannel {
}; };
} }
#[non_exhaustive]
pub struct Spi2DmaSuitablePeripheral {} pub struct Spi2DmaSuitablePeripheral {}
impl PeripheralMarker for Spi2DmaSuitablePeripheral {} impl PeripheralMarker for Spi2DmaSuitablePeripheral {}
impl SpiPeripheral for Spi2DmaSuitablePeripheral {} impl SpiPeripheral for Spi2DmaSuitablePeripheral {}
impl Spi2Peripheral for Spi2DmaSuitablePeripheral {} impl Spi2Peripheral for Spi2DmaSuitablePeripheral {}
#[non_exhaustive]
pub struct Spi3DmaSuitablePeripheral {} pub struct Spi3DmaSuitablePeripheral {}
impl PeripheralMarker for Spi3DmaSuitablePeripheral {} impl PeripheralMarker for Spi3DmaSuitablePeripheral {}
impl SpiPeripheral for Spi3DmaSuitablePeripheral {} impl SpiPeripheral for Spi3DmaSuitablePeripheral {}
@ -524,6 +534,7 @@ impl Spi3Peripheral for Spi3DmaSuitablePeripheral {}
ImplSpiChannel!(2); ImplSpiChannel!(2);
ImplSpiChannel!(3); ImplSpiChannel!(3);
#[non_exhaustive]
pub struct I2s0DmaSuitablePeripheral {} pub struct I2s0DmaSuitablePeripheral {}
impl PeripheralMarker for I2s0DmaSuitablePeripheral {} impl PeripheralMarker for I2s0DmaSuitablePeripheral {}
impl I2sPeripheral for I2s0DmaSuitablePeripheral {} impl I2sPeripheral for I2s0DmaSuitablePeripheral {}
@ -531,6 +542,7 @@ impl I2s0Peripheral for I2s0DmaSuitablePeripheral {}
ImplI2sChannel!(0, "I2S0"); ImplI2sChannel!(0, "I2S0");
#[non_exhaustive]
pub struct I2s1DmaSuitablePeripheral {} pub struct I2s1DmaSuitablePeripheral {}
impl PeripheralMarker for I2s1DmaSuitablePeripheral {} impl PeripheralMarker for I2s1DmaSuitablePeripheral {}
impl I2sPeripheral for I2s1DmaSuitablePeripheral {} impl I2sPeripheral for I2s1DmaSuitablePeripheral {}

View File

@ -9,7 +9,10 @@ use crate::{
timer::{Timer, Timer0}, timer::{Timer, Timer0},
}; };
#[cfg(not(any(esp32, esp32s2, esp32s3)))]
pub const ALARM_COUNT: usize = 1; pub const ALARM_COUNT: usize = 1;
#[cfg(any(esp32, esp32s2, esp32s3))]
pub const ALARM_COUNT: usize = 2;
pub type TimerInner = Timer0<TIMG0>; pub type TimerInner = Timer0<TIMG0>;
pub type TimerType = Timer<TimerInner>; pub type TimerType = Timer<TimerInner>;
@ -49,16 +52,25 @@ impl EmbassyTimer {
pub fn init(clocks: &Clocks, mut timer: TimerType) { pub fn init(clocks: &Clocks, mut timer: TimerType) {
use crate::{interrupt, interrupt::Priority}; use crate::{interrupt, interrupt::Priority};
// set divider to get a 1mhz clock. abp (80mhz) / 80 = 1mhz... // TODO assert // set divider to get a 1mhz clock. APB (80mhz) / 80 = 1mhz...
// abp clock is the source and its at the correct speed for the divider // TODO: assert APB clock is the source and its at the correct speed for the
// divider
timer.set_divider(clocks.apb_clock.to_MHz() as u16); timer.set_divider(clocks.apb_clock.to_MHz() as u16);
interrupt::enable(peripherals::Interrupt::TG0_T0_LEVEL, Priority::max()).unwrap(); interrupt::enable(peripherals::Interrupt::TG0_T0_LEVEL, Priority::max()).unwrap();
#[cfg(any(esp32, esp32s2, esp32s3))]
interrupt::enable(peripherals::Interrupt::TG0_T1_LEVEL, Priority::max()).unwrap();
#[interrupt] #[interrupt]
fn TG0_T0_LEVEL() { fn TG0_T0_LEVEL() {
DRIVER.on_interrupt(0); DRIVER.on_interrupt(0);
} }
#[cfg(any(esp32, esp32s2, esp32s3))]
#[interrupt]
fn TG0_T1_LEVEL() {
DRIVER.on_interrupt(1);
}
} }
pub(crate) fn set_alarm( pub(crate) fn set_alarm(

View File

@ -1230,6 +1230,7 @@ impl<MODE> embedded_hal_async::digital::Wait for AnyPin<Input<MODE>> {
} }
} }
/// General Purpose Input/Output driver
pub struct IO { pub struct IO {
_io_mux: IO_MUX, _io_mux: IO_MUX,
pub pins: Pins, pub pins: Pins,

View File

@ -250,7 +250,10 @@ where
let mut i2c = I2C { peripheral: i2c }; let mut i2c = I2C { peripheral: i2c };
// initialize SCL first to not confuse some devices like MPU6050 // avoid SCL/SDA going low during configuration
scl.set_output_high(true);
sda.set_output_high(true);
scl.set_to_open_drain_output() scl.set_to_open_drain_output()
.enable_input(true) .enable_input(true)
.internal_pull_up(true) .internal_pull_up(true)

View File

@ -7,7 +7,16 @@ use private::*;
use crate::dma::I2s1Peripheral; use crate::dma::I2s1Peripheral;
use crate::{ use crate::{
clock::Clocks, clock::Clocks,
dma::{Channel, DmaError, DmaTransfer, I2s0Peripheral, I2sPeripheral, Rx, Tx}, dma::{
Channel,
ChannelTypes,
DmaError,
DmaTransfer,
I2s0Peripheral,
I2sPeripheral,
RxPrivate,
TxPrivate,
},
gpio::{InputPin, OutputPin}, gpio::{InputPin, OutputPin},
peripheral::{Peripheral, PeripheralRef}, peripheral::{Peripheral, PeripheralRef},
system::PeripheralClockControl, system::PeripheralClockControl,
@ -271,21 +280,21 @@ impl I2sMclkPin for NoMclk {
} }
/// An in-progress DMA write transfer. /// An in-progress DMA write transfer.
pub struct I2sWriteDmaTransfer<T, P, TX, BUFFER> pub struct I2sWriteDmaTransfer<'d, T, P, CH, BUFFER>
where where
T: RegisterAccess, T: RegisterAccess,
CH: ChannelTypes,
P: I2sTxPins, P: I2sTxPins,
TX: Tx,
{ {
i2s_tx: I2sTx<T, P, TX>, i2s_tx: I2sTx<'d, T, P, CH>,
buffer: BUFFER, buffer: BUFFER,
} }
impl<'d, T, P, TX, BUFFER> I2sWriteDmaTransfer<T, P, TX, BUFFER> impl<'d, T, P, CH, BUFFER> I2sWriteDmaTransfer<'d, T, P, CH, BUFFER>
where where
T: RegisterAccess, T: RegisterAccess,
CH: ChannelTypes,
P: I2sTxPins, P: I2sTxPins,
TX: Tx,
{ {
/// Amount of bytes which can be pushed. /// Amount of bytes which can be pushed.
/// Only useful for circular DMA transfers /// Only useful for circular DMA transfers
@ -300,16 +309,16 @@ where
} }
} }
impl<'d, T, P, TX, BUFFER> DmaTransfer<BUFFER, I2sTx<T, P, TX>> impl<'d, T, P, CH, BUFFER> DmaTransfer<BUFFER, I2sTx<'d, T, P, CH>>
for I2sWriteDmaTransfer<T, P, TX, BUFFER> for I2sWriteDmaTransfer<'d, T, P, CH, BUFFER>
where where
T: RegisterAccess, T: RegisterAccess,
CH: ChannelTypes,
P: I2sTxPins, P: I2sTxPins,
TX: Tx,
{ {
/// Wait for the DMA transfer to complete and return the buffers and the /// Wait for the DMA transfer to complete and return the buffers and the
/// I2sTx instance. /// I2sTx instance.
fn wait(self) -> (BUFFER, I2sTx<T, P, TX>) { fn wait(self) -> (BUFFER, I2sTx<'d, T, P, CH>) {
self.i2s_tx.wait_tx_dma_done().ok(); // waiting for the DMA transfer is not enough self.i2s_tx.wait_tx_dma_done().ok(); // waiting for the DMA transfer is not enough
// `DmaTransfer` needs to have a `Drop` implementation, because we accept // `DmaTransfer` needs to have a `Drop` implementation, because we accept
@ -333,11 +342,11 @@ where
} }
} }
impl<'d, T, P, TX, BUFFER> Drop for I2sWriteDmaTransfer<T, P, TX, BUFFER> impl<'d, T, P, CH, BUFFER> Drop for I2sWriteDmaTransfer<'d, T, P, CH, BUFFER>
where where
T: RegisterAccess, T: RegisterAccess,
CH: ChannelTypes,
P: I2sTxPins, P: I2sTxPins,
TX: Tx,
{ {
fn drop(&mut self) { fn drop(&mut self) {
self.i2s_tx.wait_tx_dma_done().ok(); self.i2s_tx.wait_tx_dma_done().ok();
@ -350,53 +359,47 @@ pub trait I2sWrite<W> {
} }
/// Initiate a DMA tx transfer /// Initiate a DMA tx transfer
pub trait I2sWriteDma<'d, T, P, TX, TXBUF> pub trait I2sWriteDma<'d, T, P, CH, TXBUF>
where where
T: RegisterAccess, T: RegisterAccess,
CH: ChannelTypes,
P: I2sTxPins, P: I2sTxPins,
TX: Tx,
{ {
/// Write I2S. /// Write I2S.
/// Returns [I2sWriteDmaTransfer] which represents the in-ptrogress DMA /// Returns [I2sWriteDmaTransfer] which represents the in-progress DMA
/// transfer /// transfer
fn write_dma(self, words: TXBUF) -> Result<I2sWriteDmaTransfer<T, P, TX, TXBUF>, Error> fn write_dma(self, words: TXBUF) -> Result<I2sWriteDmaTransfer<'d, T, P, CH, TXBUF>, Error>
where where
T: RegisterAccess,
P: I2sTxPins,
TX: Tx,
TXBUF: ReadBuffer<Word = u8>; TXBUF: ReadBuffer<Word = u8>;
/// Continously write to I2S. Returns [I2sWriteDmaTransfer] which represents /// Continuously write to I2S. Returns [I2sWriteDmaTransfer] which
/// the in-ptrogress DMA transfer /// represents the in-progress DMA transfer
fn write_dma_circular( fn write_dma_circular(
self, self,
words: TXBUF, words: TXBUF,
) -> Result<I2sWriteDmaTransfer<T, P, TX, TXBUF>, Error> ) -> Result<I2sWriteDmaTransfer<'d, T, P, CH, TXBUF>, Error>
where where
T: RegisterAccess,
P: I2sTxPins,
TX: Tx,
TXBUF: ReadBuffer<Word = u8>; TXBUF: ReadBuffer<Word = u8>;
} }
/// An in-progress DMA read transfer. /// An in-progress DMA read transfer.
pub struct I2sReadDmaTransfer<T, P, RX, BUFFER> pub struct I2sReadDmaTransfer<'d, T, P, CH, BUFFER>
where where
T: RegisterAccess, T: RegisterAccess,
CH: ChannelTypes,
P: I2sRxPins, P: I2sRxPins,
RX: Rx,
{ {
i2s_rx: I2sRx<T, P, RX>, i2s_rx: I2sRx<'d, T, P, CH>,
buffer: BUFFER, buffer: BUFFER,
} }
impl<'d, T, P, RX, BUFFER> I2sReadDmaTransfer<T, P, RX, BUFFER> impl<'d, T, P, CH, BUFFER> I2sReadDmaTransfer<'d, T, P, CH, BUFFER>
where where
T: RegisterAccess, T: RegisterAccess,
CH: ChannelTypes,
P: I2sRxPins, P: I2sRxPins,
RX: Rx,
{ {
/// Amount of bytes which can be poped /// Amount of bytes which can be popped
pub fn available(&mut self) -> usize { pub fn available(&mut self) -> usize {
self.i2s_rx.rx_channel.available() self.i2s_rx.rx_channel.available()
} }
@ -409,7 +412,7 @@ where
/// I2sTx instance after copying the read data to the given buffer. /// I2sTx instance after copying the read data to the given buffer.
/// Length of the received data is returned at the third element of the /// Length of the received data is returned at the third element of the
/// tuple. /// tuple.
pub fn wait_receive(mut self, dst: &mut [u8]) -> (BUFFER, I2sRx<T, P, RX>, usize) { pub fn wait_receive(mut self, dst: &mut [u8]) -> (BUFFER, I2sRx<'d, T, P, CH>, usize) {
self.i2s_rx.wait_rx_dma_done().ok(); // waiting for the DMA transfer is not enough self.i2s_rx.wait_rx_dma_done().ok(); // waiting for the DMA transfer is not enough
let len = self.i2s_rx.rx_channel.drain_buffer(dst).unwrap(); let len = self.i2s_rx.rx_channel.drain_buffer(dst).unwrap();
@ -430,16 +433,16 @@ where
} }
} }
impl<'d, T, P, RX, BUFFER> DmaTransfer<BUFFER, I2sRx<T, P, RX>> impl<'d, T, P, CH, BUFFER> DmaTransfer<BUFFER, I2sRx<'d, T, P, CH>>
for I2sReadDmaTransfer<T, P, RX, BUFFER> for I2sReadDmaTransfer<'d, T, P, CH, BUFFER>
where where
T: RegisterAccess, T: RegisterAccess,
CH: ChannelTypes,
P: I2sRxPins, P: I2sRxPins,
RX: Rx,
{ {
/// Wait for the DMA transfer to complete and return the buffers and the /// Wait for the DMA transfer to complete and return the buffers and the
/// I2sTx instance. /// I2sTx instance.
fn wait(self) -> (BUFFER, I2sRx<T, P, RX>) { fn wait(self) -> (BUFFER, I2sRx<'d, T, P, CH>) {
self.i2s_rx.wait_rx_dma_done().ok(); // waiting for the DMA transfer is not enough self.i2s_rx.wait_rx_dma_done().ok(); // waiting for the DMA transfer is not enough
// `DmaTransfer` needs to have a `Drop` implementation, because we accept // `DmaTransfer` needs to have a `Drop` implementation, because we accept
@ -463,11 +466,11 @@ where
} }
} }
impl<T, P, RX, BUFFER> Drop for I2sReadDmaTransfer<T, P, RX, BUFFER> impl<T, P, CH, BUFFER> Drop for I2sReadDmaTransfer<'_, T, P, CH, BUFFER>
where where
T: RegisterAccess, T: RegisterAccess,
CH: ChannelTypes,
P: I2sRxPins, P: I2sRxPins,
RX: Rx,
{ {
fn drop(&mut self) { fn drop(&mut self) {
self.i2s_rx.wait_rx_dma_done().ok(); self.i2s_rx.wait_rx_dma_done().ok();
@ -479,71 +482,60 @@ pub trait I2sRead<W> {
fn read(&mut self, words: &mut [W]) -> Result<(), Error>; fn read(&mut self, words: &mut [W]) -> Result<(), Error>;
} }
/// Initate a DMA rx transfer /// Initiate a DMA rx transfer
pub trait I2sReadDma<'d, T, P, RX, RXBUF> pub trait I2sReadDma<'d, T, P, CH, RXBUF>
where where
T: RegisterAccess, T: RegisterAccess,
CH: ChannelTypes,
P: I2sRxPins, P: I2sRxPins,
RX: Rx,
{ {
/// Read I2S. /// Read I2S.
/// Returns [I2sReadDmaTransfer] which represents the in-ptrogress DMA /// Returns [I2sReadDmaTransfer] which represents the in-progress DMA
/// transfer /// transfer
fn read_dma(self, words: RXBUF) -> Result<I2sReadDmaTransfer<T, P, RX, RXBUF>, Error> fn read_dma(self, words: RXBUF) -> Result<I2sReadDmaTransfer<'d, T, P, CH, RXBUF>, Error>
where where
T: RegisterAccess,
P: I2sRxPins,
RX: Rx,
RXBUF: WriteBuffer<Word = u8>; RXBUF: WriteBuffer<Word = u8>;
/// Continously read from I2S. /// Continuously read from I2S.
/// Returns [I2sReadDmaTransfer] which represents the in-ptrogress DMA /// Returns [I2sReadDmaTransfer] which represents the in-progress DMA
/// transfer /// transfer
fn read_dma_circular(self, words: RXBUF) -> Result<I2sReadDmaTransfer<T, P, RX, RXBUF>, Error> fn read_dma_circular(
self,
words: RXBUF,
) -> Result<I2sReadDmaTransfer<'d, T, P, CH, RXBUF>, Error>
where where
T: RegisterAccess,
P: I2sRxPins,
RX: Rx,
RXBUF: WriteBuffer<Word = u8>; RXBUF: WriteBuffer<Word = u8>;
} }
/// Instance of the I2S peripheral driver /// Instance of the I2S peripheral driver
pub struct I2s<'d, I, T, P, TX, RX> pub struct I2s<'d, I, P, CH>
where where
I: Instance<T>, I: Instance,
T: RegisterAccess + Clone,
P: I2sMclkPin, P: I2sMclkPin,
TX: Tx, CH: ChannelTypes,
RX: Rx,
{ {
_peripheral: PeripheralRef<'d, I>, _peripheral: PeripheralRef<'d, I>,
_register_access: T,
_pins: P, _pins: P,
pub i2s_tx: TxCreator<T, TX>, pub i2s_tx: TxCreator<'d, I::Peripheral, CH>,
pub i2s_rx: RxCreator<T, RX>, pub i2s_rx: RxCreator<'d, I::Peripheral, CH>,
} }
impl<'d, I, T, P, TX, RX> I2s<'d, I, T, P, TX, RX> impl<'d, I, P, CH> I2s<'d, I, P, CH>
where where
I: Instance<T>, I: Instance,
T: RegisterAccess + Clone,
P: I2sMclkPin, P: I2sMclkPin,
TX: Tx, CH: ChannelTypes,
RX: Rx,
{ {
fn new_internal<IP>( fn new_internal(
i2s: impl Peripheral<P = I> + 'd, i2s: impl Peripheral<P = I> + 'd,
mut pins: P, mut pins: P,
standard: Standard, standard: Standard,
data_format: DataFormat, data_format: DataFormat,
sample_rate: impl Into<fugit::HertzU32>, sample_rate: impl Into<fugit::HertzU32>,
mut channel: Channel<TX, RX, IP>, mut channel: Channel<'d, CH>,
peripheral_clock_control: &mut PeripheralClockControl, peripheral_clock_control: &mut PeripheralClockControl,
clocks: &Clocks, clocks: &Clocks,
) -> Self ) -> Self {
where
IP: I2sPeripheral,
{
// on ESP32-C3 / ESP32-S3 and later RX and TX are independent and // on ESP32-C3 / ESP32-S3 and later RX and TX are independent and
// could be configured totally independently but for now handle all // could be configured totally independently but for now handle all
// the targets the same and force same configuration for both, TX and RX // the targets the same and force same configuration for both, TX and RX
@ -566,7 +558,6 @@ where
Self { Self {
_peripheral: i2s, _peripheral: i2s,
_register_access: register_access.clone(),
_pins: pins, _pins: pins,
i2s_tx: TxCreator { i2s_tx: TxCreator {
register_access: register_access.clone(), register_access: register_access.clone(),
@ -581,15 +572,12 @@ where
} }
/// Construct a new I2S peripheral driver instance for the first I2S peripheral /// Construct a new I2S peripheral driver instance for the first I2S peripheral
pub trait I2s0New<'d, I, T, P, TX, RX, IP> pub trait I2s0New<'d, I, P, CH>
where where
I: Instance<T>, I: Instance,
T: RegisterAccess + Clone,
P: I2sMclkPin, P: I2sMclkPin,
TX: Tx, CH: ChannelTypes,
RX: Rx, CH::P: I2sPeripheral + I2s0Peripheral,
IP: I2sPeripheral + I2s0Peripheral,
RX: Rx,
{ {
fn new( fn new(
i2s: impl Peripheral<P = I> + 'd, i2s: impl Peripheral<P = I> + 'd,
@ -597,20 +585,18 @@ where
standard: Standard, standard: Standard,
data_format: DataFormat, data_format: DataFormat,
sample_rate: impl Into<fugit::HertzU32>, sample_rate: impl Into<fugit::HertzU32>,
channel: Channel<TX, RX, IP>, channel: Channel<'d, CH>,
peripheral_clock_control: &mut PeripheralClockControl, peripheral_clock_control: &mut PeripheralClockControl,
clocks: &Clocks, clocks: &Clocks,
) -> Self; ) -> Self;
} }
impl<'d, I, T, P, TX, RX, IP> I2s0New<'d, I, T, P, TX, RX, IP> for I2s<'d, I, T, P, TX, RX> impl<'d, I, P, CH> I2s0New<'d, I, P, CH> for I2s<'d, I, P, CH>
where where
I: Instance<T> + I2s0Instance, I: Instance + I2s0Instance,
T: RegisterAccess + Clone,
P: I2sMclkPin, P: I2sMclkPin,
TX: Tx, CH: ChannelTypes,
RX: Rx, CH::P: I2sPeripheral + I2s0Peripheral,
IP: I2sPeripheral + I2s0Peripheral,
{ {
fn new( fn new(
i2s: impl Peripheral<P = I> + 'd, i2s: impl Peripheral<P = I> + 'd,
@ -618,7 +604,7 @@ where
standard: Standard, standard: Standard,
data_format: DataFormat, data_format: DataFormat,
sample_rate: impl Into<fugit::HertzU32>, sample_rate: impl Into<fugit::HertzU32>,
channel: Channel<TX, RX, IP>, channel: Channel<'d, CH>,
peripheral_clock_control: &mut PeripheralClockControl, peripheral_clock_control: &mut PeripheralClockControl,
clocks: &Clocks, clocks: &Clocks,
) -> Self { ) -> Self {
@ -637,15 +623,12 @@ where
/// Construct a new I2S peripheral driver instance for the second I2S peripheral /// Construct a new I2S peripheral driver instance for the second I2S peripheral
#[cfg(any(esp32s3))] #[cfg(any(esp32s3))]
pub trait I2s1New<'d, I, T, P, TX, RX, IP> pub trait I2s1New<'d, I, P, CH>
where where
I: Instance<T>, I: Instance,
T: RegisterAccess + Clone,
P: I2sMclkPin, P: I2sMclkPin,
TX: Tx, CH: ChannelTypes,
RX: Rx, CH::P: I2sPeripheral + I2s1Peripheral,
IP: I2sPeripheral + I2s1Peripheral,
RX: Rx,
{ {
fn new( fn new(
i2s: impl Peripheral<P = I> + 'd, i2s: impl Peripheral<P = I> + 'd,
@ -653,21 +636,19 @@ where
standard: Standard, standard: Standard,
data_format: DataFormat, data_format: DataFormat,
sample_rate: impl Into<fugit::HertzU32>, sample_rate: impl Into<fugit::HertzU32>,
channel: Channel<TX, RX, IP>, channel: Channel<'d, CH>,
peripheral_clock_control: &mut PeripheralClockControl, peripheral_clock_control: &mut PeripheralClockControl,
clocks: &Clocks, clocks: &Clocks,
) -> Self; ) -> Self;
} }
#[cfg(any(esp32s3))] #[cfg(any(esp32s3))]
impl<'d, I, T, P, TX, RX, IP> I2s1New<'d, I, T, P, TX, RX, IP> for I2s<'d, I, T, P, TX, RX> impl<'d, I, P, CH> I2s1New<'d, I, P, CH> for I2s<'d, I, P, CH>
where where
I: Instance<T> + I2s1Instance, I: Instance + I2s1Instance,
T: RegisterAccess + Clone,
P: I2sMclkPin, P: I2sMclkPin,
TX: Tx, CH: ChannelTypes,
RX: Rx, CH::P: I2sPeripheral + I2s1Peripheral,
IP: I2sPeripheral + I2s1Peripheral,
{ {
fn new( fn new(
i2s: impl Peripheral<P = I> + 'd, i2s: impl Peripheral<P = I> + 'd,
@ -675,7 +656,7 @@ where
standard: Standard, standard: Standard,
data_format: DataFormat, data_format: DataFormat,
sample_rate: impl Into<fugit::HertzU32>, sample_rate: impl Into<fugit::HertzU32>,
channel: Channel<TX, RX, IP>, channel: Channel<'d, CH>,
peripheral_clock_control: &mut PeripheralClockControl, peripheral_clock_control: &mut PeripheralClockControl,
clocks: &Clocks, clocks: &Clocks,
) -> Self { ) -> Self {
@ -693,24 +674,24 @@ where
} }
/// I2S TX channel /// I2S TX channel
pub struct I2sTx<T, P, TX> pub struct I2sTx<'d, T, P, CH>
where where
T: RegisterAccess, T: RegisterAccess,
CH: ChannelTypes,
P: I2sTxPins, P: I2sTxPins,
TX: Tx,
{ {
register_access: T, register_access: T,
_pins: P, _pins: P,
tx_channel: TX, tx_channel: CH::Tx<'d>,
} }
impl<T, P, TX> I2sTx<T, P, TX> impl<'d, T, P, CH> I2sTx<'d, T, P, CH>
where where
T: RegisterAccess, T: RegisterAccess,
CH: ChannelTypes,
P: I2sTxPins, P: I2sTxPins,
TX: Tx,
{ {
fn new(mut register_access: T, mut pins: P, tx_channel: TX) -> Self { fn new(mut register_access: T, mut pins: P, tx_channel: CH::Tx<'d>) -> Self {
pins.configure(&mut register_access); pins.configure(&mut register_access);
Self { Self {
@ -751,7 +732,7 @@ where
mut self, mut self,
words: TXBUF, words: TXBUF,
circular: bool, circular: bool,
) -> Result<I2sWriteDmaTransfer<T, P, TX, TXBUF>, Error> ) -> Result<I2sWriteDmaTransfer<'d, T, P, CH, TXBUF>, Error>
where where
TXBUF: ReadBuffer<Word = u8>, TXBUF: ReadBuffer<Word = u8>,
{ {
@ -789,11 +770,11 @@ where
} }
} }
impl<T, P, TX, W> I2sWrite<W> for I2sTx<T, P, TX> impl<'d, T, P, W, CH> I2sWrite<W> for I2sTx<'d, T, P, CH>
where where
T: RegisterAccess, T: RegisterAccess,
CH: ChannelTypes,
P: I2sTxPins, P: I2sTxPins,
TX: Tx,
W: AcceptedWord, W: AcceptedWord,
{ {
fn write(&mut self, words: &[W]) -> Result<(), Error> { fn write(&mut self, words: &[W]) -> Result<(), Error> {
@ -806,20 +787,23 @@ where
} }
} }
impl<'d, T, P, TX, TXBUF> I2sWriteDma<'d, T, P, TX, TXBUF> for I2sTx<T, P, TX> impl<'d, T, P, CH, TXBUF> I2sWriteDma<'d, T, P, CH, TXBUF> for I2sTx<'d, T, P, CH>
where where
T: RegisterAccess, T: RegisterAccess,
CH: ChannelTypes,
P: I2sTxPins, P: I2sTxPins,
TX: Tx,
{ {
fn write_dma(self, words: TXBUF) -> Result<I2sWriteDmaTransfer<T, P, TX, TXBUF>, Error> fn write_dma(self, words: TXBUF) -> Result<I2sWriteDmaTransfer<'d, T, P, CH, TXBUF>, Error>
where where
TXBUF: ReadBuffer<Word = u8>, TXBUF: ReadBuffer<Word = u8>,
{ {
self.start_tx_transfer(words, false) self.start_tx_transfer(words, false)
} }
fn write_dma_circular(self, words: TXBUF) -> Result<I2sWriteDmaTransfer<T, P, TX, TXBUF>, Error> fn write_dma_circular(
self,
words: TXBUF,
) -> Result<I2sWriteDmaTransfer<'d, T, P, CH, TXBUF>, Error>
where where
TXBUF: ReadBuffer<Word = u8>, TXBUF: ReadBuffer<Word = u8>,
{ {
@ -828,24 +812,24 @@ where
} }
/// I2S RX channel /// I2S RX channel
pub struct I2sRx<T, P, RX> pub struct I2sRx<'d, T, P, CH>
where where
T: RegisterAccess, T: RegisterAccess,
CH: ChannelTypes,
P: I2sRxPins, P: I2sRxPins,
RX: Rx,
{ {
register_access: T, register_access: T,
_pins: P, _pins: P,
rx_channel: RX, rx_channel: CH::Rx<'d>,
} }
impl<'d, T, P, RX> I2sRx<T, P, RX> impl<'d, T, P, CH> I2sRx<'d, T, P, CH>
where where
T: RegisterAccess, T: RegisterAccess,
CH: ChannelTypes,
P: I2sRxPins, P: I2sRxPins,
RX: Rx,
{ {
fn new(mut register_access: T, mut pins: P, rx_channel: RX) -> Self { fn new(mut register_access: T, mut pins: P, rx_channel: CH::Rx<'d>) -> Self {
pins.configure(&mut register_access); pins.configure(&mut register_access);
Self { Self {
@ -886,7 +870,7 @@ where
mut self, mut self,
mut words: RXBUF, mut words: RXBUF,
circular: bool, circular: bool,
) -> Result<I2sReadDmaTransfer<T, P, RX, RXBUF>, Error> ) -> Result<I2sReadDmaTransfer<'d, T, P, CH, RXBUF>, Error>
where where
RXBUF: WriteBuffer<Word = u8>, RXBUF: WriteBuffer<Word = u8>,
{ {
@ -931,11 +915,11 @@ where
} }
} }
impl<W, T, P, RX> I2sRead<W> for I2sRx<T, P, RX> impl<'d, W, T, P, CH> I2sRead<W> for I2sRx<'d, T, P, CH>
where where
T: RegisterAccess, T: RegisterAccess,
CH: ChannelTypes,
P: I2sRxPins, P: I2sRxPins,
RX: Rx,
W: AcceptedWord, W: AcceptedWord,
{ {
fn read(&mut self, words: &mut [W]) -> Result<(), Error> { fn read(&mut self, words: &mut [W]) -> Result<(), Error> {
@ -952,20 +936,23 @@ where
} }
} }
impl<'d, T, P, RX, RXBUF> I2sReadDma<'d, T, P, RX, RXBUF> for I2sRx<T, P, RX> impl<'d, T, P, CH, RXBUF> I2sReadDma<'d, T, P, CH, RXBUF> for I2sRx<'d, T, P, CH>
where where
T: RegisterAccess, T: RegisterAccess,
CH: ChannelTypes,
P: I2sRxPins, P: I2sRxPins,
RX: Rx,
{ {
fn read_dma(self, words: RXBUF) -> Result<I2sReadDmaTransfer<T, P, RX, RXBUF>, Error> fn read_dma(self, words: RXBUF) -> Result<I2sReadDmaTransfer<'d, T, P, CH, RXBUF>, Error>
where where
RXBUF: WriteBuffer<Word = u8>, RXBUF: WriteBuffer<Word = u8>,
{ {
self.start_rx_transfer(words, false) self.start_rx_transfer(words, false)
} }
fn read_dma_circular(self, words: RXBUF) -> Result<I2sReadDmaTransfer<T, P, RX, RXBUF>, Error> fn read_dma_circular(
self,
words: RXBUF,
) -> Result<I2sReadDmaTransfer<'d, T, P, CH, RXBUF>, Error>
where where
RXBUF: WriteBuffer<Word = u8>, RXBUF: WriteBuffer<Word = u8>,
{ {
@ -1005,7 +992,7 @@ mod private {
use crate::peripherals::i2s1::RegisterBlock; use crate::peripherals::i2s1::RegisterBlock;
use crate::{ use crate::{
clock::Clocks, clock::Clocks,
dma::{DmaPeripheral, Rx, Tx}, dma::{ChannelTypes, DmaPeripheral},
gpio::{InputSignal, OutputSignal}, gpio::{InputSignal, OutputSignal},
peripherals::I2S0, peripherals::I2S0,
system::Peripheral, system::Peripheral,
@ -1013,21 +1000,21 @@ mod private {
pub trait I2sPins {} pub trait I2sPins {}
pub struct TxCreator<T, TX> pub struct TxCreator<'d, T, CH>
where where
T: RegisterAccess + Clone, T: RegisterAccess + Clone,
TX: Tx, CH: ChannelTypes,
{ {
pub register_access: T, pub register_access: T,
pub tx_channel: TX, pub tx_channel: CH::Tx<'d>,
} }
impl<T, TX> TxCreator<T, TX> impl<'d, T, CH> TxCreator<'d, T, CH>
where where
T: RegisterAccess + Clone, T: RegisterAccess + Clone,
TX: Tx, CH: ChannelTypes,
{ {
pub fn with_pins<P>(self, pins: P) -> I2sTx<T, P, TX> pub fn with_pins<P>(self, pins: P) -> I2sTx<'d, T, P, CH>
where where
P: super::I2sTxPins, P: super::I2sTxPins,
{ {
@ -1035,21 +1022,21 @@ mod private {
} }
} }
pub struct RxCreator<T, RX> pub struct RxCreator<'d, T, CH>
where where
T: RegisterAccess + Clone, T: RegisterAccess + Clone,
RX: Rx, CH: ChannelTypes,
{ {
pub register_access: T, pub register_access: T,
pub rx_channel: RX, pub rx_channel: CH::Rx<'d>,
} }
impl<T, RX> RxCreator<T, RX> impl<'d, T, CH> RxCreator<'d, T, CH>
where where
T: RegisterAccess + Clone, T: RegisterAccess + Clone,
RX: Rx, CH: ChannelTypes,
{ {
pub fn with_pins<P>(self, pins: P) -> I2sRx<T, P, RX> pub fn with_pins<P>(self, pins: P) -> I2sRx<'d, T, P, CH>
where where
P: super::I2sRxPins, P: super::I2sRxPins,
{ {
@ -1061,14 +1048,15 @@ mod private {
pub trait I2s1Instance {} pub trait I2s1Instance {}
pub trait Instance<R> pub trait Instance {
where type Peripheral: RegisterAccess + Clone;
R: RegisterAccess,
{ fn register_access(&self) -> Self::Peripheral;
fn register_access(&self) -> R;
} }
impl Instance<I2sPeripheral0> for I2S0 { impl Instance for I2S0 {
type Peripheral = I2sPeripheral0;
fn register_access(&self) -> I2sPeripheral0 { fn register_access(&self) -> I2sPeripheral0 {
I2sPeripheral0 {} I2sPeripheral0 {}
} }
@ -1077,7 +1065,8 @@ mod private {
impl I2s0Instance for I2S0 {} impl I2s0Instance for I2S0 {}
#[cfg(esp32s3)] #[cfg(esp32s3)]
impl Instance<I2sPeripheral1> for crate::peripherals::I2S1 { impl Instance for crate::peripherals::I2S1 {
type Peripheral = I2sPeripheral1;
fn register_access(&self) -> I2sPeripheral1 { fn register_access(&self) -> I2sPeripheral1 {
I2sPeripheral1 {} I2sPeripheral1 {}
} }

View File

@ -1,3 +1,5 @@
//! Interrupt support
#[cfg(riscv)] #[cfg(riscv)]
pub use riscv::*; pub use riscv::*;
#[cfg(xtensa)] #[cfg(xtensa)]

View File

@ -69,7 +69,8 @@ pub enum InterruptKind {
Edge, Edge,
} }
/// Enumeration of available CPU interrupts. /// Enumeration of available CPU interrupts
///
/// It is possible to create a handler for each of the interrupts. (e.g. /// It is possible to create a handler for each of the interrupts. (e.g.
/// `interrupt3`) /// `interrupt3`)
#[repr(u32)] #[repr(u32)]
@ -531,7 +532,7 @@ pub fn _setup_interrupts() {
} }
} }
/// Disable the given peripheral interrupt. /// Disable the given peripheral interrupt
pub fn disable(_core: Cpu, interrupt: Interrupt) { pub fn disable(_core: Cpu, interrupt: Interrupt) {
unsafe { unsafe {
let interrupt_number = interrupt as isize; let interrupt_number = interrupt as isize;
@ -577,7 +578,7 @@ pub fn get_status(_core: Cpu) -> u128 {
} }
} }
/// Assign a peripheral interrupt to an CPU interrupt. /// Assign a peripheral interrupt to an CPU interrupt
/// ///
/// Great care must be taken when using the `vectored` feature (enabled by /// Great care must be taken when using the `vectored` feature (enabled by
/// default). Avoid interrupts 1 - 15 when interrupt vectoring is enabled. /// default). Avoid interrupts 1 - 15 when interrupt vectoring is enabled.

View File

@ -7,6 +7,7 @@ use crate::{
}; };
/// Enumeration of available CPU interrupts /// Enumeration of available CPU interrupts
///
/// It's possible to create one handler per priority level. (e.g /// It's possible to create one handler per priority level. (e.g
/// `level1_interrupt`) /// `level1_interrupt`)
#[allow(unused)] #[allow(unused)]
@ -47,7 +48,7 @@ pub enum CpuInterrupt {
Interrupt31EdgePriority5, Interrupt31EdgePriority5,
} }
/// Assign a peripheral interrupt to an CPU interrupt. /// Assign a peripheral interrupt to an CPU interrupt
/// ///
/// Great care **must** be taken when using this function with interrupt /// Great care **must** be taken when using this function with interrupt
/// vectoring (enabled by default). Avoid the following CPU interrupts: /// vectoring (enabled by default). Avoid the following CPU interrupts:
@ -73,7 +74,7 @@ pub unsafe fn map(core: Cpu, interrupt: Interrupt, which: CpuInterrupt) {
.write_volatile(cpu_interrupt_number as u32); .write_volatile(cpu_interrupt_number as u32);
} }
/// Disable the given peripheral interrupt. /// Disable the given peripheral interrupt
pub fn disable(core: Cpu, interrupt: Interrupt) { pub fn disable(core: Cpu, interrupt: Interrupt) {
unsafe { unsafe {
let interrupt_number = interrupt as isize; let interrupt_number = interrupt as isize;
@ -264,6 +265,7 @@ mod vectored {
} }
} }
/// Enable the given peripheral interrupt
pub fn enable(interrupt: Interrupt, level: Priority) -> Result<(), Error> { pub fn enable(interrupt: Interrupt, level: Priority) -> Result<(), Error> {
let cpu_interrupt = let cpu_interrupt =
interrupt_level_to_cpu_interrupt(level, chip_specific::interrupt_is_edge(interrupt))?; interrupt_level_to_cpu_interrupt(level, chip_specific::interrupt_is_edge(interrupt))?;

View File

@ -50,8 +50,8 @@ pub use self::delay::Delay;
pub use self::dma::gdma; pub use self::dma::gdma;
#[cfg(pdma)] #[cfg(pdma)]
pub use self::dma::pdma; pub use self::dma::pdma;
#[cfg(any(dport, interrupt_core0, interrupt_core1))] #[cfg(gpio)]
pub use self::interrupt::*; pub use self::gpio::IO;
#[cfg(rmt)] #[cfg(rmt)]
pub use self::pulse_control::PulseControl; pub use self::pulse_control::PulseControl;
#[cfg(rng)] #[cfg(rng)]
@ -63,6 +63,8 @@ pub use self::soc::cpu_control;
#[cfg(efuse)] #[cfg(efuse)]
pub use self::soc::efuse; pub use self::soc::efuse;
pub use self::soc::peripherals; pub use self::soc::peripherals;
#[cfg(psram)]
pub use self::soc::psram;
#[cfg(any(spi0, spi1, spi2, spi3))] #[cfg(any(spi0, spi1, spi2, spi3))]
pub use self::spi::Spi; pub use self::spi::Spi;
#[cfg(any(timg0, timg1))] #[cfg(any(timg0, timg1))]
@ -117,7 +119,6 @@ pub mod rsa;
pub mod rtc_cntl; pub mod rtc_cntl;
#[cfg(sha)] #[cfg(sha)]
pub mod sha; pub mod sha;
pub mod soc;
#[cfg(any(spi0, spi1, spi2, spi3))] #[cfg(any(spi0, spi1, spi2, spi3))]
pub mod spi; pub mod spi;
#[cfg(any(dport, pcr, system))] #[cfg(any(dport, pcr, system))]
@ -141,6 +142,10 @@ pub mod trapframe {
pub use xtensa_lx_rt::exception::Context as TrapFrame; pub use xtensa_lx_rt::exception::Context as TrapFrame;
} }
// The `soc` module contains chip-specific implementation details and should not
// be directly exposed.
mod soc;
#[no_mangle] #[no_mangle]
extern "C" fn EspDefaultHandler(_level: u32, _interrupt: peripherals::Interrupt) {} extern "C" fn EspDefaultHandler(_level: u32, _interrupt: peripherals::Interrupt) {}
@ -148,16 +153,8 @@ extern "C" fn EspDefaultHandler(_level: u32, _interrupt: peripherals::Interrupt)
#[no_mangle] #[no_mangle]
extern "C" fn DefaultHandler() {} extern "C" fn DefaultHandler() {}
#[cfg(esp32c6)] /// Available CPU cores
pub fn disable_apm_filter() { ///
unsafe {
(&*esp32c6::LP_APM::PTR).func_ctrl.write(|w| w.bits(0));
(&*esp32c6::LP_APM0::PTR).func_ctrl.write(|w| w.bits(0));
(&*esp32c6::HP_APM::PTR).func_ctrl.write(|w| w.bits(0));
}
}
/// Enumeration of CPU cores
/// The actual number of available cores depends on the target. /// The actual number of available cores depends on the target.
#[derive(Debug, PartialEq, Eq)] #[derive(Debug, PartialEq, Eq)]
pub enum Cpu { pub enum Cpu {
@ -168,6 +165,7 @@ pub enum Cpu {
AppCpu, AppCpu,
} }
/// Which core the application is currently executing on
pub fn get_core() -> Cpu { pub fn get_core() -> Cpu {
#[cfg(all(xtensa, multi_core))] #[cfg(all(xtensa, multi_core))]
match ((xtensa_lx::get_processor_id() >> 13) & 1) != 0 { match ((xtensa_lx::get_processor_id() >> 13) & 1) != 0 {

View File

@ -1,3 +1,5 @@
//! Pulse Counter peripheral driver
use self::unit::Unit; use self::unit::Unit;
use crate::{ use crate::{
peripheral::{Peripheral, PeripheralRef}, peripheral::{Peripheral, PeripheralRef},

View File

@ -1,3 +1,5 @@
//! Exclusive peripheral access
use core::{ use core::{
marker::PhantomData, marker::PhantomData,
ops::{Deref, DerefMut}, ops::{Deref, DerefMut},
@ -185,6 +187,7 @@ pub(crate) mod sealed {
} }
mod peripheral_macros { mod peripheral_macros {
#[doc(hidden)]
#[macro_export] #[macro_export]
macro_rules! peripherals { macro_rules! peripherals {
($($(#[$cfg:meta])? $name:ident => $from_pac:tt),*$(,)?) => { ($($(#[$cfg:meta])? $name:ident => $from_pac:tt),*$(,)?) => {
@ -247,6 +250,7 @@ mod peripheral_macros {
} }
} }
#[doc(hidden)]
#[macro_export] #[macro_export]
macro_rules! into_ref { macro_rules! into_ref {
($($name:ident),*) => { ($($name:ident),*) => {
@ -257,6 +261,7 @@ mod peripheral_macros {
} }
} }
#[doc(hidden)]
#[macro_export] #[macro_export]
macro_rules! create_peripheral { macro_rules! create_peripheral {
($(#[$cfg:meta])? $name:ident => true) => { ($(#[$cfg:meta])? $name:ident => true) => {

View File

@ -70,7 +70,7 @@ pub use crate::pulse_control::{
}; };
#[cfg(radio)] #[cfg(radio)]
pub use crate::radio::RadioExt as _esp_hal_RadioExt; pub use crate::radio::RadioExt as _esp_hal_RadioExt;
#[cfg(any(esp32, esp32s2))] #[cfg(any(esp32, esp32s2, esp32s3))]
pub use crate::spi::dma::WithDmaSpi3 as _esp_hal_spi_dma_WithDmaSpi3; pub use crate::spi::dma::WithDmaSpi3 as _esp_hal_spi_dma_WithDmaSpi3;
#[cfg(any(spi0, spi1, spi2, spi3))] #[cfg(any(spi0, spi1, spi2, spi3))]
pub use crate::spi::{ pub use crate::spi::{

View File

@ -886,7 +886,7 @@ macro_rules! rmt {
)+ )+
) )
=> { => {
/// RMT peripheral (RMT) /// Remote Control (RMT) peripheral driver
pub struct PulseControl<'d> { pub struct PulseControl<'d> {
/// The underlying register block /// The underlying register block
reg: PeripheralRef<'d, RMT>, reg: PeripheralRef<'d, RMT>,

View File

@ -1,3 +1,5 @@
//! Wireless communication peripheral implementations
pub trait RadioExt { pub trait RadioExt {
type Components; type Components;
@ -68,17 +70,7 @@ impl crate::peripheral::Peripheral for LowRate {
impl crate::peripheral::sealed::Sealed for LowRate {} impl crate::peripheral::sealed::Sealed for LowRate {}
cfg_if::cfg_if! { cfg_if::cfg_if! {
if #[cfg(any(esp32, esp32c2, esp32c3, esp32s3))] { if #[cfg(all(bt, ieee802154, wifi))] {
impl RadioExt for crate::peripherals::RADIO {
type Components = (Wifi, Bluetooth);
fn split(self) -> Self::Components {
unsafe {
(Wifi::steal(), Bluetooth::steal())
}
}
}
} else if #[cfg(esp32c6)] {
impl RadioExt for crate::peripherals::RADIO { impl RadioExt for crate::peripherals::RADIO {
type Components = (Wifi, Bluetooth, LowRate); type Components = (Wifi, Bluetooth, LowRate);
@ -88,7 +80,27 @@ cfg_if::cfg_if! {
} }
} }
} }
} else if #[cfg(esp32s2)] { } else if #[cfg(all(bt, ieee802154))] {
impl RadioExt for crate::peripherals::RADIO {
type Components = (Bluetooth, LowRate);
fn split(self) -> Self::Components {
unsafe {
(Bluetooth::steal(), LowRate::steal())
}
}
}
} else if #[cfg(all(bt, wifi))] {
impl RadioExt for crate::peripherals::RADIO {
type Components = (Wifi, Bluetooth);
fn split(self) -> Self::Components {
unsafe {
(Wifi::steal(), Bluetooth::steal())
}
}
}
} else if #[cfg(wifi)] {
impl RadioExt for crate::peripherals::RADIO { impl RadioExt for crate::peripherals::RADIO {
type Components = Wifi; type Components = Wifi;

View File

@ -1,3 +1,5 @@
//! Hardware and Software Reset
use crate::rtc_cntl::SocResetReason; use crate::rtc_cntl::SocResetReason;
pub enum SleepSource { pub enum SleepSource {

View File

@ -8,11 +8,11 @@
//! //!
//! The ROM provides the following polynomials for each CRC width: //! The ROM provides the following polynomials for each CRC width:
//! //!
//! | CRC Width | Polynomial | //! | CRC Width | Polynomial |
//! | --------- | ---------- | //! | --------- | ----------- |
//! | CRC-8 | 0x07 | //! | CRC-8 | 0x07 |
//! | CRC-16 | 0x1021 | //! | CRC-16 | 0x1021 |
//! | CRC-32 | 0x0411db7 | //! | CRC-32 | 0x04c11db7 |
//! //!
//! The "big-endian" `*_be()` functions are left-shifting algorithms to be used //! The "big-endian" `*_be()` functions are left-shifting algorithms to be used
//! when input and output reflection are **not** needed. If input and output //! when input and output reflection are **not** needed. If input and output
@ -37,26 +37,35 @@
//! <https://reveng.sourceforge.io/crc-catalogue/all.htm> //! <https://reveng.sourceforge.io/crc-catalogue/all.htm>
//! //!
//! CRC-32/ISO-HDLC poly=0x04c11db7 init=0xffffffff refin=true refout=true //! CRC-32/ISO-HDLC poly=0x04c11db7 init=0xffffffff refin=true refout=true
//! xorout=0xffffffff ``` //! xorout=0xffffffff
//!
//! ```
//! let crc = crc32_le(!0xffffffff, &data); //! let crc = crc32_le(!0xffffffff, &data);
//! ``` //! ```
//! //!
//! CRC-32/BZIP2 poly=0x04c11db7 init=0xffffffff refin=false refout=false //! CRC-32/BZIP2 poly=0x04c11db7 init=0xffffffff refin=false refout=false
//! xorout=0xffffffff ``` //! xorout=0xffffffff
//!
//! ```
//! let crc = crc32_be(!0xffffffff, &data); //! let crc = crc32_be(!0xffffffff, &data);
//! ``` //! ```
//! //!
//! CRC-32/MPEG-2 poly=0x04c11db7 init=0xffffffff refin=false refout=false //! CRC-32/MPEG-2 poly=0x04c11db7 init=0xffffffff refin=false refout=false
//! xorout=0x00000000 ``` //! xorout=0x00000000
//!
//! ```
//! let crc = !crc32_be(!0xffffffff, &data); //! let crc = !crc32_be(!0xffffffff, &data);
//! ``` //! ```
//! //!
//! CRC-32/CKSUM poly=0x04c11db7 init=0x00000000 refin=false refout=false //! CRC-32/CKSUM poly=0x04c11db7 init=0x00000000 refin=false refout=false
//! xorout=0xffffffff ``` //! xorout=0xffffffff
//!
//! ```
//! let crc = crc32_be(!0, &data); //! let crc = crc32_be(!0, &data);
//! ``` //! ```
//! //!
//! CRC-16/KERMIT poly=0x1021 init=0x0000 refin=true refout=true xorout=0x0000 //! CRC-16/KERMIT poly=0x1021 init=0x0000 refin=true refout=true xorout=0x0000
//!
//! ``` //! ```
//! let crc = !crc16_le(!0, &data); //! let crc = !crc16_le(!0, &data);
//! ``` //! ```
@ -65,7 +74,7 @@
// needed to access them, they are all referentially transparent, and the size // needed to access them, they are all referentially transparent, and the size
// and alignment of `usize` and `u32` are identical on all ESP32 chips. // and alignment of `usize` and `u32` are identical on all ESP32 chips.
/// Left-shifting CRC-32 with polynomial 0x0411db7 /// Left-shifting CRC-32 with polynomial 0x04c11db7
#[cfg(rom_crc_be)] #[cfg(rom_crc_be)]
#[inline(always)] #[inline(always)]
pub fn crc32_be(crc: u32, buf: &[u8]) -> u32 { pub fn crc32_be(crc: u32, buf: &[u8]) -> u32 {
@ -95,7 +104,7 @@ pub fn crc8_be(crc: u8, buf: &[u8]) -> u8 {
unsafe { esp_rom_crc8_be(crc, buf.as_ptr(), buf.len() as u32) } unsafe { esp_rom_crc8_be(crc, buf.as_ptr(), buf.len() as u32) }
} }
/// Right-shifting CRC-32 with polynomial 0x0411db7 /// Right-shifting CRC-32 with polynomial 0x04c11db7
#[cfg(rom_crc_le)] #[cfg(rom_crc_le)]
#[inline(always)] #[inline(always)]
pub fn crc32_le(crc: u32, buf: &[u8]) -> u32 { pub fn crc32_le(crc: u32, buf: &[u8]) -> u32 {
@ -208,7 +217,7 @@ static CRC8_BE_TABLE: [u8; 256] = [
0xde, 0xd9, 0xd0, 0xd7, 0xc2, 0xc5, 0xcc, 0xcb, 0xe6, 0xe1, 0xe8, 0xef, 0xfa, 0xfd, 0xf4, 0xf3 0xde, 0xd9, 0xd0, 0xd7, 0xc2, 0xc5, 0xcc, 0xcb, 0xe6, 0xe1, 0xe8, 0xef, 0xfa, 0xfd, 0xf4, 0xf3
]; ];
/// Left-shifting CRC-32 with polynomial 0x0411db7 /// Left-shifting CRC-32 with polynomial 0x04c11db7
#[cfg(not(rom_crc_be))] #[cfg(not(rom_crc_be))]
pub fn crc32_be(crc: u32, buf: &[u8]) -> u32 { pub fn crc32_be(crc: u32, buf: &[u8]) -> u32 {
let mut crc = !crc; let mut crc = !crc;
@ -320,7 +329,7 @@ static CRC8_LE_TABLE: [u8; 256] = [
0xb4, 0x25, 0x57, 0xc6, 0xb3, 0x22, 0x50, 0xc1, 0xba, 0x2b, 0x59, 0xc8, 0xbd, 0x2c, 0x5e, 0xcf 0xb4, 0x25, 0x57, 0xc6, 0xb3, 0x22, 0x50, 0xc1, 0xba, 0x2b, 0x59, 0xc8, 0xbd, 0x2c, 0x5e, 0xcf
]; ];
/// Right-shifting CRC-32 with polynomial 0x0411db7 /// Right-shifting CRC-32 with polynomial 0x04c11db7
#[cfg(not(rom_crc_le))] #[cfg(not(rom_crc_le))]
pub fn crc32_le(crc: u32, buf: &[u8]) -> u32 { pub fn crc32_le(crc: u32, buf: &[u8]) -> u32 {
let mut crc = !crc; let mut crc = !crc;

View File

@ -0,0 +1,232 @@
//! MD5 Message-Digest Algorithm
//!
//! # Security Warning
//!
//! MD5 is a **cryptographically broken** message digest. It should **not**
//! be used for data security, for example, to check if data has been
//! intentionally tampered with.
//!
//! However, it is still very useful for purposes of data **integrity**, for
//! example, to check if data has been **accidentally** tampered with, such as
//! detecting data corrupted during transmission in a stream or stored in
//! flash. This is especially important on microcontrollers where the
//! computational efficiency of MD5 is desired.
//!
//! # Compatibility
//!
//! The public API exposed by this module tries to *mimic* the public API
//! offered by the [MD5][1] crate in an effort to act as a drop-in replacement.
//! The actual implementation, however, links to whatever is available in the
//! ROM of the particular ESP32 target. Each chip target may offer a different
//! underlying MD5 implementation with varying functionality.
//!
//! This module offers a least-common-denominator API to stay consistent with
//! all of them. Usage of this module may help make program binaries smaller
//! than it would be if you included an MD5 implementation in your project.
//!
//! # Example
//!
//! To compute a full digest from a single buffer, use the following:
//!
//! ```
//! let d: md5::Digest = md5::compute(&data);
//! writeln!(uart0, "{}", d);
//! ```
//!
//! To compute a digest over multiple buffers:
//!
//! ```
//! let mut ctx = md5::Context::new();
//! ctx.consume(&data0);
//! ctx.consume(&data1);
//! let d: md5::Digest = ctx.compute();
//! writeln!(uart0, "{}", d);
//! ```
//!
//! [1]: <https://crates.io/crates/md5>
#[allow(unused)]
use core::ffi::{c_int, c_uchar, c_void};
use core::{
convert::From,
fmt,
mem::MaybeUninit,
ops::{Deref, DerefMut},
};
// If there is not exactly one of the MD5 variations defined in the device
// toml file then `InternalContext` will be either undefined or multiple
// defined and this module will fail to compile letting you know to fix it
#[cfg(doc)]
struct InternalContext;
#[cfg(rom_md5_bsd)]
#[derive(Clone)]
#[repr(C)]
struct InternalContext {
buf: [u32; 4],
bits: [u32; 2],
_in: [u8; 64],
}
#[cfg(rom_md5_bsd)]
extern "C" {
fn esp_rom_md5_init(context: *mut InternalContext);
fn esp_rom_md5_update(context: *mut InternalContext, buf: *const c_void, len: u32);
fn esp_rom_md5_final(digest: *mut u8, context: *mut InternalContext);
}
#[cfg(rom_md5_mbedtls)]
#[derive(Clone)]
#[repr(C)]
struct InternalContext {
total: [u32; 2],
state: [u32; 4],
buffer: [c_uchar; 64],
}
#[cfg(rom_md5_mbedtls)]
extern "C" {
fn esp_rom_mbedtls_md5_starts_ret(context: *mut InternalContext) -> c_int;
fn esp_rom_mbedtls_md5_update_ret(
context: *mut InternalContext,
buf: *const c_void,
len: u32,
) -> c_int;
fn esp_rom_mbedtls_md5_finish_ret(context: *mut InternalContext, digest: *mut u8) -> c_int;
}
/// MD5 context for an ongoing computation
#[derive(Clone)]
pub struct Context(InternalContext);
impl Context {
/// Create a new MD5 context
#[inline]
pub fn new() -> Self {
let mut ctx = MaybeUninit::<InternalContext>::uninit();
unsafe {
#[cfg(rom_md5_bsd)]
esp_rom_md5_init(ctx.as_mut_ptr());
#[cfg(rom_md5_mbedtls)]
let _ = esp_rom_mbedtls_md5_starts_ret(ctx.as_mut_ptr());
Self(ctx.assume_init())
}
}
/// Feed data to the hasher
#[inline]
pub fn consume<T: AsRef<[u8]>>(&mut self, data: T) {
let data = data.as_ref();
unsafe {
#[cfg(rom_md5_bsd)]
esp_rom_md5_update(
&mut self.0 as *mut _,
data.as_ptr() as *const c_void,
data.len() as u32,
);
#[cfg(rom_md5_mbedtls)]
let _ = esp_rom_mbedtls_md5_update_ret(
&mut self.0 as *mut _,
data.as_ptr() as *const c_void,
data.len() as u32,
);
}
}
/// Finalize and return a digest
#[inline]
pub fn compute(mut self) -> Digest {
let mut digest = MaybeUninit::<[u8; 16]>::uninit();
unsafe {
#[cfg(rom_md5_bsd)]
esp_rom_md5_final(digest.as_mut_ptr() as *mut _, &mut self.0 as *mut _);
#[cfg(rom_md5_mbedtls)]
let _ = esp_rom_mbedtls_md5_finish_ret(
&mut self.0 as *mut _,
digest.as_mut_ptr() as *mut _,
);
Digest(digest.assume_init())
}
}
}
/// Compute a full digest from a single buffer
#[inline]
pub fn compute<T: AsRef<[u8]>>(data: T) -> Digest {
let mut ctx = Context::new();
ctx.consume(data);
ctx.compute()
}
/// 16-byte message digest
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
pub struct Digest(pub [u8; 16]);
impl fmt::LowerHex for Digest {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
for &byte in &self.0 {
write!(f, "{:02x}", byte)?;
}
Ok(())
}
}
impl fmt::UpperHex for Digest {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
for &byte in &self.0 {
write!(f, "{:02X}", byte)?;
}
Ok(())
}
}
impl fmt::Display for Digest {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
<Digest as fmt::LowerHex>::fmt(self, f)
}
}
impl fmt::Debug for Digest {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
<Digest as fmt::LowerHex>::fmt(self, f)
}
}
impl From<Digest> for [u8; 16] {
#[inline]
fn from(digest: Digest) -> Self {
digest.0
}
}
impl From<Context> for Digest {
#[inline]
fn from(context: Context) -> Digest {
context.compute()
}
}
impl Deref for Digest {
type Target = [u8; 16];
#[inline]
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl DerefMut for Digest {
#[inline]
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}

View File

@ -1,6 +1,10 @@
pub use paste::paste; //! ESP ROM libraries
//!
//! Safe abstractions to the additional libraries provided in the ESP's
//! read-only memory.
pub mod crc; pub mod crc;
pub mod md5;
#[allow(unused)] #[allow(unused)]
extern "C" { extern "C" {
@ -16,6 +20,7 @@ extern "C" {
); );
} }
#[doc(hidden)]
#[macro_export] #[macro_export]
macro_rules! regi2c_write { macro_rules! regi2c_write {
( $block: ident, $reg_add: ident, $indata: expr ) => { ( $block: ident, $reg_add: ident, $indata: expr ) => {
@ -29,6 +34,7 @@ macro_rules! regi2c_write {
}; };
} }
#[doc(hidden)]
#[macro_export] #[macro_export]
macro_rules! regi2c_write_mask { macro_rules! regi2c_write_mask {
( $block: ident, $reg_add: ident, $indata: expr ) => { ( $block: ident, $reg_add: ident, $indata: expr ) => {

View File

@ -1,3 +1,5 @@
//! Low-power Management
use embedded_hal::watchdog::{Watchdog, WatchdogDisable, WatchdogEnable}; use embedded_hal::watchdog::{Watchdog, WatchdogDisable, WatchdogEnable};
#[cfg(not(any(esp32c6, esp32h2)))] #[cfg(not(any(esp32c6, esp32h2)))]
use fugit::HertzU32; use fugit::HertzU32;
@ -116,6 +118,7 @@ pub(crate) enum RtcCalSel {
RtcCalInternalOsc = 3, RtcCalInternalOsc = 3,
} }
/// Low-power Management
pub struct Rtc<'d> { pub struct Rtc<'d> {
_inner: PeripheralRef<'d, RtcCntl>, _inner: PeripheralRef<'d, RtcCntl>,
pub rwdt: Rwdt, pub rwdt: Rwdt,

View File

@ -646,6 +646,8 @@ impl RtcClock {
let minor: u8 = Efuse::read_field_le(WAFER_VERSION_MINOR); let minor: u8 = Efuse::read_field_le(WAFER_VERSION_MINOR);
let major: u8 = Efuse::read_field_le(WAFER_VERSION_MAJOR); let major: u8 = Efuse::read_field_le(WAFER_VERSION_MAJOR);
let mut slowclk_cycles = slowclk_cycles;
// The Fosc CLK of calibration circuit is divided by 32 for ECO1. // The Fosc CLK of calibration circuit is divided by 32 for ECO1.
// So we need to divide the calibrate cycles of the FOSC for ECO1 and above // So we need to divide the calibrate cycles of the FOSC for ECO1 and above
// chips by 32 to avoid excessive calibration time.*/ // chips by 32 to avoid excessive calibration time.*/
@ -654,7 +656,7 @@ impl RtcClock {
// formula: MAJOR * 100 + MINOR. (if the result is 1, then version is v0.1) // formula: MAJOR * 100 + MINOR. (if the result is 1, then version is v0.1)
if (major * 100 + minor) > 0 { if (major * 100 + minor) > 0 {
if cal_clk == RtcCalSel::RtcCalRcFast { if cal_clk == RtcCalSel::RtcCalRcFast {
let slowclk_cycles = slowclk_cycles >> 5; slowclk_cycles >>= 5;
} }
} }

View File

@ -1,3 +1,5 @@
//! Secure Hash Algorithm peripheral driver
use core::convert::Infallible; use core::convert::Infallible;
use crate::{ use crate::{

View File

@ -1,3 +1,5 @@
//! Peripheral instance singletons
use esp32 as pac; use esp32 as pac;
// We need to export this for users to use // We need to export this for users to use
pub use pac::Interrupt; pub use pac::Interrupt;

View File

@ -1,5 +1,9 @@
const PSRAM_VADDR: u32 = 0x3F800000; const PSRAM_VADDR: u32 = 0x3F800000;
pub fn psram_vaddr_start() -> usize {
unsafe { PSRAM_VADDR_START as usize }
}
cfg_if::cfg_if! { cfg_if::cfg_if! {
if #[cfg(feature = "psram_2m")] { if #[cfg(feature = "psram_2m")] {
const PSRAM_SIZE: u32 = 2; const PSRAM_SIZE: u32 = 2;

View File

@ -1,3 +1,5 @@
//! Peripheral instance singletons
use esp32c2 as pac; use esp32c2 as pac;
// We need to export this for users to use // We need to export this for users to use
pub use pac::Interrupt; pub use pac::Interrupt;

View File

@ -1,3 +1,5 @@
//! Peripheral instance singletons
use esp32c3 as pac; use esp32c3 as pac;
// We need to export this for users to use // We need to export this for users to use
pub use pac::Interrupt; pub use pac::Interrupt;

View File

@ -1,3 +1,5 @@
//! Peripheral instance singletons
use esp32c6 as pac; use esp32c6 as pac;
// We need to export this for users to use // We need to export this for users to use
pub use pac::Interrupt; pub use pac::Interrupt;

View File

@ -1,3 +1,5 @@
//! Peripheral instance singletons
use esp32h2 as pac; use esp32h2 as pac;
// We need to export this for users to use // We need to export this for users to use
pub use pac::Interrupt; pub use pac::Interrupt;
@ -10,13 +12,13 @@ crate::peripherals! {
APB_SARADC => true, APB_SARADC => true,
ASSIST_DEBUG => true, ASSIST_DEBUG => true,
DMA => true, DMA => true,
// DS => true, DS => true,
// ECC => true, ECC => true,
EFUSE => true, EFUSE => true,
GPIO => true, GPIO => true,
// HMAC => true, HMAC => true,
// HP_APM => true, HP_APM => true,
// HP_SYS => true, HP_SYS => true,
I2C0 => true, I2C0 => true,
I2C1 => true, I2C1 => true,
I2S0 => true, I2S0 => true,
@ -24,20 +26,20 @@ crate::peripherals! {
INTPRI => true, INTPRI => true,
IO_MUX => true, IO_MUX => true,
LEDC => true, LEDC => true,
// LP_ANA => true, LP_ANA => true,
// LP_AON => true, LP_AON => true,
// LP_APM => true, LP_APM => true,
LP_CLKRST => true, LP_CLKRST => true,
// LP_PERI => true, LP_PERI => true,
// LP_TIMER => true, LP_TIMER => true,
LP_WDT => true, LP_WDT => true,
MCPWM0 => true, MCPWM0 => true,
MEM_MONITOR => true, MEM_MONITOR => true,
MODEM_LPCON => true, MODEM_LPCON => true,
MODEM_SYSCON => true, MODEM_SYSCON => true,
// OTP_DEBUG => true, OTP_DEBUG => true,
// PARL_IO => true, PARL_IO => true,
// PAU => true, PAU => true,
PCNT => true, PCNT => true,
PCR => true, PCR => true,
PMU => true, PMU => true,
@ -45,19 +47,19 @@ crate::peripherals! {
RNG => true, RNG => true,
RSA => true, RSA => true,
SHA => true, SHA => true,
// SOC_ETM => true, SOC_ETM => true,
SPI0 => true, SPI0 => true,
SPI1 => true, SPI1 => true,
SPI2 => true, SPI2 => true,
SYSTIMER => true, SYSTIMER => true,
// TEE => true, TEE => true,
TIMG0 => true, TIMG0 => true,
TIMG1 => true, TIMG1 => true,
// TRACE => true, TRACE => true,
// TWAI0 => true, TWAI0 => true,
UART0 => true, UART0 => true,
UART1 => true, UART1 => true,
// UHCI0 => true, UHCI0 => true,
USB_DEVICE => true, USB_DEVICE => true,
RADIO => false, RADIO => false,
} }

View File

@ -1,3 +1,5 @@
//! Peripheral instance singletons
use esp32s2 as pac; use esp32s2 as pac;
// We need to export this for users to use // We need to export this for users to use
pub use pac::Interrupt; pub use pac::Interrupt;

View File

@ -1,5 +1,9 @@
const PSRAM_VADDR: u32 = 0x3f500000; const PSRAM_VADDR: u32 = 0x3f500000;
pub fn psram_vaddr_start() -> usize {
unsafe { PSRAM_VADDR_START as usize }
}
cfg_if::cfg_if! { cfg_if::cfg_if! {
if #[cfg(feature = "psram_2m")] { if #[cfg(feature = "psram_2m")] {
const PSRAM_SIZE: u32 = 2; const PSRAM_SIZE: u32 = 2;

View File

@ -1,3 +1,5 @@
//! Peripheral instance singletons
use esp32s3 as pac; use esp32s3 as pac;
// We need to export this for users to use // We need to export this for users to use
pub use pac::Interrupt; pub use pac::Interrupt;

File diff suppressed because it is too large Load Diff

View File

@ -411,6 +411,7 @@ pub trait HalfDuplexReadWrite {
) -> Result<(), Self::Error>; ) -> Result<(), Self::Error>;
} }
/// SPI peripheral driver
pub struct Spi<'d, T, M> { pub struct Spi<'d, T, M> {
spi: PeripheralRef<'d, T>, spi: PeripheralRef<'d, T>,
_mode: PhantomData<M>, _mode: PhantomData<M>,
@ -752,42 +753,48 @@ pub mod dma {
use crate::dma::Spi3Peripheral; use crate::dma::Spi3Peripheral;
use crate::{ use crate::{
clock::Clocks, clock::Clocks,
dma::{Channel, DmaTransfer, DmaTransferRxTx, Rx, Spi2Peripheral, SpiPeripheral, Tx}, dma::{
Channel,
ChannelTypes,
DmaTransfer,
DmaTransferRxTx,
RxPrivate,
Spi2Peripheral,
SpiPeripheral,
TxPrivate,
},
peripheral::PeripheralRef, peripheral::PeripheralRef,
}; };
pub trait WithDmaSpi2<'d, T, RX, TX, P, M> pub trait WithDmaSpi2<'d, T, C, M>
where where
T: Instance + Spi2Instance, T: Instance + Spi2Instance,
TX: Tx, C: ChannelTypes,
RX: Rx, C::P: SpiPeripheral,
P: SpiPeripheral,
M: DuplexMode, M: DuplexMode,
{ {
fn with_dma(self, channel: Channel<TX, RX, P>) -> SpiDma<'d, T, TX, RX, P, M>; fn with_dma(self, channel: Channel<'d, C>) -> SpiDma<'d, T, C, M>;
} }
#[cfg(any(esp32, esp32s2, esp32s3))] #[cfg(any(esp32, esp32s2, esp32s3))]
pub trait WithDmaSpi3<'d, T, RX, TX, P, M> pub trait WithDmaSpi3<'d, T, C, M>
where where
T: Instance + Spi3Instance, T: Instance + Spi3Instance,
TX: Tx, C: ChannelTypes,
RX: Rx, C::P: SpiPeripheral,
P: SpiPeripheral,
M: DuplexMode, M: DuplexMode,
{ {
fn with_dma(self, channel: Channel<TX, RX, P>) -> SpiDma<'d, T, TX, RX, P, M>; fn with_dma(self, channel: Channel<'d, C>) -> SpiDma<'d, T, C, M>;
} }
impl<'d, T, RX, TX, P, M> WithDmaSpi2<'d, T, RX, TX, P, M> for Spi<'d, T, M> impl<'d, T, C, M> WithDmaSpi2<'d, T, C, M> for Spi<'d, T, M>
where where
T: Instance + Spi2Instance, T: Instance + Spi2Instance,
TX: Tx, C: ChannelTypes,
RX: Rx, C::P: SpiPeripheral + Spi2Peripheral,
P: SpiPeripheral + Spi2Peripheral,
M: DuplexMode, M: DuplexMode,
{ {
fn with_dma(self, mut channel: Channel<TX, RX, P>) -> SpiDma<'d, T, TX, RX, P, M> { fn with_dma(self, mut channel: Channel<'d, C>) -> SpiDma<'d, T, C, M> {
channel.tx.init_channel(); // no need to call this for both, TX and RX channel.tx.init_channel(); // no need to call this for both, TX and RX
SpiDma { SpiDma {
@ -799,51 +806,47 @@ pub mod dma {
} }
#[cfg(any(esp32, esp32s2, esp32s3))] #[cfg(any(esp32, esp32s2, esp32s3))]
impl<'d, T, RX, TX, P, M> WithDmaSpi3<'d, T, RX, TX, P, M> for Spi<'d, T, M> impl<'d, T, C, M> WithDmaSpi3<'d, T, C, M> for Spi<'d, T, M>
where where
T: Instance + Spi3Instance, T: Instance + Spi3Instance,
TX: Tx, C: ChannelTypes,
RX: Rx, C::P: SpiPeripheral + Spi3Peripheral,
P: SpiPeripheral + Spi3Peripheral,
M: DuplexMode, M: DuplexMode,
{ {
fn with_dma(self, mut channel: Channel<TX, RX, P>) -> SpiDma<'d, T, TX, RX, P, M> { fn with_dma(self, mut channel: Channel<'d, C>) -> SpiDma<'d, T, C, M> {
channel.tx.init_channel(); // no need to call this for both, TX and RX channel.tx.init_channel(); // no need to call this for both, TX and RX
SpiDma { SpiDma {
spi: self.spi, spi: self.spi,
channel, channel,
_mode: PhantomData::default(), _mode: PhantomData,
} }
} }
} }
/// An in-progress DMA transfer /// An in-progress DMA transfer
pub struct SpiDmaTransferRxTx<'d, T, TX, RX, P, RBUFFER, TBUFFER, M> pub struct SpiDmaTransferRxTx<'d, T, C, RBUFFER, TBUFFER, M>
where where
T: InstanceDma<TX, RX>, T: InstanceDma<C::Tx<'d>, C::Rx<'d>>,
TX: Tx, C: ChannelTypes,
RX: Rx, C::P: SpiPeripheral,
P: SpiPeripheral,
M: DuplexMode, M: DuplexMode,
{ {
spi_dma: SpiDma<'d, T, TX, RX, P, M>, spi_dma: SpiDma<'d, T, C, M>,
rbuffer: RBUFFER, rbuffer: RBUFFER,
tbuffer: TBUFFER, tbuffer: TBUFFER,
} }
impl<'d, T, TX, RX, P, RXBUF, TXBUF, M> impl<'d, T, C, RXBUF, TXBUF, M> DmaTransferRxTx<RXBUF, TXBUF, SpiDma<'d, T, C, M>>
DmaTransferRxTx<RXBUF, TXBUF, SpiDma<'d, T, TX, RX, P, M>> for SpiDmaTransferRxTx<'d, T, C, RXBUF, TXBUF, M>
for SpiDmaTransferRxTx<'d, T, TX, RX, P, RXBUF, TXBUF, M>
where where
T: InstanceDma<TX, RX>, T: InstanceDma<C::Tx<'d>, C::Rx<'d>>,
TX: Tx, C: ChannelTypes,
RX: Rx, C::P: SpiPeripheral,
P: SpiPeripheral,
M: DuplexMode, M: DuplexMode,
{ {
/// Wait for the DMA transfer to complete and return the buffers and the /// Wait for the DMA transfer to complete and return the buffers and the
/// SPI instance. /// SPI instance.
fn wait(mut self) -> (RXBUF, TXBUF, SpiDma<'d, T, TX, RX, P, M>) { fn wait(mut self) -> (RXBUF, TXBUF, SpiDma<'d, T, C, M>) {
self.spi_dma.spi.flush().ok(); // waiting for the DMA transfer is not enough self.spi_dma.spi.flush().ok(); // waiting for the DMA transfer is not enough
// `DmaTransfer` needs to have a `Drop` implementation, because we accept // `DmaTransfer` needs to have a `Drop` implementation, because we accept
@ -869,13 +872,11 @@ pub mod dma {
} }
} }
impl<'d, T, TX, RX, P, RXBUF, TXBUF, M> Drop impl<'d, T, C, RXBUF, TXBUF, M> Drop for SpiDmaTransferRxTx<'d, T, C, RXBUF, TXBUF, M>
for SpiDmaTransferRxTx<'d, T, TX, RX, P, RXBUF, TXBUF, M>
where where
T: InstanceDma<TX, RX>, T: InstanceDma<C::Tx<'d>, C::Rx<'d>>,
TX: Tx, C: ChannelTypes,
RX: Rx, C::P: SpiPeripheral,
P: SpiPeripheral,
M: DuplexMode, M: DuplexMode,
{ {
fn drop(&mut self) { fn drop(&mut self) {
@ -884,30 +885,28 @@ pub mod dma {
} }
/// An in-progress DMA transfer. /// An in-progress DMA transfer.
pub struct SpiDmaTransfer<'d, T, TX, RX, P, BUFFER, M> pub struct SpiDmaTransfer<'d, T, C, BUFFER, M>
where where
T: InstanceDma<TX, RX>, T: InstanceDma<C::Tx<'d>, C::Rx<'d>>,
TX: Tx, C: ChannelTypes,
RX: Rx, C::P: SpiPeripheral,
P: SpiPeripheral,
M: DuplexMode, M: DuplexMode,
{ {
spi_dma: SpiDma<'d, T, TX, RX, P, M>, spi_dma: SpiDma<'d, T, C, M>,
buffer: BUFFER, buffer: BUFFER,
} }
impl<'d, T, TX, RX, P, BUFFER, M> DmaTransfer<BUFFER, SpiDma<'d, T, TX, RX, P, M>> impl<'d, T, C, BUFFER, M> DmaTransfer<BUFFER, SpiDma<'d, T, C, M>>
for SpiDmaTransfer<'d, T, TX, RX, P, BUFFER, M> for SpiDmaTransfer<'d, T, C, BUFFER, M>
where where
T: InstanceDma<TX, RX>, T: InstanceDma<C::Tx<'d>, C::Rx<'d>>,
TX: Tx, C: ChannelTypes,
RX: Rx, C::P: SpiPeripheral,
P: SpiPeripheral,
M: DuplexMode, M: DuplexMode,
{ {
/// Wait for the DMA transfer to complete and return the buffers and the /// Wait for the DMA transfer to complete and return the buffers and the
/// SPI instance. /// SPI instance.
fn wait(mut self) -> (BUFFER, SpiDma<'d, T, TX, RX, P, M>) { fn wait(mut self) -> (BUFFER, SpiDma<'d, T, C, M>) {
self.spi_dma.spi.flush().ok(); // waiting for the DMA transfer is not enough self.spi_dma.spi.flush().ok(); // waiting for the DMA transfer is not enough
// `DmaTransfer` needs to have a `Drop` implementation, because we accept // `DmaTransfer` needs to have a `Drop` implementation, because we accept
@ -932,12 +931,11 @@ pub mod dma {
} }
} }
impl<'d, T, TX, RX, P, BUFFER, M> Drop for SpiDmaTransfer<'d, T, TX, RX, P, BUFFER, M> impl<'d, T, C, BUFFER, M> Drop for SpiDmaTransfer<'d, T, C, BUFFER, M>
where where
T: InstanceDma<TX, RX>, T: InstanceDma<C::Tx<'d>, C::Rx<'d>>,
TX: Tx, C: ChannelTypes,
RX: Rx, C::P: SpiPeripheral,
P: SpiPeripheral,
M: DuplexMode, M: DuplexMode,
{ {
fn drop(&mut self) { fn drop(&mut self) {
@ -946,24 +944,22 @@ pub mod dma {
} }
/// A DMA capable SPI instance. /// A DMA capable SPI instance.
pub struct SpiDma<'d, T, TX, RX, P, M> pub struct SpiDma<'d, T, C, M>
where where
TX: Tx, C: ChannelTypes,
RX: Rx, C::P: SpiPeripheral,
P: SpiPeripheral,
M: DuplexMode, M: DuplexMode,
{ {
pub(crate) spi: PeripheralRef<'d, T>, pub(crate) spi: PeripheralRef<'d, T>,
pub(crate) channel: Channel<TX, RX, P>, pub(crate) channel: Channel<'d, C>,
_mode: PhantomData<M>, _mode: PhantomData<M>,
} }
impl<'d, T, TX, RX, P, M> SpiDma<'d, T, TX, RX, P, M> impl<'d, T, C, M> SpiDma<'d, T, C, M>
where where
T: InstanceDma<TX, RX>, T: InstanceDma<C::Tx<'d>, C::Rx<'d>>,
TX: Tx, C: ChannelTypes,
RX: Rx, C::P: SpiPeripheral,
P: SpiPeripheral,
M: DuplexMode, M: DuplexMode,
{ {
pub fn change_bus_frequency(&mut self, frequency: HertzU32, clocks: &Clocks) { pub fn change_bus_frequency(&mut self, frequency: HertzU32, clocks: &Clocks) {
@ -971,12 +967,11 @@ pub mod dma {
} }
} }
impl<'d, T, TX, RX, P, M> SpiDma<'d, T, TX, RX, P, M> impl<'d, T, C, M> SpiDma<'d, T, C, M>
where where
T: InstanceDma<TX, RX>, T: InstanceDma<C::Tx<'d>, C::Rx<'d>>,
TX: Tx, C: ChannelTypes,
RX: Rx, C::P: SpiPeripheral,
P: SpiPeripheral,
M: IsFullDuplex, M: IsFullDuplex,
{ {
/// Perform a DMA write. /// Perform a DMA write.
@ -987,7 +982,7 @@ pub mod dma {
pub fn dma_write<TXBUF>( pub fn dma_write<TXBUF>(
mut self, mut self,
words: TXBUF, words: TXBUF,
) -> Result<SpiDmaTransfer<'d, T, TX, RX, P, TXBUF, M>, super::Error> ) -> Result<SpiDmaTransfer<'d, T, C, TXBUF, M>, super::Error>
where where
TXBUF: ReadBuffer<Word = u8>, TXBUF: ReadBuffer<Word = u8>,
{ {
@ -1013,7 +1008,7 @@ pub mod dma {
pub fn dma_read<RXBUF>( pub fn dma_read<RXBUF>(
mut self, mut self,
mut words: RXBUF, mut words: RXBUF,
) -> Result<SpiDmaTransfer<'d, T, TX, RX, P, RXBUF, M>, super::Error> ) -> Result<SpiDmaTransfer<'d, T, C, RXBUF, M>, super::Error>
where where
RXBUF: WriteBuffer<Word = u8>, RXBUF: WriteBuffer<Word = u8>,
{ {
@ -1040,7 +1035,7 @@ pub mod dma {
mut self, mut self,
words: TXBUF, words: TXBUF,
mut read_buffer: RXBUF, mut read_buffer: RXBUF,
) -> Result<SpiDmaTransferRxTx<'d, T, TX, RX, P, RXBUF, TXBUF, M>, super::Error> ) -> Result<SpiDmaTransferRxTx<'d, T, C, RXBUF, TXBUF, M>, super::Error>
where where
TXBUF: ReadBuffer<Word = u8>, TXBUF: ReadBuffer<Word = u8>,
RXBUF: WriteBuffer<Word = u8>, RXBUF: WriteBuffer<Word = u8>,
@ -1068,12 +1063,11 @@ pub mod dma {
} }
} }
impl<'d, T, TX, RX, P, M> SpiDma<'d, T, TX, RX, P, M> impl<'d, T, C, M> SpiDma<'d, T, C, M>
where where
T: InstanceDma<TX, RX>, T: InstanceDma<C::Tx<'d>, C::Rx<'d>>,
TX: Tx, C: ChannelTypes,
RX: Rx, C::P: SpiPeripheral,
P: SpiPeripheral,
M: IsHalfDuplex, M: IsHalfDuplex,
{ {
pub fn read<RXBUF>( pub fn read<RXBUF>(
@ -1083,7 +1077,7 @@ pub mod dma {
address: Address, address: Address,
dummy: u8, dummy: u8,
mut buffer: RXBUF, mut buffer: RXBUF,
) -> Result<SpiDmaTransfer<'d, T, TX, RX, P, RXBUF, M>, super::Error> ) -> Result<SpiDmaTransfer<'d, T, C, RXBUF, M>, super::Error>
where where
RXBUF: WriteBuffer<Word = u8>, RXBUF: WriteBuffer<Word = u8>,
{ {
@ -1156,7 +1150,7 @@ pub mod dma {
address: Address, address: Address,
dummy: u8, dummy: u8,
buffer: TXBUF, buffer: TXBUF,
) -> Result<SpiDmaTransfer<'d, T, TX, RX, P, TXBUF, M>, super::Error> ) -> Result<SpiDmaTransfer<'d, T, C, TXBUF, M>, super::Error>
where where
TXBUF: ReadBuffer<Word = u8>, TXBUF: ReadBuffer<Word = u8>,
{ {
@ -1223,12 +1217,11 @@ pub mod dma {
} }
} }
impl<'d, T, TX, RX, P, M> embedded_hal::blocking::spi::Transfer<u8> for SpiDma<'d, T, TX, RX, P, M> impl<'d, T, C, M> embedded_hal::blocking::spi::Transfer<u8> for SpiDma<'d, T, C, M>
where where
T: InstanceDma<TX, RX>, T: InstanceDma<C::Tx<'d>, C::Rx<'d>>,
TX: Tx, C: ChannelTypes,
RX: Rx, C::P: SpiPeripheral,
P: SpiPeripheral,
M: IsFullDuplex, M: IsFullDuplex,
{ {
type Error = super::Error; type Error = super::Error;
@ -1239,12 +1232,11 @@ pub mod dma {
} }
} }
impl<'d, T, TX, RX, P, M> embedded_hal::blocking::spi::Write<u8> for SpiDma<'d, T, TX, RX, P, M> impl<'d, T, C, M> embedded_hal::blocking::spi::Write<u8> for SpiDma<'d, T, C, M>
where where
T: InstanceDma<TX, RX>, T: InstanceDma<C::Tx<'d>, C::Rx<'d>>,
TX: Tx, C: ChannelTypes,
RX: Rx, C::P: SpiPeripheral,
P: SpiPeripheral,
M: IsFullDuplex, M: IsFullDuplex,
{ {
type Error = super::Error; type Error = super::Error;
@ -1260,12 +1252,11 @@ pub mod dma {
mod asynch { mod asynch {
use super::*; use super::*;
impl<'d, T, TX, RX, P, M> embedded_hal_async::spi::SpiBusWrite for SpiDma<'d, T, TX, RX, P, M> impl<'d, T, C, M> embedded_hal_async::spi::SpiBusWrite for SpiDma<'d, T, C, M>
where where
T: InstanceDma<TX, RX>, T: InstanceDma<C::Tx<'d>, C::Rx<'d>>,
TX: Tx, C: ChannelTypes,
RX: Rx, C::P: SpiPeripheral,
P: SpiPeripheral,
M: IsFullDuplex, M: IsFullDuplex,
{ {
async fn write(&mut self, words: &[u8]) -> Result<(), Self::Error> { async fn write(&mut self, words: &[u8]) -> Result<(), Self::Error> {
@ -1287,12 +1278,11 @@ pub mod dma {
} }
} }
impl<'d, T, TX, RX, P, M> embedded_hal_async::spi::SpiBusFlush for SpiDma<'d, T, TX, RX, P, M> impl<'d, T, C, M> embedded_hal_async::spi::SpiBusFlush for SpiDma<'d, T, C, M>
where where
T: InstanceDma<TX, RX>, T: InstanceDma<C::Tx<'d>, C::Rx<'d>>,
TX: Tx, C: ChannelTypes,
RX: Rx, C::P: SpiPeripheral,
P: SpiPeripheral,
M: IsFullDuplex, M: IsFullDuplex,
{ {
async fn flush(&mut self) -> Result<(), Self::Error> { async fn flush(&mut self) -> Result<(), Self::Error> {
@ -1301,12 +1291,11 @@ pub mod dma {
} }
} }
impl<'d, T, TX, RX, P, M> embedded_hal_async::spi::SpiBusRead for SpiDma<'d, T, TX, RX, P, M> impl<'d, T, C, M> embedded_hal_async::spi::SpiBusRead for SpiDma<'d, T, C, M>
where where
T: InstanceDma<TX, RX>, T: InstanceDma<C::Tx<'d>, C::Rx<'d>>,
TX: Tx, C: ChannelTypes,
RX: Rx, C::P: SpiPeripheral,
P: SpiPeripheral,
M: IsFullDuplex, M: IsFullDuplex,
{ {
async fn read(&mut self, words: &mut [u8]) -> Result<(), Self::Error> { async fn read(&mut self, words: &mut [u8]) -> Result<(), Self::Error> {
@ -1322,12 +1311,11 @@ pub mod dma {
} }
} }
impl<'d, T, TX, RX, P, M> embedded_hal_async::spi::SpiBus for SpiDma<'d, T, TX, RX, P, M> impl<'d, T, C, M> embedded_hal_async::spi::SpiBus for SpiDma<'d, T, C, M>
where where
T: InstanceDma<TX, RX>, T: InstanceDma<C::Tx<'d>, C::Rx<'d>>,
TX: Tx, C: ChannelTypes,
RX: Rx, C::P: SpiPeripheral,
P: SpiPeripheral,
M: IsFullDuplex, M: IsFullDuplex,
{ {
async fn transfer<'a>( async fn transfer<'a>(
@ -1406,28 +1394,23 @@ pub mod dma {
use embedded_hal_1::spi::{SpiBus, SpiBusFlush, SpiBusRead, SpiBusWrite}; use embedded_hal_1::spi::{SpiBus, SpiBusFlush, SpiBusRead, SpiBusWrite};
use super::{super::InstanceDma, SpiDma, SpiPeripheral}; use super::{super::InstanceDma, SpiDma, SpiPeripheral};
use crate::{ use crate::{dma::ChannelTypes, spi::IsFullDuplex};
dma::{Rx, Tx},
spi::IsFullDuplex,
};
impl<'d, T, TX, RX, P, M> embedded_hal_1::spi::ErrorType for SpiDma<'d, T, TX, RX, P, M> impl<'d, T, C, M> embedded_hal_1::spi::ErrorType for SpiDma<'d, T, C, M>
where where
T: InstanceDma<TX, RX>, T: InstanceDma<C::Tx<'d>, C::Rx<'d>>,
TX: Tx, C: ChannelTypes,
RX: Rx, C::P: SpiPeripheral,
P: SpiPeripheral,
M: IsFullDuplex, M: IsFullDuplex,
{ {
type Error = super::super::Error; type Error = super::super::Error;
} }
impl<'d, T, TX, RX, P, M> SpiBusWrite for SpiDma<'d, T, TX, RX, P, M> impl<'d, T, C, M> SpiBusWrite for SpiDma<'d, T, C, M>
where where
T: InstanceDma<TX, RX>, T: InstanceDma<C::Tx<'d>, C::Rx<'d>>,
TX: Tx, C: ChannelTypes,
RX: Rx, C::P: SpiPeripheral,
P: SpiPeripheral,
M: IsFullDuplex, M: IsFullDuplex,
{ {
/// See also: [`write_bytes`]. /// See also: [`write_bytes`].
@ -1437,12 +1420,11 @@ pub mod dma {
} }
} }
impl<'d, T, TX, RX, P, M> SpiBusRead for SpiDma<'d, T, TX, RX, P, M> impl<'d, T, C, M> SpiBusRead for SpiDma<'d, T, C, M>
where where
T: InstanceDma<TX, RX>, T: InstanceDma<C::Tx<'d>, C::Rx<'d>>,
TX: Tx, C: ChannelTypes,
RX: Rx, C::P: SpiPeripheral,
P: SpiPeripheral,
M: IsFullDuplex, M: IsFullDuplex,
{ {
fn read(&mut self, words: &mut [u8]) -> Result<(), Self::Error> { fn read(&mut self, words: &mut [u8]) -> Result<(), Self::Error> {
@ -1452,12 +1434,11 @@ pub mod dma {
} }
} }
impl<'d, T, TX, RX, P, M> SpiBus for SpiDma<'d, T, TX, RX, P, M> impl<'d, T, C, M> SpiBus for SpiDma<'d, T, C, M>
where where
T: InstanceDma<TX, RX>, T: InstanceDma<C::Tx<'d>, C::Rx<'d>>,
TX: Tx, C: ChannelTypes,
RX: Rx, C::P: SpiPeripheral,
P: SpiPeripheral,
M: IsFullDuplex, M: IsFullDuplex,
{ {
/// Write out data from `write`, read response into `read`. /// Write out data from `write`, read response into `read`.
@ -1490,12 +1471,11 @@ pub mod dma {
} }
} }
impl<'d, T, TX, RX, P, M> SpiBusFlush for SpiDma<'d, T, TX, RX, P, M> impl<'d, T, C, M> SpiBusFlush for SpiDma<'d, T, C, M>
where where
T: InstanceDma<TX, RX>, T: InstanceDma<C::Tx<'d>, C::Rx<'d>>,
TX: Tx, C: ChannelTypes,
RX: Rx, C::P: SpiPeripheral,
P: SpiPeripheral,
M: IsFullDuplex, M: IsFullDuplex,
{ {
fn flush(&mut self) -> Result<(), Self::Error> { fn flush(&mut self) -> Result<(), Self::Error> {

View File

@ -1,4 +1,4 @@
//! System //! System Control
//! //!
//! The SYSTEM/DPORT peripheral needs to be split into several logical parts. //! The SYSTEM/DPORT peripheral needs to be split into several logical parts.
//! //!

View File

@ -1,3 +1,5 @@
//! System Timer peripheral driver
use core::{intrinsics::transmute, marker::PhantomData}; use core::{intrinsics::transmute, marker::PhantomData};
use fugit::MillisDurationU32; use fugit::MillisDurationU32;

View File

@ -188,13 +188,12 @@ where
} }
} }
/// General-purpose timer /// General-purpose Timer driver
pub struct Timer<T> { pub struct Timer<T> {
timg: T, timg: T,
apb_clk_freq: HertzU32, apb_clk_freq: HertzU32,
} }
/// Timer driver
impl<T> Timer<T> impl<T> Timer<T>
where where
T: Instance, T: Instance,

View File

@ -19,7 +19,10 @@ const UART_FIFO_SIZE: u16 = 128;
/// Custom serial error type /// Custom serial error type
#[derive(Debug)] #[derive(Debug)]
pub enum Error {} pub enum Error {
#[cfg(feature = "async")]
ReadBufferFull,
}
/// UART configuration /// UART configuration
pub mod config { pub mod config {
@ -994,11 +997,15 @@ mod asynch {
use core::task::Poll; use core::task::Poll;
use cfg_if::cfg_if; use cfg_if::cfg_if;
use embassy_futures::select::select;
use embassy_sync::waitqueue::AtomicWaker; use embassy_sync::waitqueue::AtomicWaker;
use procmacros::interrupt; use procmacros::interrupt;
use super::{Error, Instance}; use super::{Error, Instance};
use crate::{uart::UART_FIFO_SIZE, Uart}; use crate::{
uart::{RegisterBlock, UART_FIFO_SIZE},
Uart,
};
cfg_if! { cfg_if! {
if #[cfg(all(uart0, uart1, uart2))] { if #[cfg(all(uart0, uart1, uart2))] {
@ -1016,6 +1023,8 @@ mod asynch {
pub(crate) enum Event { pub(crate) enum Event {
TxDone, TxDone,
TxFiFoEmpty, TxFiFoEmpty,
RxFifoFull,
RxCmdCharDetected,
} }
pub(crate) struct UartFuture<'a, T: Instance> { pub(crate) struct UartFuture<'a, T: Instance> {
@ -1034,6 +1043,14 @@ mod asynch {
.register_block() .register_block()
.int_ena .int_ena
.modify(|_, w| w.txfifo_empty_int_ena().set_bit()), .modify(|_, w| w.txfifo_empty_int_ena().set_bit()),
Event::RxFifoFull => instance
.register_block()
.int_ena
.modify(|_, w| w.rxfifo_full_int_ena().set_bit()),
Event::RxCmdCharDetected => instance
.register_block()
.int_ena
.modify(|_, w| w.at_cmd_char_det_int_ena().set_bit()),
} }
Self { event, instance } Self { event, instance }
@ -1055,6 +1072,20 @@ mod asynch {
.read() .read()
.txfifo_empty_int_ena() .txfifo_empty_int_ena()
.bit_is_clear(), .bit_is_clear(),
Event::RxFifoFull => self
.instance
.register_block()
.int_ena
.read()
.rxfifo_full_int_ena()
.bit_is_clear(),
Event::RxCmdCharDetected => self
.instance
.register_block()
.int_ena
.read()
.at_cmd_char_det_int_ena()
.bit_is_clear(),
} }
} }
} }
@ -1079,11 +1110,42 @@ mod asynch {
where where
T: Instance, T: Instance,
{ {
async fn write(&mut self, words: &[u8]) -> Result<(), Error> { pub async fn read(&mut self, buf: &mut [u8]) -> Result<usize, Error> {
for chunk in words.chunks(UART_FIFO_SIZE as usize) { let mut read_bytes = 0;
for &byte in chunk {
self.write_byte(byte).unwrap() // should never fail select(
UartFuture::new(Event::RxCmdCharDetected, self.inner()),
UartFuture::new(Event::RxFifoFull, self.inner()),
)
.await;
while let Ok(byte) = self.read_byte() {
if read_bytes < buf.len() {
buf[read_bytes] = byte;
read_bytes += 1;
} else {
return Err(Error::ReadBufferFull);
} }
}
Ok(read_bytes)
}
async fn write(&mut self, words: &[u8]) -> Result<(), Error> {
let mut offset: usize = 0;
loop {
let mut next_offset =
offset + (UART_FIFO_SIZE - self.uart.get_tx_fifo_count()) as usize;
if next_offset > words.len() {
next_offset = words.len();
}
for &byte in &words[offset..next_offset] {
self.write_byte(byte).unwrap(); // should never fail
}
if next_offset == words.len() {
break;
}
offset = next_offset;
UartFuture::new(Event::TxFiFoEmpty, self.inner()).await; UartFuture::new(Event::TxFiFoEmpty, self.inner()).await;
} }
Ok(()) Ok(())
@ -1111,42 +1173,63 @@ mod asynch {
} }
} }
fn intr_handler(uart: &RegisterBlock) -> bool {
let int_ena_val = uart.int_ena.read();
let int_raw_val = uart.int_raw.read();
if int_ena_val.txfifo_empty_int_ena().bit_is_set()
&& int_raw_val.txfifo_empty_int_raw().bit_is_set()
{
uart.int_ena.write(|w| w.txfifo_empty_int_ena().clear_bit());
return true;
}
if int_ena_val.tx_done_int_ena().bit_is_set() && int_raw_val.tx_done_int_raw().bit_is_set()
{
uart.int_ena.write(|w| w.tx_done_int_ena().clear_bit());
return true;
}
if int_ena_val.at_cmd_char_det_int_ena().bit_is_set()
&& int_raw_val.at_cmd_char_det_int_raw().bit_is_set()
{
uart.int_clr
.write(|w| w.at_cmd_char_det_int_clr().set_bit());
uart.int_ena
.write(|w| w.at_cmd_char_det_int_ena().clear_bit());
return true;
}
if int_ena_val.rxfifo_full_int_ena().bit_is_set()
&& int_raw_val.rxfifo_full_int_raw().bit_is_set()
{
uart.int_clr.write(|w| w.rxfifo_full_int_clr().set_bit());
uart.int_ena.write(|w| w.rxfifo_full_int_ena().clear_bit());
return true;
}
false
}
#[cfg(uart0)] #[cfg(uart0)]
#[interrupt] #[interrupt]
fn UART0() { fn UART0() {
let uart = unsafe { &*crate::peripherals::UART0::ptr() }; let uart = unsafe { &*crate::peripherals::UART0::ptr() };
uart.int_ena.modify(|_, w| { if intr_handler(uart) {
w.txfifo_empty_int_ena() WAKERS[0].wake();
.clear_bit() }
.tx_done_int_ena()
.clear_bit()
});
WAKERS[0].wake();
} }
#[cfg(uart1)] #[cfg(uart1)]
#[interrupt] #[interrupt]
fn UART1() { fn UART1() {
let uart = unsafe { &*crate::peripherals::UART1::ptr() }; let uart = unsafe { &*crate::peripherals::UART1::ptr() };
uart.int_ena.modify(|_, w| { if intr_handler(uart) {
w.txfifo_empty_int_ena() WAKERS[1].wake();
.clear_bit() }
.tx_done_int_ena()
.clear_bit()
});
WAKERS[1].wake();
} }
#[cfg(uart2)] #[cfg(uart2)]
#[interrupt] #[interrupt]
fn UART2() { fn UART2() {
let uart = unsafe { &*crate::peripherals::UART2::ptr() }; let uart = unsafe { &*crate::peripherals::UART2::ptr() };
uart.int_ena.modify(|_, w| { if intr_handler(uart) {
w.txfifo_empty_int_ena() WAKERS[2].wake();
.clear_bit() }
.tx_done_int_ena()
.clear_bit()
});
WAKERS[2].wake();
} }
} }

View File

@ -1,3 +1,5 @@
//! USB Serial JTAG peripheral driver
use core::convert::Infallible; use core::convert::Infallible;
use crate::{ use crate::{
@ -6,6 +8,7 @@ use crate::{
system::PeripheralClockControl, system::PeripheralClockControl,
}; };
/// USB Serial JTAG driver
pub struct UsbSerialJtag<'d> { pub struct UsbSerialJtag<'d> {
usb_serial: PeripheralRef<'d, USB_DEVICE>, usb_serial: PeripheralRef<'d, USB_DEVICE>,
} }
@ -150,7 +153,7 @@ impl<'d> UsbSerialJtag<'d> {
} }
} }
/// USB serial/JTAG peripheral instance /// USB Serial JTAG peripheral instance
pub trait Instance { pub trait Instance {
fn register_block(&self) -> &RegisterBlock; fn register_block(&self) -> &RegisterBlock;

View File

@ -3,8 +3,13 @@ runner = "espflash flash --monitor"
[build] [build]
rustflags = [ rustflags = [
"-C", "link-arg=-nostartfiles", # GNU LD
"-C", "link-arg=-Wl,-Tlinkall.x", # "-C", "link-arg=-nostartfiles",
# "-C", "link-arg=-Wl,-Tlinkall.x",
# LLD
"-C", "linker=rust-lld",
"-C", "link-arg=-Tlinkall.x",
] ]
target = "xtensa-esp32-none-elf" target = "xtensa-esp32-none-elf"

View File

@ -47,6 +47,7 @@ sha2 = { version = "0.10.6", default-features = false}
smart-leds = "0.3.0" smart-leds = "0.3.0"
ssd1306 = "0.7.1" ssd1306 = "0.7.1"
static_cell = "1.0.0" static_cell = "1.0.0"
heapless = "0.7.16"
[features] [features]
default = ["rt", "vectored", "xtal40mhz"] default = ["rt", "vectored", "xtal40mhz"]

View File

@ -9,7 +9,7 @@ use esp32_hal::{
clock::ClockControl, clock::ClockControl,
peripherals::Peripherals, peripherals::Peripherals,
prelude::*, prelude::*,
rom::crc, rom::{crc, md5},
timer::TimerGroup, timer::TimerGroup,
Rtc, Rtc,
Uart, Uart,
@ -40,6 +40,7 @@ fn main() -> ! {
timer0.start(1u64.secs()); timer0.start(1u64.secs());
let data = "123456789"; let data = "123456789";
let sentence = "The quick brown fox jumps over a lazy dog";
writeln!( writeln!(
serial0, serial0,
@ -66,10 +67,38 @@ fn main() -> ! {
assert_eq!(crc_rohc, 0xd0); assert_eq!(crc_rohc, 0xd0);
assert_eq!(crc_smbus, 0xf4); assert_eq!(crc_smbus, 0xf4);
// Hash the sentence one word at a time to *really* test the context
// Use Peekable while iter_intersperse is unstable
let mut md5_ctx = md5::Context::new();
let mut it = sentence.split_whitespace().peekable();
while let Some(word) = it.next() {
md5_ctx.consume(word);
if it.peek().is_some() {
md5_ctx.consume(" ");
}
}
let md5_digest = md5_ctx.compute();
assert_eq!(
md5_digest,
md5::Digest([
0x30, 0xde, 0xd8, 0x07, 0xd6, 0x5e, 0xe0, 0x37, 0x0f, 0xc6, 0xd7, 0x3d, 0x6a, 0xb5,
0x5a, 0x95
])
);
writeln!( writeln!(
serial0, serial0,
"{:08x} {:08x} {:08x} {:08x} {:04x} {:04x} {:02x} {:02x}", "{:08x} {:08x} {:08x} {:08x} {:04x} {:04x} {:02x} {:02x} {}",
crc_hdlc, crc_bzip2, crc_mpeg2, crc_cksum, crc_kermit, crc_genibus, crc_rohc, crc_smbus crc_hdlc,
crc_bzip2,
crc_mpeg2,
crc_cksum,
crc_kermit,
crc_genibus,
crc_rohc,
crc_smbus,
md5_digest
) )
.unwrap(); .unwrap();

View File

@ -20,10 +20,10 @@ use esp32_hal::{
clock::ClockControl, clock::ClockControl,
embassy, embassy,
i2c::I2C, i2c::I2C,
interrupt,
peripherals::{Interrupt, Peripherals, I2C0}, peripherals::{Interrupt, Peripherals, I2C0},
prelude::*, prelude::*,
timer::TimerGroup, timer::TimerGroup,
Priority,
Rtc, Rtc,
IO, IO,
}; };
@ -77,7 +77,7 @@ fn main() -> ! {
&clocks, &clocks,
); );
esp32_hal::interrupt::enable(Interrupt::I2C_EXT0, Priority::Priority1).unwrap(); interrupt::enable(Interrupt::I2C_EXT0, interrupt::Priority::Priority1).unwrap();
let executor = EXECUTOR.init(Executor::new()); let executor = EXECUTOR.init(Executor::new());
executor.run(|spawner| { executor.run(|spawner| {

View File

@ -1,17 +1,20 @@
//! embassy serial //! embassy serial
//! //!
//! This is an example of running the embassy executor and asynchronously //! This is an example of running the embassy executor and asynchronously
//! writing to a uart. //! writing to and reading from uart
#![no_std] #![no_std]
#![no_main] #![no_main]
#![feature(type_alias_impl_trait)] #![feature(type_alias_impl_trait)]
use core::fmt::Write;
use embassy_executor::Executor; use embassy_executor::Executor;
use embassy_time::{Duration, Timer}; use embassy_time::{with_timeout, Duration};
use esp32_hal::{ use esp32_hal::{
clock::ClockControl, clock::ClockControl,
embassy, embassy,
interrupt,
peripherals::{Interrupt, Peripherals, UART0}, peripherals::{Interrupt, Peripherals, UART0},
prelude::*, prelude::*,
timer::TimerGroup, timer::TimerGroup,
@ -19,18 +22,79 @@ use esp32_hal::{
Uart, Uart,
}; };
use esp_backtrace as _; use esp_backtrace as _;
use esp_hal_common::uart::config::AtCmdConfig;
use heapless::Vec;
use static_cell::StaticCell; use static_cell::StaticCell;
// rx_fifo_full_threshold
const READ_BUF_SIZE: usize = 128;
// EOT (CTRL-D)
const AT_CMD: u8 = 0x04;
#[embassy_executor::task] #[embassy_executor::task]
async fn run(mut uart: Uart<'static, UART0>) { async fn run(mut uart: Uart<'static, UART0>) {
// max message size to receive
// leave some extra space for AT-CMD characters
const MAX_BUFFER_SIZE: usize = 10 * READ_BUF_SIZE + 16;
// timeout read
const READ_TIMEOUT: Duration = Duration::from_secs(10);
let mut rbuf: Vec<u8, MAX_BUFFER_SIZE> = Vec::new();
let mut wbuf: Vec<u8, MAX_BUFFER_SIZE> = Vec::new();
loop { loop {
embedded_hal_async::serial::Write::write(&mut uart, b"Hello async write!!!\r\n") if rbuf.is_empty() {
embedded_hal_async::serial::Write::write(
&mut uart,
b"Hello async serial. Enter something ended with EOT (CTRL-D).\r\n",
)
.await .await
.unwrap(); .unwrap();
} else {
wbuf.clear();
write!(&mut wbuf, "\r\n-- received {} bytes --\r\n", rbuf.len()).unwrap();
embedded_hal_async::serial::Write::write(&mut uart, wbuf.as_slice())
.await
.unwrap();
embedded_hal_async::serial::Write::write(&mut uart, rbuf.as_slice())
.await
.unwrap();
embedded_hal_async::serial::Write::write(&mut uart, b"\r\n")
.await
.unwrap();
}
embedded_hal_async::serial::Write::flush(&mut uart) embedded_hal_async::serial::Write::flush(&mut uart)
.await .await
.unwrap(); .unwrap();
Timer::after(Duration::from_millis(1_000)).await;
// set rbuf full capacity
rbuf.resize_default(rbuf.capacity()).ok();
let mut offset = 0;
loop {
match with_timeout(READ_TIMEOUT, uart.read(&mut rbuf[offset..])).await {
Ok(r) => {
if let Ok(len) = r {
offset += len;
if offset == 0 {
rbuf.truncate(0);
break;
}
// if set_at_cmd is used than stop reading
if len < READ_BUF_SIZE {
rbuf.truncate(offset);
break;
}
} else {
// buffer is full
break;
}
}
Err(_) => {
// Timeout
rbuf.truncate(offset);
break;
}
}
}
} }
} }
@ -65,9 +129,11 @@ fn main() -> ! {
#[cfg(feature = "embassy-time-timg0")] #[cfg(feature = "embassy-time-timg0")]
embassy::init(&clocks, timer_group0.timer0); embassy::init(&clocks, timer_group0.timer0);
let uart0 = Uart::new(peripherals.UART0, &mut system.peripheral_clock_control); let mut uart0 = Uart::new(peripherals.UART0, &mut system.peripheral_clock_control);
uart0.set_at_cmd(AtCmdConfig::new(None, None, None, AT_CMD, None));
uart0.set_rx_fifo_full_threshold(READ_BUF_SIZE as u16);
esp32_hal::interrupt::enable(Interrupt::UART0, esp32_hal::Priority::Priority1).unwrap(); interrupt::enable(Interrupt::UART0, interrupt::Priority::Priority1).unwrap();
let executor = EXECUTOR.init(Executor::new()); let executor = EXECUTOR.init(Executor::new());
executor.run(|spawner| { executor.run(|spawner| {

View File

@ -44,14 +44,7 @@ macro_rules! singleton {
}}; }};
} }
pub type SpiType<'d> = SpiDma< pub type SpiType<'d> = SpiDma<'d, esp32_hal::peripherals::SPI2, Spi2DmaChannel, FullDuplexMode>;
'd,
esp32_hal::peripherals::SPI2,
ChannelTx<'d, Spi2DmaChannelTxImpl, Spi2DmaChannel>,
ChannelRx<'d, Spi2DmaChannelRxImpl, Spi2DmaChannel>,
Spi2DmaSuitablePeripheral,
FullDuplexMode,
>;
#[embassy_executor::task] #[embassy_executor::task]
async fn spi_task(spi: &'static mut SpiType<'static>) { async fn spi_task(spi: &'static mut SpiType<'static>) {

View File

@ -9,7 +9,7 @@ use esp32_hal::{
clock::ClockControl, clock::ClockControl,
peripherals::Peripherals, peripherals::Peripherals,
prelude::*, prelude::*,
soc, psram,
timer::TimerGroup, timer::TimerGroup,
Rtc, Rtc,
}; };
@ -23,10 +23,7 @@ static ALLOCATOR: esp_alloc::EspHeap = esp_alloc::EspHeap::empty();
fn init_psram_heap() { fn init_psram_heap() {
unsafe { unsafe {
ALLOCATOR.init( ALLOCATOR.init(psram::PSRAM_VADDR_START as *mut u8, psram::PSRAM_BYTES);
soc::psram::PSRAM_VADDR_START as *mut u8,
soc::psram::PSRAM_BYTES,
);
} }
} }
@ -38,7 +35,7 @@ fn main() -> ! {
esp_println::logger::init_logger_from_env(); esp_println::logger::init_logger_from_env();
let peripherals = Peripherals::take(); let peripherals = Peripherals::take();
soc::psram::init_psram(peripherals.PSRAM); psram::init_psram(peripherals.PSRAM);
init_psram_heap(); init_psram_heap();
let mut system = peripherals.DPORT.split(); let mut system = peripherals.DPORT.split();

View File

@ -23,3 +23,7 @@ PROVIDE (esp_rom_crc8_be = 0x4005d114);
PROVIDE (esp_rom_crc32_le = 0x4005cfec); PROVIDE (esp_rom_crc32_le = 0x4005cfec);
PROVIDE (esp_rom_crc16_le = 0x4005d05c); PROVIDE (esp_rom_crc16_le = 0x4005d05c);
PROVIDE (esp_rom_crc8_le = 0x4005d0e0); PROVIDE (esp_rom_crc8_le = 0x4005d0e0);
PROVIDE (esp_rom_md5_init = 0x4005da7c);
PROVIDE (esp_rom_md5_update = 0x4005da9c);
PROVIDE (esp_rom_md5_final = 0x4005db1c);

View File

@ -1,13 +1,15 @@
//! `no_std` HAL for the ESP32 from Espressif.
//!
//! Implements a number of the traits defined by the various packages in the
//! [embedded-hal] repository.
//!
//! [embedded-hal]: https://github.com/rust-embedded/embedded-hal
#![no_std] #![no_std]
#![doc(html_logo_url = "https://avatars.githubusercontent.com/u/46717278")] #![doc(html_logo_url = "https://avatars.githubusercontent.com/u/46717278")]
pub use embedded_hal as ehal;
#[cfg(feature = "embassy")]
pub use esp_hal_common::embassy;
pub use esp_hal_common::*; pub use esp_hal_common::*;
pub use self::gpio::IO;
/// Common module for analog functions /// Common module for analog functions
pub mod analog { pub mod analog {
pub use esp_hal_common::analog::{AvailableAnalog, SensExt}; pub use esp_hal_common::analog::{AvailableAnalog, SensExt};

View File

@ -42,6 +42,7 @@ lis3dh-async = "0.7.0"
sha2 = { version = "0.10.6", default-features = false} sha2 = { version = "0.10.6", default-features = false}
ssd1306 = "0.7.1" ssd1306 = "0.7.1"
static_cell = "1.0.0" static_cell = "1.0.0"
heapless = "0.7.16"
[features] [features]
default = ["rt", "vectored", "xtal40mhz"] default = ["rt", "vectored", "xtal40mhz"]

View File

@ -9,7 +9,7 @@ use esp32c2_hal::{
clock::ClockControl, clock::ClockControl,
peripherals::Peripherals, peripherals::Peripherals,
prelude::*, prelude::*,
rom::crc, rom::{crc, md5},
timer::TimerGroup, timer::TimerGroup,
Rtc, Rtc,
Uart, Uart,
@ -41,6 +41,7 @@ fn main() -> ! {
timer0.start(1u64.secs()); timer0.start(1u64.secs());
let data = "123456789"; let data = "123456789";
let sentence = "The quick brown fox jumps over a lazy dog";
writeln!( writeln!(
serial0, serial0,
@ -67,10 +68,38 @@ fn main() -> ! {
assert_eq!(crc_rohc, 0xd0); assert_eq!(crc_rohc, 0xd0);
assert_eq!(crc_smbus, 0xf4); assert_eq!(crc_smbus, 0xf4);
// Hash the sentence one word at a time to *really* test the context
// Use Peekable while iter_intersperse is unstable
let mut md5_ctx = md5::Context::new();
let mut it = sentence.split_whitespace().peekable();
while let Some(word) = it.next() {
md5_ctx.consume(word);
if it.peek().is_some() {
md5_ctx.consume(" ");
}
}
let md5_digest = md5_ctx.compute();
assert_eq!(
md5_digest,
md5::Digest([
0x30, 0xde, 0xd8, 0x07, 0xd6, 0x5e, 0xe0, 0x37, 0x0f, 0xc6, 0xd7, 0x3d, 0x6a, 0xb5,
0x5a, 0x95
])
);
writeln!( writeln!(
serial0, serial0,
"{:08x} {:08x} {:08x} {:08x} {:04x} {:04x} {:02x} {:02x}", "{:08x} {:08x} {:08x} {:08x} {:04x} {:04x} {:02x} {:02x} {}",
crc_hdlc, crc_bzip2, crc_mpeg2, crc_cksum, crc_kermit, crc_genibus, crc_rohc, crc_smbus crc_hdlc,
crc_bzip2,
crc_mpeg2,
crc_cksum,
crc_kermit,
crc_genibus,
crc_rohc,
crc_smbus,
md5_digest
) )
.unwrap(); .unwrap();

View File

@ -20,10 +20,10 @@ use esp32c2_hal::{
clock::ClockControl, clock::ClockControl,
embassy, embassy,
i2c::I2C, i2c::I2C,
interrupt,
peripherals::{Interrupt, Peripherals, I2C0}, peripherals::{Interrupt, Peripherals, I2C0},
prelude::*, prelude::*,
timer::TimerGroup, timer::TimerGroup,
Priority,
Rtc, Rtc,
IO, IO,
}; };
@ -85,7 +85,7 @@ fn main() -> ! {
&clocks, &clocks,
); );
esp32c2_hal::interrupt::enable(Interrupt::I2C_EXT0, Priority::Priority1).unwrap(); interrupt::enable(Interrupt::I2C_EXT0, interrupt::Priority::Priority1).unwrap();
let executor = EXECUTOR.init(Executor::new()); let executor = EXECUTOR.init(Executor::new());
executor.run(|spawner| { executor.run(|spawner| {

View File

@ -1,17 +1,20 @@
//! embassy serial //! embassy serial
//! //!
//! This is an example of running the embassy executor and asynchronously //! This is an example of running the embassy executor and asynchronously
//! writing to a uart. //! writing to and reading from uart
#![no_std] #![no_std]
#![no_main] #![no_main]
#![feature(type_alias_impl_trait)] #![feature(type_alias_impl_trait)]
use core::fmt::Write;
use embassy_executor::Executor; use embassy_executor::Executor;
use embassy_time::{Duration, Timer}; use embassy_time::{with_timeout, Duration};
use esp32c2_hal::{ use esp32c2_hal::{
clock::ClockControl, clock::ClockControl,
embassy, embassy,
interrupt,
peripherals::{Interrupt, Peripherals, UART0}, peripherals::{Interrupt, Peripherals, UART0},
prelude::*, prelude::*,
timer::TimerGroup, timer::TimerGroup,
@ -19,18 +22,79 @@ use esp32c2_hal::{
Uart, Uart,
}; };
use esp_backtrace as _; use esp_backtrace as _;
use esp_hal_common::uart::config::AtCmdConfig;
use heapless::Vec;
use static_cell::StaticCell; use static_cell::StaticCell;
// rx_fifo_full_threshold
const READ_BUF_SIZE: usize = 128;
/// EOT; CTRL-D
const AT_CMD: u8 = 0x04;
#[embassy_executor::task] #[embassy_executor::task]
async fn run(mut uart: Uart<'static, UART0>) { async fn run(mut uart: Uart<'static, UART0>) {
// max message size to receive
// leave some extra space for AT-CMD characters
const MAX_BUFFER_SIZE: usize = 10 * READ_BUF_SIZE + 16;
// timeout read
const READ_TIMEOUT: Duration = Duration::from_secs(10);
let mut rbuf: Vec<u8, MAX_BUFFER_SIZE> = Vec::new();
let mut wbuf: Vec<u8, MAX_BUFFER_SIZE> = Vec::new();
loop { loop {
embedded_hal_async::serial::Write::write(&mut uart, b"Hello async write!!!\r\n") if rbuf.is_empty() {
embedded_hal_async::serial::Write::write(
&mut uart,
b"Hello async serial. Enter something ended with EOT (CTRL-D).\r\n",
)
.await .await
.unwrap(); .unwrap();
} else {
wbuf.clear();
write!(&mut wbuf, "\r\n-- received {} bytes --\r\n", rbuf.len()).unwrap();
embedded_hal_async::serial::Write::write(&mut uart, wbuf.as_slice())
.await
.unwrap();
embedded_hal_async::serial::Write::write(&mut uart, rbuf.as_slice())
.await
.unwrap();
embedded_hal_async::serial::Write::write(&mut uart, b"\r\n")
.await
.unwrap();
}
embedded_hal_async::serial::Write::flush(&mut uart) embedded_hal_async::serial::Write::flush(&mut uart)
.await .await
.unwrap(); .unwrap();
Timer::after(Duration::from_millis(1_000)).await;
// set rbuf full capacity
rbuf.resize_default(rbuf.capacity()).ok();
let mut offset = 0;
loop {
match with_timeout(READ_TIMEOUT, uart.read(&mut rbuf[offset..])).await {
Ok(r) => {
if let Ok(len) = r {
offset += len;
if offset == 0 {
rbuf.truncate(0);
break;
}
// if set_at_cmd is used than stop reading
if len < READ_BUF_SIZE {
rbuf.truncate(offset);
break;
}
} else {
// buffer is full
break;
}
}
Err(_) => {
// Timeout
rbuf.truncate(offset);
break;
}
}
}
} }
} }
@ -65,9 +129,11 @@ fn main() -> ! {
#[cfg(feature = "embassy-time-timg0")] #[cfg(feature = "embassy-time-timg0")]
embassy::init(&clocks, timer_group0.timer0); embassy::init(&clocks, timer_group0.timer0);
let uart0 = Uart::new(peripherals.UART0, &mut system.peripheral_clock_control); let mut uart0 = Uart::new(peripherals.UART0, &mut system.peripheral_clock_control);
uart0.set_at_cmd(AtCmdConfig::new(None, None, None, AT_CMD, None));
uart0.set_rx_fifo_full_threshold(READ_BUF_SIZE as u16);
esp32c2_hal::interrupt::enable(Interrupt::UART0, esp32c2_hal::Priority::Priority1).unwrap(); interrupt::enable(Interrupt::UART0, interrupt::Priority::Priority1).unwrap();
let executor = EXECUTOR.init(Executor::new()); let executor = EXECUTOR.init(Executor::new());
executor.run(|spawner| { executor.run(|spawner| {

View File

@ -44,14 +44,8 @@ macro_rules! singleton {
}}; }};
} }
pub type SpiType<'d> = SpiDma< pub type SpiType<'d> =
'd, SpiDma<'d, esp32c2_hal::peripherals::SPI2, esp32c2_hal::gdma::Channel0, FullDuplexMode>;
esp32c2_hal::peripherals::SPI2,
ChannelTx<'d, Channel0TxImpl, esp32c2_hal::gdma::Channel0>,
ChannelRx<'d, Channel0RxImpl, esp32c2_hal::gdma::Channel0>,
SuitablePeripheral0,
FullDuplexMode,
>;
#[embassy_executor::task] #[embassy_executor::task]
async fn spi_task(spi: &'static mut SpiType<'static>) { async fn spi_task(spi: &'static mut SpiType<'static>) {

View File

@ -67,7 +67,7 @@ SECTIONS {
*(.trap.*); *(.trap.*);
} > RWTEXT } > RWTEXT
} }
INSERT AFTER .rwtext; INSERT BEFORE .rwtext;
SECTIONS { SECTIONS {
/** /**

View File

@ -89,10 +89,10 @@ SECTIONS
_data_size = _data_end - _data_start + 8; _data_size = _data_end - _data_start + 8;
.rwtext ORIGIN(REGION_RWTEXT) + _data_size : AT(_text_size + _rodata_size + _data_size){ .rwtext ORIGIN(REGION_RWTEXT) + _data_size : AT(_text_size + _rodata_size + _data_size){
_srwtext = .; _srwtext = .;
*(.rwtext);
. = ALIGN(4);
KEEP(*(.trap)); KEEP(*(.trap));
*(.trap.*); *(.trap.*);
*(.rwtext);
. = ALIGN(4);
_erwtext = .; _erwtext = .;
} > REGION_RWTEXT } > REGION_RWTEXT
_rwtext_size = _erwtext - _srwtext + 8; _rwtext_size = _erwtext - _srwtext + 8;

View File

@ -12,3 +12,7 @@ PROVIDE(esp_rom_crc8_be = 0x40000810);
PROVIDE(esp_rom_crc32_le = 0x400007fc); PROVIDE(esp_rom_crc32_le = 0x400007fc);
PROVIDE(esp_rom_crc16_le = 0x40000800); PROVIDE(esp_rom_crc16_le = 0x40000800);
PROVIDE(esp_rom_crc8_le = 0x40000804); PROVIDE(esp_rom_crc8_le = 0x40000804);
PROVIDE(esp_rom_mbedtls_md5_starts_ret = 0x40002be4);
PROVIDE(esp_rom_mbedtls_md5_update_ret = 0x40002be8);
PROVIDE(esp_rom_mbedtls_md5_finish_ret = 0x40002bec);

View File

@ -1,13 +1,15 @@
//! `no_std` HAL for the ESP32-C2/ESP8684 from Espressif.
//!
//! Implements a number of the traits defined by the various packages in the
//! [embedded-hal] repository.
//!
//! [embedded-hal]: https://github.com/rust-embedded/embedded-hal
#![no_std] #![no_std]
#![doc(html_logo_url = "https://avatars.githubusercontent.com/u/46717278")] #![doc(html_logo_url = "https://avatars.githubusercontent.com/u/46717278")]
pub use embedded_hal as ehal;
#[cfg(feature = "embassy")]
pub use esp_hal_common::embassy;
pub use esp_hal_common::*; pub use esp_hal_common::*;
pub use self::gpio::IO;
/// Common module for analog functions /// Common module for analog functions
pub mod analog { pub mod analog {
pub use esp_hal_common::analog::{AvailableAnalog, SarAdcExt}; pub use esp_hal_common::analog::{AvailableAnalog, SarAdcExt};

View File

@ -48,6 +48,7 @@ sha2 = { version = "0.10.6", default-features = false}
smart-leds = "0.3.0" smart-leds = "0.3.0"
ssd1306 = "0.7.1" ssd1306 = "0.7.1"
static_cell = "1.0.0" static_cell = "1.0.0"
heapless = "0.7.16"
[features] [features]
default = ["rt", "vectored", "esp-hal-common/rv-zero-rtc-bss"] default = ["rt", "vectored", "esp-hal-common/rv-zero-rtc-bss"]

View File

@ -9,7 +9,7 @@ use esp32c3_hal::{
clock::ClockControl, clock::ClockControl,
peripherals::Peripherals, peripherals::Peripherals,
prelude::*, prelude::*,
rom::crc, rom::{crc, md5},
timer::TimerGroup, timer::TimerGroup,
Rtc, Rtc,
Uart, Uart,
@ -48,6 +48,7 @@ fn main() -> ! {
timer0.start(1u64.secs()); timer0.start(1u64.secs());
let data = "123456789"; let data = "123456789";
let sentence = "The quick brown fox jumps over a lazy dog";
writeln!( writeln!(
uart0, uart0,
@ -74,10 +75,38 @@ fn main() -> ! {
assert_eq!(crc_rohc, 0xd0); assert_eq!(crc_rohc, 0xd0);
assert_eq!(crc_smbus, 0xf4); assert_eq!(crc_smbus, 0xf4);
// Hash the sentence one word at a time to *really* test the context
// Use Peekable while iter_intersperse is unstable
let mut md5_ctx = md5::Context::new();
let mut it = sentence.split_whitespace().peekable();
while let Some(word) = it.next() {
md5_ctx.consume(word);
if it.peek().is_some() {
md5_ctx.consume(" ");
}
}
let md5_digest = md5_ctx.compute();
assert_eq!(
md5_digest,
md5::Digest([
0x30, 0xde, 0xd8, 0x07, 0xd6, 0x5e, 0xe0, 0x37, 0x0f, 0xc6, 0xd7, 0x3d, 0x6a, 0xb5,
0x5a, 0x95
])
);
writeln!( writeln!(
uart0, uart0,
"{:08x} {:08x} {:08x} {:08x} {:04x} {:04x} {:02x} {:02x}", "{:08x} {:08x} {:08x} {:08x} {:04x} {:04x} {:02x} {:02x} {}",
crc_hdlc, crc_bzip2, crc_mpeg2, crc_cksum, crc_kermit, crc_genibus, crc_rohc, crc_smbus crc_hdlc,
crc_bzip2,
crc_mpeg2,
crc_cksum,
crc_kermit,
crc_genibus,
crc_rohc,
crc_smbus,
md5_digest
) )
.unwrap(); .unwrap();

View File

@ -20,10 +20,10 @@ use esp32c3_hal::{
clock::ClockControl, clock::ClockControl,
embassy, embassy,
i2c::I2C, i2c::I2C,
interrupt,
peripherals::{Interrupt, Peripherals, I2C0}, peripherals::{Interrupt, Peripherals, I2C0},
prelude::*, prelude::*,
timer::TimerGroup, timer::TimerGroup,
Priority,
Rtc, Rtc,
IO, IO,
}; };
@ -92,7 +92,7 @@ fn main() -> ! {
&clocks, &clocks,
); );
esp32c3_hal::interrupt::enable(Interrupt::I2C_EXT0, Priority::Priority1).unwrap(); interrupt::enable(Interrupt::I2C_EXT0, interrupt::Priority::Priority1).unwrap();
let executor = EXECUTOR.init(Executor::new()); let executor = EXECUTOR.init(Executor::new());
executor.run(|spawner| { executor.run(|spawner| {

View File

@ -1,17 +1,20 @@
//! embassy serial //! embassy serial
//! //!
//! This is an example of running the embassy executor and asynchronously //! This is an example of running the embassy executor and asynchronously
//! writing to a uart. //! writing to and reading from uart
#![no_std] #![no_std]
#![no_main] #![no_main]
#![feature(type_alias_impl_trait)] #![feature(type_alias_impl_trait)]
use core::fmt::Write;
use embassy_executor::Executor; use embassy_executor::Executor;
use embassy_time::{Duration, Timer}; use embassy_time::{with_timeout, Duration};
use esp32c3_hal::{ use esp32c3_hal::{
clock::ClockControl, clock::ClockControl,
embassy, embassy,
interrupt,
peripherals::{Interrupt, Peripherals, UART0}, peripherals::{Interrupt, Peripherals, UART0},
prelude::*, prelude::*,
timer::TimerGroup, timer::TimerGroup,
@ -19,18 +22,79 @@ use esp32c3_hal::{
Uart, Uart,
}; };
use esp_backtrace as _; use esp_backtrace as _;
use esp_hal_common::uart::config::AtCmdConfig;
use heapless::Vec;
use static_cell::StaticCell; use static_cell::StaticCell;
// rx_fifo_full_threshold
const READ_BUF_SIZE: usize = 128;
// EOT (CTRL-D)
const AT_CMD: u8 = 0x04;
#[embassy_executor::task] #[embassy_executor::task]
async fn run(mut uart: Uart<'static, UART0>) { async fn run(mut uart: Uart<'static, UART0>) {
// max message size to receive
// leave some extra space for AT-CMD characters
const MAX_BUFFER_SIZE: usize = 10 * READ_BUF_SIZE + 16;
// timeout read
const READ_TIMEOUT: Duration = Duration::from_secs(10);
let mut rbuf: Vec<u8, MAX_BUFFER_SIZE> = Vec::new();
let mut wbuf: Vec<u8, MAX_BUFFER_SIZE> = Vec::new();
loop { loop {
embedded_hal_async::serial::Write::write(&mut uart, b"Hello async write!!!\r\n") if rbuf.is_empty() {
embedded_hal_async::serial::Write::write(
&mut uart,
b"Hello async serial. Enter something ended with EOT (CTRL-D).\r\n",
)
.await .await
.unwrap(); .unwrap();
} else {
wbuf.clear();
write!(&mut wbuf, "\r\n-- received {} bytes --\r\n", rbuf.len()).unwrap();
embedded_hal_async::serial::Write::write(&mut uart, wbuf.as_slice())
.await
.unwrap();
embedded_hal_async::serial::Write::write(&mut uart, rbuf.as_slice())
.await
.unwrap();
embedded_hal_async::serial::Write::write(&mut uart, b"\r\n")
.await
.unwrap();
}
embedded_hal_async::serial::Write::flush(&mut uart) embedded_hal_async::serial::Write::flush(&mut uart)
.await .await
.unwrap(); .unwrap();
Timer::after(Duration::from_millis(1_000)).await;
// set rbuf full capacity
rbuf.resize_default(rbuf.capacity()).ok();
let mut offset = 0;
loop {
match with_timeout(READ_TIMEOUT, uart.read(&mut rbuf[offset..])).await {
Ok(r) => {
if let Ok(len) = r {
offset += len;
if offset == 0 {
rbuf.truncate(0);
break;
}
// if set_at_cmd is used than stop reading
if len < READ_BUF_SIZE {
rbuf.truncate(offset);
break;
}
} else {
// buffer is full
break;
}
}
Err(_) => {
// Timeout
rbuf.truncate(offset);
break;
}
}
}
} }
} }
@ -72,9 +136,11 @@ fn main() -> ! {
#[cfg(feature = "embassy-time-timg0")] #[cfg(feature = "embassy-time-timg0")]
embassy::init(&clocks, timer_group0.timer0); embassy::init(&clocks, timer_group0.timer0);
let uart0 = Uart::new(peripherals.UART0, &mut system.peripheral_clock_control); let mut uart0 = Uart::new(peripherals.UART0, &mut system.peripheral_clock_control);
uart0.set_at_cmd(AtCmdConfig::new(None, None, None, AT_CMD, None));
uart0.set_rx_fifo_full_threshold(READ_BUF_SIZE as u16);
esp32c3_hal::interrupt::enable(Interrupt::UART0, esp32c3_hal::Priority::Priority1).unwrap(); interrupt::enable(Interrupt::UART0, interrupt::Priority::Priority1).unwrap();
let executor = EXECUTOR.init(Executor::new()); let executor = EXECUTOR.init(Executor::new());
executor.run(|spawner| { executor.run(|spawner| {

View File

@ -44,14 +44,8 @@ macro_rules! singleton {
}}; }};
} }
pub type SpiType<'d> = SpiDma< pub type SpiType<'d> =
'd, SpiDma<'d, esp32c3_hal::peripherals::SPI2, esp32c3_hal::gdma::Channel0, FullDuplexMode>;
esp32c3_hal::peripherals::SPI2,
ChannelTx<'d, Channel0TxImpl, esp32c3_hal::gdma::Channel0>,
ChannelRx<'d, Channel0RxImpl, esp32c3_hal::gdma::Channel0>,
SuitablePeripheral0,
FullDuplexMode,
>;
#[embassy_executor::task] #[embassy_executor::task]
async fn spi_task(spi: &'static mut SpiType<'static>) { async fn spi_task(spi: &'static mut SpiType<'static>) {

View File

@ -67,7 +67,7 @@ SECTIONS {
*(.trap.*); *(.trap.*);
} > RWTEXT } > RWTEXT
} }
INSERT AFTER .rwtext; INSERT BEFORE .rwtext;
SECTIONS { SECTIONS {
/** /**

View File

@ -89,10 +89,10 @@ SECTIONS
_data_size = _data_end - _data_start + 8; _data_size = _data_end - _data_start + 8;
.rwtext ORIGIN(REGION_RWTEXT) + _data_size : AT(_text_size + _rodata_size + _data_size){ .rwtext ORIGIN(REGION_RWTEXT) + _data_size : AT(_text_size + _rodata_size + _data_size){
_srwtext = .; _srwtext = .;
*(.rwtext);
. = ALIGN(4);
KEEP(*(.trap)); KEEP(*(.trap));
*(.trap.*); *(.trap.*);
*(.rwtext);
. = ALIGN(4);
_erwtext = .; _erwtext = .;
} > REGION_RWTEXT } > REGION_RWTEXT
_rwtext_size = _erwtext - _srwtext + 8; _rwtext_size = _erwtext - _srwtext + 8;

View File

@ -64,9 +64,9 @@ SECTIONS
KEEP(*(.init)); KEEP(*(.init));
KEEP(*(.init.rust)); KEEP(*(.init.rust));
KEEP(*(.text.abort)); KEEP(*(.text.abort));
. = ALIGN(4);
KEEP(*(.trap)); KEEP(*(.trap));
*(.trap.*); *(.trap.*);
. = ALIGN(4);
*libriscv-*.rlib:riscv.*(.literal .text .literal.* .text.*); *libriscv-*.rlib:riscv.*(.literal .text .literal.* .text.*);
*libesp_riscv_rt-*.rlib:esp-riscv-rt.*(.literal .text .literal.* .text.*); *libesp_riscv_rt-*.rlib:esp-riscv-rt.*(.literal .text .literal.* .text.*);

View File

@ -19,3 +19,7 @@ PROVIDE(esp_rom_crc8_be = 0x4000063c);
PROVIDE(esp_rom_crc32_le = 0x40000628); PROVIDE(esp_rom_crc32_le = 0x40000628);
PROVIDE(esp_rom_crc16_le = 0x40000630); PROVIDE(esp_rom_crc16_le = 0x40000630);
PROVIDE(esp_rom_crc8_le = 0x40000638); PROVIDE(esp_rom_crc8_le = 0x40000638);
PROVIDE(esp_rom_md5_init = 0x40000614);
PROVIDE(esp_rom_md5_update = 0x40000618);
PROVIDE(esp_rom_md5_final = 0x4000061c);

View File

@ -1,16 +1,15 @@
//! `no_std` HAL for the ESP32-C3/ESP8685 from Espressif.
//!
//! Implements a number of the traits defined by the various packages in the
//! [embedded-hal] repository.
//!
//! [embedded-hal]: https://github.com/rust-embedded/embedded-hal
#![no_std] #![no_std]
#![doc(html_logo_url = "https://avatars.githubusercontent.com/u/46717278")] #![doc(html_logo_url = "https://avatars.githubusercontent.com/u/46717278")]
#[cfg(feature = "mcu-boot")]
use core::mem::size_of;
pub use embedded_hal as ehal;
#[cfg(feature = "embassy")]
pub use esp_hal_common::embassy;
pub use esp_hal_common::*; pub use esp_hal_common::*;
pub use self::gpio::IO;
/// Common module for analog functions /// Common module for analog functions
pub mod analog { pub mod analog {
pub use esp_hal_common::analog::{AvailableAnalog, SarAdcExt}; pub use esp_hal_common::analog::{AvailableAnalog, SarAdcExt};
@ -90,7 +89,7 @@ unsafe fn configure_mmu() {
const FLASH_MMU_TABLE: *mut u32 = 0x600c_5000 as *mut u32; const FLASH_MMU_TABLE: *mut u32 = 0x600c_5000 as *mut u32;
const ICACHE_MMU_SIZE: usize = 0x200; const ICACHE_MMU_SIZE: usize = 0x200;
const FLASH_MMU_TABLE_SIZE: usize = ICACHE_MMU_SIZE / size_of::<u32>(); const FLASH_MMU_TABLE_SIZE: usize = ICACHE_MMU_SIZE / core::mem::size_of::<u32>();
const MMU_TABLE_INVALID_VAL: u32 = 0x100; const MMU_TABLE_INVALID_VAL: u32 = 0x100;
for i in 0..FLASH_MMU_TABLE_SIZE { for i in 0..FLASH_MMU_TABLE_SIZE {

View File

@ -49,6 +49,7 @@ sha2 = { version = "0.10.6", default-features = false}
smart-leds = "0.3.0" smart-leds = "0.3.0"
ssd1306 = "0.7.1" ssd1306 = "0.7.1"
static_cell = "1.0.0" static_cell = "1.0.0"
heapless = "0.7.16"
[features] [features]
default = ["rt", "vectored", "esp-hal-common/rv-zero-rtc-bss"] default = ["rt", "vectored", "esp-hal-common/rv-zero-rtc-bss"]

View File

@ -33,7 +33,7 @@ By default, [espflash](https://github.com/esp-rs/espflash) fetches the required
#### Direct Boot #### Direct Boot
[Direct Boot](https://github.com/espressif/esp32c6-direct-boot-example#direct-boot-in-esp32-c6) allows an application stored in the External Flash to be executed directly, without being copied into Internal RAM. [Direct Boot](https://github.com/espressif/esp32c3-direct-boot-example#direct-boot-in-esp32-c3) allows an application stored in the External Flash to be executed directly, without being copied into Internal RAM.
##### Booting the Hello World example using Direct Boot ##### Booting the Hello World example using Direct Boot

View File

@ -9,7 +9,7 @@ use esp32c6_hal::{
clock::ClockControl, clock::ClockControl,
peripherals::Peripherals, peripherals::Peripherals,
prelude::*, prelude::*,
rom::crc, rom::{crc, md5},
timer::TimerGroup, timer::TimerGroup,
Rtc, Rtc,
Uart, Uart,
@ -48,6 +48,7 @@ fn main() -> ! {
timer0.start(1u64.secs()); timer0.start(1u64.secs());
let data = "123456789"; let data = "123456789";
let sentence = "The quick brown fox jumps over a lazy dog";
writeln!( writeln!(
uart0, uart0,
@ -74,10 +75,38 @@ fn main() -> ! {
assert_eq!(crc_rohc, 0xd0); assert_eq!(crc_rohc, 0xd0);
assert_eq!(crc_smbus, 0xf4); assert_eq!(crc_smbus, 0xf4);
// Hash the sentence one word at a time to *really* test the context
// Use Peekable while iter_intersperse is unstable
let mut md5_ctx = md5::Context::new();
let mut it = sentence.split_whitespace().peekable();
while let Some(word) = it.next() {
md5_ctx.consume(word);
if it.peek().is_some() {
md5_ctx.consume(" ");
}
}
let md5_digest = md5_ctx.compute();
assert_eq!(
md5_digest,
md5::Digest([
0x30, 0xde, 0xd8, 0x07, 0xd6, 0x5e, 0xe0, 0x37, 0x0f, 0xc6, 0xd7, 0x3d, 0x6a, 0xb5,
0x5a, 0x95
])
);
writeln!( writeln!(
uart0, uart0,
"{:08x} {:08x} {:08x} {:08x} {:04x} {:04x} {:02x} {:02x}", "{:08x} {:08x} {:08x} {:08x} {:04x} {:04x} {:02x} {:02x} {}",
crc_hdlc, crc_bzip2, crc_mpeg2, crc_cksum, crc_kermit, crc_genibus, crc_rohc, crc_smbus crc_hdlc,
crc_bzip2,
crc_mpeg2,
crc_cksum,
crc_kermit,
crc_genibus,
crc_rohc,
crc_smbus,
md5_digest
) )
.unwrap(); .unwrap();

View File

@ -20,10 +20,10 @@ use esp32c6_hal::{
clock::ClockControl, clock::ClockControl,
embassy, embassy,
i2c::I2C, i2c::I2C,
interrupt,
peripherals::{Interrupt, Peripherals, I2C0}, peripherals::{Interrupt, Peripherals, I2C0},
prelude::*, prelude::*,
timer::TimerGroup, timer::TimerGroup,
Priority,
Rtc, Rtc,
IO, IO,
}; };
@ -92,7 +92,7 @@ fn main() -> ! {
&clocks, &clocks,
); );
esp32c6_hal::interrupt::enable(Interrupt::I2C_EXT0, Priority::Priority1).unwrap(); interrupt::enable(Interrupt::I2C_EXT0, interrupt::Priority::Priority1).unwrap();
let executor = EXECUTOR.init(Executor::new()); let executor = EXECUTOR.init(Executor::new());
executor.run(|spawner| { executor.run(|spawner| {

View File

@ -1,17 +1,20 @@
//! embassy serial //! embassy serial
//! //!
//! This is an example of running the embassy executor and asynchronously //! This is an example of running the embassy executor and asynchronously
//! writing to a uart. //! writing to and reading from uart
#![no_std] #![no_std]
#![no_main] #![no_main]
#![feature(type_alias_impl_trait)] #![feature(type_alias_impl_trait)]
use core::fmt::Write;
use embassy_executor::Executor; use embassy_executor::Executor;
use embassy_time::{Duration, Timer}; use embassy_time::{with_timeout, Duration};
use esp32c6_hal::{ use esp32c6_hal::{
clock::ClockControl, clock::ClockControl,
embassy, embassy,
interrupt,
peripherals::{Interrupt, Peripherals, UART0}, peripherals::{Interrupt, Peripherals, UART0},
prelude::*, prelude::*,
timer::TimerGroup, timer::TimerGroup,
@ -19,18 +22,79 @@ use esp32c6_hal::{
Uart, Uart,
}; };
use esp_backtrace as _; use esp_backtrace as _;
use esp_hal_common::uart::config::AtCmdConfig;
use heapless::Vec;
use static_cell::StaticCell; use static_cell::StaticCell;
// rx_fifo_full_threshold
const READ_BUF_SIZE: usize = 128;
// EOT (CTRL-D)
const AT_CMD: u8 = 0x04;
#[embassy_executor::task] #[embassy_executor::task]
async fn run(mut uart: Uart<'static, UART0>) { async fn run(mut uart: Uart<'static, UART0>) {
// max message size to receive
// leave some extra space for AT-CMD characters
const MAX_BUFFER_SIZE: usize = 10 * READ_BUF_SIZE + 16;
// timeout read
const READ_TIMEOUT: Duration = Duration::from_secs(10);
let mut rbuf: Vec<u8, MAX_BUFFER_SIZE> = Vec::new();
let mut wbuf: Vec<u8, MAX_BUFFER_SIZE> = Vec::new();
loop { loop {
embedded_hal_async::serial::Write::write(&mut uart, b"Hello async write!!!\r\n") if rbuf.is_empty() {
embedded_hal_async::serial::Write::write(
&mut uart,
b"Hello async serial. Enter something ended with EOT (CTRL-D).\r\n",
)
.await .await
.unwrap(); .unwrap();
} else {
wbuf.clear();
write!(&mut wbuf, "\r\n-- received {} bytes --\r\n", rbuf.len()).unwrap();
embedded_hal_async::serial::Write::write(&mut uart, wbuf.as_slice())
.await
.unwrap();
embedded_hal_async::serial::Write::write(&mut uart, rbuf.as_slice())
.await
.unwrap();
embedded_hal_async::serial::Write::write(&mut uart, b"\r\n")
.await
.unwrap();
}
embedded_hal_async::serial::Write::flush(&mut uart) embedded_hal_async::serial::Write::flush(&mut uart)
.await .await
.unwrap(); .unwrap();
Timer::after(Duration::from_millis(1_000)).await;
// set rbuf full capacity
rbuf.resize_default(rbuf.capacity()).ok();
let mut offset = 0;
loop {
match with_timeout(READ_TIMEOUT, uart.read(&mut rbuf[offset..])).await {
Ok(r) => {
if let Ok(len) = r {
offset += len;
if offset == 0 {
rbuf.truncate(0);
break;
}
// if set_at_cmd is used than stop reading
if len < READ_BUF_SIZE {
rbuf.truncate(offset);
break;
}
} else {
// buffer is full
break;
}
}
Err(_) => {
// Timeout
rbuf.truncate(offset);
break;
}
}
}
} }
} }
@ -72,9 +136,11 @@ fn main() -> ! {
#[cfg(feature = "embassy-time-timg0")] #[cfg(feature = "embassy-time-timg0")]
embassy::init(&clocks, timer_group0.timer0); embassy::init(&clocks, timer_group0.timer0);
let uart0 = Uart::new(peripherals.UART0, &mut system.peripheral_clock_control); let mut uart0 = Uart::new(peripherals.UART0, &mut system.peripheral_clock_control);
uart0.set_at_cmd(AtCmdConfig::new(None, None, None, AT_CMD, None));
uart0.set_rx_fifo_full_threshold(READ_BUF_SIZE as u16);
esp32c6_hal::interrupt::enable(Interrupt::UART0, esp32c6_hal::Priority::Priority1).unwrap(); interrupt::enable(Interrupt::UART0, interrupt::Priority::Priority1).unwrap();
let executor = EXECUTOR.init(Executor::new()); let executor = EXECUTOR.init(Executor::new());
executor.run(|spawner| { executor.run(|spawner| {

View File

@ -44,14 +44,8 @@ macro_rules! singleton {
}}; }};
} }
pub type SpiType<'d> = SpiDma< pub type SpiType<'d> =
'd, SpiDma<'d, esp32c6_hal::peripherals::SPI2, esp32c6_hal::gdma::Channel0, FullDuplexMode>;
esp32c6_hal::peripherals::SPI2,
ChannelTx<'d, Channel0TxImpl, esp32c6_hal::gdma::Channel0>,
ChannelRx<'d, Channel0RxImpl, esp32c6_hal::gdma::Channel0>,
SuitablePeripheral0,
FullDuplexMode,
>;
#[embassy_executor::task] #[embassy_executor::task]
async fn spi_task(spi: &'static mut SpiType<'static>) { async fn spi_task(spi: &'static mut SpiType<'static>) {

View File

@ -71,7 +71,7 @@ SECTIONS {
*(.trap.*); *(.trap.*);
} > RWTEXT } > RWTEXT
} }
INSERT AFTER .rwtext; INSERT BEFORE .rwtext;
SECTIONS { SECTIONS {
/** /**

View File

@ -94,10 +94,10 @@ SECTIONS
_data_size = _data_end - _data_start + 8; _data_size = _data_end - _data_start + 8;
.rwtext ORIGIN(REGION_RWTEXT) + _data_size : AT(_text_size + _rodata_size + _data_size){ .rwtext ORIGIN(REGION_RWTEXT) + _data_size : AT(_text_size + _rodata_size + _data_size){
_srwtext = .; _srwtext = .;
*(.rwtext);
. = ALIGN(4);
KEEP(*(.trap)); KEEP(*(.trap));
*(.trap.*); *(.trap.*);
*(.rwtext);
. = ALIGN(4);
_erwtext = .; _erwtext = .;
} > REGION_RWTEXT } > REGION_RWTEXT
_rwtext_size = _erwtext - _srwtext + 8; _rwtext_size = _erwtext - _srwtext + 8;

View File

@ -19,3 +19,7 @@ PROVIDE(esp_rom_crc8_be = 0x4000076c);
PROVIDE(esp_rom_crc32_le = 0x40000758); PROVIDE(esp_rom_crc32_le = 0x40000758);
PROVIDE(esp_rom_crc16_le = 0x4000075c); PROVIDE(esp_rom_crc16_le = 0x4000075c);
PROVIDE(esp_rom_crc8_le = 0x40000760); PROVIDE(esp_rom_crc8_le = 0x40000760);
PROVIDE(esp_rom_md5_init = 0x4000074c);
PROVIDE(esp_rom_md5_update = 0x40000750);
PROVIDE(esp_rom_md5_final = 0x40000754);

View File

@ -1,13 +1,15 @@
//! `no_std` HAL for the ESP32-C6 from Espressif.
//!
//! Implements a number of the traits defined by the various packages in the
//! [embedded-hal] repository.
//!
//! [embedded-hal]: https://github.com/rust-embedded/embedded-hal
#![no_std] #![no_std]
#![doc(html_logo_url = "https://avatars.githubusercontent.com/u/46717278")] #![doc(html_logo_url = "https://avatars.githubusercontent.com/u/46717278")]
pub use embedded_hal as ehal;
#[cfg(feature = "embassy")]
pub use esp_hal_common::embassy;
pub use esp_hal_common::*; pub use esp_hal_common::*;
pub use self::gpio::IO;
/// Common module for analog functions /// Common module for analog functions
pub mod analog { pub mod analog {
pub use esp_hal_common::analog::{AvailableAnalog, SarAdcExt}; pub use esp_hal_common::analog::{AvailableAnalog, SarAdcExt};

View File

@ -49,6 +49,7 @@ sha2 = { version = "0.10.6", default-features = false}
smart-leds = "0.3.0" smart-leds = "0.3.0"
ssd1306 = "0.7.1" ssd1306 = "0.7.1"
static_cell = "1.0.0" static_cell = "1.0.0"
heapless = "0.7.16"
[features] [features]
default = ["rt", "vectored", "esp-hal-common/rv-zero-rtc-bss"] default = ["rt", "vectored", "esp-hal-common/rv-zero-rtc-bss"]

View File

@ -1,17 +1,17 @@
# esp32h2-hal # esp32h2-hal
<!-- [![Crates.io](https://img.shields.io/crates/v/esp32h2-hal?labelColor=1C2C2E&color=C96329&logo=Rust&style=flat-square)](https://crates.io/crates/esp32h2-hal) [![Crates.io](https://img.shields.io/crates/v/esp32h2-hal?labelColor=1C2C2E&color=C96329&logo=Rust&style=flat-square)](https://crates.io/crates/esp32h2-hal)
[![docs.rs](https://img.shields.io/docsrs/esp32h2-hal?labelColor=1C2C2E&color=C96329&logo=rust&style=flat-square)](https://docs.rs/esp32h2-hal) [![docs.rs](https://img.shields.io/docsrs/esp32h2-hal?labelColor=1C2C2E&color=C96329&logo=rust&style=flat-square)](https://docs.rs/esp32h2-hal)
![Crates.io](https://img.shields.io/crates/l/esp32h2-hal?labelColor=1C2C2E&style=flat-square) --> ![Crates.io](https://img.shields.io/crates/l/esp32h2-hal?labelColor=1C2C2E&style=flat-square)
[![Matrix](https://img.shields.io/matrix/esp-rs:matrix.org?label=join%20matrix&labelColor=1C2C2E&color=BEC5C9&logo=matrix&style=flat-square)](https://matrix.to/#/#esp-rs:matrix.org) [![Matrix](https://img.shields.io/matrix/esp-rs:matrix.org?label=join%20matrix&labelColor=1C2C2E&color=BEC5C9&logo=matrix&style=flat-square)](https://matrix.to/#/#esp-rs:matrix.org)
`no_std` HAL for the ESP32-H2 from Espressif. Implements a number of the traits defined by [embedded-hal](https://github.com/rust-embedded/embedded-hal). `no_std` HAL for the ESP32-H2 from Espressif. Implements a number of the traits defined by [embedded-hal](https://github.com/rust-embedded/embedded-hal).
This device uses the RISC-V ISA, which is officially supported by the Rust compiler via the `riscv32imac-unknown-none-elf` target. Refer to the [Getting Started](#getting-started) section below for more information. This device uses the RISC-V ISA, which is officially supported by the Rust compiler via the `riscv32imac-unknown-none-elf` target. Refer to the [Getting Started](#getting-started) section below for more information.
<!-- ## [Documentation] ## [Documentation]
[documentation]: https://docs.rs/esp32h2-hal/ --> [documentation]: https://docs.rs/esp32h2-hal/
## Getting Started ## Getting Started
@ -33,7 +33,7 @@ By default, [espflash](https://github.com/esp-rs/espflash) fetches the required
#### Direct Boot #### Direct Boot
Direct Boot allows an application stored in the External Flash to be executed directly, without being copied into Internal RAM. [Direct Boot](https://github.com/espressif/esp32c3-direct-boot-example#direct-boot-in-esp32-c3) allows an application stored in the External Flash to be executed directly, without being copied into Internal RAM.
##### Booting the Hello World example using Direct Boot ##### Booting the Hello World example using Direct Boot

View File

@ -9,7 +9,7 @@ use esp32h2_hal::{
clock::ClockControl, clock::ClockControl,
peripherals::Peripherals, peripherals::Peripherals,
prelude::*, prelude::*,
rom::crc, rom::{crc, md5},
timer::TimerGroup, timer::TimerGroup,
Rtc, Rtc,
Uart, Uart,
@ -49,6 +49,7 @@ fn main() -> ! {
timer0.start(1u64.secs()); timer0.start(1u64.secs());
let data = "123456789"; let data = "123456789";
let sentence = "The quick brown fox jumps over a lazy dog";
writeln!( writeln!(
uart0, uart0,
@ -75,10 +76,38 @@ fn main() -> ! {
assert_eq!(crc_rohc, 0xd0); assert_eq!(crc_rohc, 0xd0);
assert_eq!(crc_smbus, 0xf4); assert_eq!(crc_smbus, 0xf4);
// Hash the sentence one word at a time to *really* test the context
// Use Peekable while iter_intersperse is unstable
let mut md5_ctx = md5::Context::new();
let mut it = sentence.split_whitespace().peekable();
while let Some(word) = it.next() {
md5_ctx.consume(word);
if it.peek().is_some() {
md5_ctx.consume(" ");
}
}
let md5_digest = md5_ctx.compute();
assert_eq!(
md5_digest,
md5::Digest([
0x30, 0xde, 0xd8, 0x07, 0xd6, 0x5e, 0xe0, 0x37, 0x0f, 0xc6, 0xd7, 0x3d, 0x6a, 0xb5,
0x5a, 0x95
])
);
writeln!( writeln!(
uart0, uart0,
"{:08x} {:08x} {:08x} {:08x} {:04x} {:04x} {:02x} {:02x}", "{:08x} {:08x} {:08x} {:08x} {:04x} {:04x} {:02x} {:02x} {}",
crc_hdlc, crc_bzip2, crc_mpeg2, crc_cksum, crc_kermit, crc_genibus, crc_rohc, crc_smbus crc_hdlc,
crc_bzip2,
crc_mpeg2,
crc_cksum,
crc_kermit,
crc_genibus,
crc_rohc,
crc_smbus,
md5_digest
) )
.unwrap(); .unwrap();

Some files were not shown because too many files have changed in this diff Show More