Compare commits
28 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f15621244b | ||
|
|
d19e5aef54 | ||
|
|
27c0aa471f | ||
|
|
d8dbf520fb | ||
|
|
4e36d3b3b9 | ||
|
|
d255c4c4af | ||
|
|
559d00703d | ||
|
|
14823d669f | ||
|
|
9570a660a1 | ||
|
|
89c6f37c3f | ||
|
|
9f7565440a | ||
|
|
226bdc3038 | ||
|
|
d95be13c4d | ||
|
|
28fafa05e1 | ||
|
|
b5fe37e6e7 | ||
|
|
61b57e722e | ||
|
|
510dba03b4 | ||
|
|
0b26d3851c | ||
|
|
a72d292a74 | ||
|
|
c38ed67fb0 | ||
|
|
14f46371eb | ||
|
|
0c1d59b553 | ||
|
|
a4bc624e2d | ||
|
|
1cfc3eccb5 | ||
|
|
b51a5ed1fa | ||
|
|
8a958e92bc | ||
|
|
c0ef68115f | ||
|
|
978ae3c451 |
2
.github/workflows/ci.yml
vendored
2
.github/workflows/ci.yml
vendored
@ -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
16
.github/workflows/issue_handler.yml
vendored
Normal 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 }}
|
||||||
57
CHANGELOG.md
57
CHANGELOG.md
@ -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
|
||||||
|
|
||||||
|
|||||||
@ -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"]
|
||||||
|
|
||||||
|
|||||||
@ -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());
|
||||||
|
|||||||
@ -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",
|
||||||
|
|||||||
@ -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",
|
||||||
|
|||||||
@ -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",
|
||||||
|
|||||||
@ -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",
|
||||||
|
|||||||
@ -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",
|
||||||
]
|
]
|
||||||
|
|||||||
@ -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",
|
||||||
|
|||||||
@ -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",
|
||||||
|
|||||||
@ -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.
|
||||||
|
|||||||
@ -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
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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
|
||||||
}
|
}
|
||||||
@ -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
|
||||||
}
|
}
|
||||||
@ -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
|
||||||
}
|
}
|
||||||
@ -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 */
|
||||||
|
|||||||
@ -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
|
||||||
}
|
}
|
||||||
@ -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
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -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>] {}
|
||||||
|
|
||||||
|
|||||||
@ -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.
|
||||||
|
|||||||
@ -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 {}
|
||||||
|
|||||||
@ -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(
|
||||||
|
|||||||
@ -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,
|
||||||
|
|||||||
@ -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)
|
||||||
|
|||||||
@ -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 {}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,3 +1,5 @@
|
|||||||
|
//! Interrupt support
|
||||||
|
|
||||||
#[cfg(riscv)]
|
#[cfg(riscv)]
|
||||||
pub use riscv::*;
|
pub use riscv::*;
|
||||||
#[cfg(xtensa)]
|
#[cfg(xtensa)]
|
||||||
|
|||||||
@ -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.
|
||||||
|
|||||||
@ -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))?;
|
||||||
|
|||||||
@ -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 {
|
||||||
|
|||||||
@ -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},
|
||||||
|
|||||||
@ -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) => {
|
||||||
|
|||||||
@ -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::{
|
||||||
|
|||||||
@ -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>,
|
||||||
|
|||||||
@ -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;
|
||||||
|
|
||||||
|
|||||||
@ -1,3 +1,5 @@
|
|||||||
|
//! Hardware and Software Reset
|
||||||
|
|
||||||
use crate::rtc_cntl::SocResetReason;
|
use crate::rtc_cntl::SocResetReason;
|
||||||
|
|
||||||
pub enum SleepSource {
|
pub enum SleepSource {
|
||||||
|
|||||||
@ -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;
|
||||||
|
|||||||
232
esp-hal-common/src/rom/md5.rs
Normal file
232
esp-hal-common/src/rom/md5.rs
Normal 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
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -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 ) => {
|
||||||
|
|||||||
@ -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,
|
||||||
|
|||||||
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,3 +1,5 @@
|
|||||||
|
//! Secure Hash Algorithm peripheral driver
|
||||||
|
|
||||||
use core::convert::Infallible;
|
use core::convert::Infallible;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
|||||||
@ -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;
|
||||||
|
|||||||
@ -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;
|
||||||
|
|||||||
@ -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;
|
||||||
|
|||||||
@ -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;
|
||||||
|
|||||||
@ -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;
|
||||||
|
|||||||
@ -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,
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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;
|
||||||
|
|||||||
@ -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;
|
||||||
|
|||||||
@ -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
@ -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> {
|
||||||
|
|||||||
@ -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.
|
||||||
//!
|
//!
|
||||||
|
|||||||
@ -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;
|
||||||
|
|||||||
@ -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,
|
||||||
|
|||||||
@ -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();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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;
|
||||||
|
|
||||||
|
|||||||
@ -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"
|
||||||
|
|
||||||
|
|||||||
@ -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"]
|
||||||
|
|||||||
@ -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();
|
||||||
|
|
||||||
|
|||||||
@ -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| {
|
||||||
|
|||||||
@ -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| {
|
||||||
|
|||||||
@ -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>) {
|
||||||
|
|||||||
@ -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();
|
||||||
|
|||||||
@ -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);
|
||||||
|
|||||||
@ -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};
|
||||||
|
|||||||
@ -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"]
|
||||||
|
|||||||
@ -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();
|
||||||
|
|
||||||
|
|||||||
@ -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| {
|
||||||
|
|||||||
@ -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| {
|
||||||
|
|||||||
@ -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>) {
|
||||||
|
|||||||
@ -67,7 +67,7 @@ SECTIONS {
|
|||||||
*(.trap.*);
|
*(.trap.*);
|
||||||
} > RWTEXT
|
} > RWTEXT
|
||||||
}
|
}
|
||||||
INSERT AFTER .rwtext;
|
INSERT BEFORE .rwtext;
|
||||||
|
|
||||||
SECTIONS {
|
SECTIONS {
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -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;
|
||||||
|
|||||||
@ -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);
|
||||||
|
|||||||
@ -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};
|
||||||
|
|||||||
@ -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"]
|
||||||
|
|||||||
@ -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();
|
||||||
|
|
||||||
|
|||||||
@ -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| {
|
||||||
|
|||||||
@ -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| {
|
||||||
|
|||||||
@ -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>) {
|
||||||
|
|||||||
@ -67,7 +67,7 @@ SECTIONS {
|
|||||||
*(.trap.*);
|
*(.trap.*);
|
||||||
} > RWTEXT
|
} > RWTEXT
|
||||||
}
|
}
|
||||||
INSERT AFTER .rwtext;
|
INSERT BEFORE .rwtext;
|
||||||
|
|
||||||
SECTIONS {
|
SECTIONS {
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -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;
|
||||||
|
|||||||
@ -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.*);
|
||||||
|
|||||||
@ -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);
|
||||||
|
|||||||
@ -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 {
|
||||||
|
|||||||
@ -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"]
|
||||||
|
|||||||
@ -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
|
||||||
|
|
||||||
|
|||||||
@ -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();
|
||||||
|
|
||||||
|
|||||||
@ -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| {
|
||||||
|
|||||||
@ -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| {
|
||||||
|
|||||||
@ -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>) {
|
||||||
|
|||||||
@ -71,7 +71,7 @@ SECTIONS {
|
|||||||
*(.trap.*);
|
*(.trap.*);
|
||||||
} > RWTEXT
|
} > RWTEXT
|
||||||
}
|
}
|
||||||
INSERT AFTER .rwtext;
|
INSERT BEFORE .rwtext;
|
||||||
|
|
||||||
SECTIONS {
|
SECTIONS {
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -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;
|
||||||
|
|||||||
@ -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);
|
||||||
|
|||||||
@ -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};
|
||||||
|
|||||||
@ -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"]
|
||||||
|
|||||||
@ -1,17 +1,17 @@
|
|||||||
# esp32h2-hal
|
# esp32h2-hal
|
||||||
|
|
||||||
<!-- [](https://crates.io/crates/esp32h2-hal)
|
[](https://crates.io/crates/esp32h2-hal)
|
||||||
[](https://docs.rs/esp32h2-hal)
|
[](https://docs.rs/esp32h2-hal)
|
||||||
 -->
|

|
||||||
[](https://matrix.to/#/#esp-rs:matrix.org)
|
[](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
|
||||||
|
|
||||||
|
|||||||
@ -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
Loading…
Reference in New Issue
Block a user