Compare commits

...

28 Commits
main ... lld2

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

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

* Remove private type from I2s

* Remove redundant spi3 example, update examples

* Merge markdown sections

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

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

* README updates for ESP32-C6/H2

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

* Add embassy async read support for uart

* changes based on review

* fix CI failures

* change review #2

* fixed re-opened PR number

* changes review no.3

---------

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

* Add initial MD5 support

* Implement traits and add comments to MD5 module

* Add MD5 example to ESP32-C3

* Test MD5 context on the quick brown fox

* Implemenr From<Context> for Digest

* Add MD5 to the rest of the examples

* Add docs for MD5

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

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

* Apply fixes for db and mcuboot

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

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

* Add simple package-level documentation for each HAL package

* Clean up/simplify re-exports

* Fix the examples that I broke

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

* Update CHANGELOG

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

---------

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


Added the change to the Changelog


Fix: typo

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

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

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

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

View File

@ -313,6 +313,8 @@ jobs:
run: cd esp32s3-hal/ && cargo check --example=embassy_serial --features=embassy,embassy-time-timg0,async
- name: check esp32s3-hal (async, i2c)
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:
runs-on: ubuntu-latest

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

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

View File

@ -11,48 +11,41 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Added
- Add `WithDmaSpi3` to prelude for ESP32S3 (#623)
- 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 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)
- Add LEDC hardware fade support
- Add LEDC hardware fade support (#475)
- Added support for multicore async GPIO (#542)
- Add initial support for MCPWM in ESP32-H2 (#544)
- 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)
- Add a fn to poll DMA transfers (#559)
- 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)
- Add unified field-based efuse access
- Add `timer_interrupt` example in ESP32-H2 and refactor `clk_src` configuration (#576)
- Add unified field-based efuse access (#567)
- Move `esp-riscv-rt` into esp-hal (#578)
- Add initial implementation of radio clocks for ESP32-H2 (#577)
- 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 CRC functions from ESP ROM (#587)
- Add a `debug` feature to enable the PACs' `impl-register-debug` feature (#596)
- 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
- 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)
- 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
- Corrected the expected DMA descriptor counts (#622, #625)
- DMA is supported for SPI3 on ESP32-S3 (#507)
- `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)
@ -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)
- Sometimes half-duplex non-DMA SPI reads were reading garbage in non-release mode (#552)
- ESP32-C3: Fix GPIO5 ADC channel id (#562)
- ESP32-H2: Fix direct-boot feature
- ESP32-C6: Support FOSC CLK calibration for ECO1+ chip revisions
- ESP32-H2: Fix direct-boot feature (#570)
- ESP32-C6: Support FOSC CLK calibration for ECO1+ chip revisions (#593)
- Fixed CI by pinning the log crate to 0.4.18 (#600)
### Changed
- Improve examples documentation (#533)
- esp32h2-hal: added README (#585)
- ESP32-S3: Fix calculation of PSRAM start address
- 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)
- Fixed a possible overlap of `.data` and `.rwtext` (#616)
- Avoid SDA/SCL being low while configuring pins for I2C
### Breaking
- Simplified user-facing SpiDma and I2s types (#626)
- 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

View File

@ -43,7 +43,7 @@ riscv-atomic-emulation-trap = { version = "0.4.0", optional = true }
# Xtensa
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
ufmt-write = { version = "0.1.0", optional = true }
@ -82,6 +82,10 @@ psram_2m = []
psram_4m = []
psram_8m = []
opsram_2m = []
opsram_4m = []
opsram_8m = []
# Implement the `embedded-hal==1.0.0-alpha.x` traits
eh1 = ["embedded-hal-1", "embedded-hal-nb", "embedded-can"]

View File

@ -1,4 +1,8 @@
use std::{env, fs, path::PathBuf};
use std::{
env,
fs,
path::{Path, PathBuf},
};
use serde::Deserialize;
@ -144,13 +148,20 @@ fn main() {
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"))
&& (cfg!(feature = "psram_2m") || cfg!(feature = "psram_4m") || cfg!(feature = "psram_8m"))
{
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
// files:
let out = PathBuf::from(env::var_os("OUT_DIR").unwrap());
@ -169,10 +180,7 @@ fn main() {
gen_efuse_table(device_name, out);
}
fn copy_dir_all(
src: impl AsRef<std::path::Path>,
dst: impl AsRef<std::path::Path>,
) -> std::io::Result<()> {
fn copy_dir_all(src: impl AsRef<Path>, dst: impl AsRef<Path>) -> std::io::Result<()> {
fs::create_dir_all(&dst)?;
for entry in fs::read_dir(src)? {
let entry = entry?;
@ -186,10 +194,10 @@ fn copy_dir_all(
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};
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");
println!("cargo:rerun-if-changed={}", src_path.display());

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -2,7 +2,7 @@
SECTIONS {
.rodata_dummy (NOLOAD) :
.rodata_dummy (NOLOAD) : ALIGN(4)
{
/* This dummy section represents the .flash.text section but in RODATA.
* 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 */
. = SIZEOF(.text);
. = . + SIZEOF(.text);
/* Prepare the alignment of the section above. Few bytes (0x20) must be
* added for the mapping header.

View File

@ -4,10 +4,10 @@
*/
SECTIONS {
.rtc_fast.dummy (NOLOAD) :
.rtc_fast.dummy (NOLOAD) : ALIGN(4)
{
_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_FAST_RWDATA
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -9,8 +9,15 @@ use crate::{
macro_rules! impl_channel {
($num: literal) => {
paste::paste! {
#[non_exhaustive]
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>] {
fn init_channel() {
// nothing special to be done here
@ -365,6 +372,7 @@ macro_rules! impl_channel {
}
}
#[non_exhaustive]
pub struct [<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>] {}
impl<'a> RxChannel<[<Channel $num>]> for [<Channel $num RxImpl>] {
@ -385,19 +394,21 @@ macro_rules! impl_channel {
}
}
#[non_exhaustive]
pub struct [<ChannelCreator $num>] {}
impl [<ChannelCreator $num>] {
/// 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>(
self,
burst_mode: bool,
tx_descriptors: &'a mut [u32],
rx_descriptors: &'a mut [u32],
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>] {};
tx_impl.init(burst_mode, priority);
@ -431,11 +442,11 @@ macro_rules! impl_channel {
Channel {
tx: tx_channel,
rx: rx_channel,
_phantom: PhantomData::default(),
}
}
}
#[non_exhaustive]
pub struct [<SuitablePeripheral $num>] {}
impl PeripheralMarker for [<SuitablePeripheral $num>] {}

View File

@ -1,6 +1,7 @@
//! 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};
@ -347,7 +348,7 @@ where
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);
}
@ -647,7 +648,7 @@ where
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);
}
@ -829,16 +830,20 @@ pub trait RegisterAccess {
fn unlisten_in_eof();
fn unlisten_out_eof();
}
pub trait ChannelTypes {
type P: PeripheralMarker;
type Tx<'a>: Tx;
type Rx<'a>: Rx;
}
/// DMA Channel
pub struct Channel<TX, RX, P>
pub struct Channel<'d, C>
where
TX: Tx,
RX: Rx,
P: PeripheralMarker,
C: ChannelTypes,
{
pub(crate) tx: TX,
pub(crate) rx: RX,
_phantom: PhantomData<P>,
pub(crate) tx: C::Tx<'d>,
pub(crate) rx: C::Rx<'d>,
}
/// Trait to be implemented for an in progress dma transfer.

View File

@ -9,8 +9,15 @@ use crate::{
macro_rules! ImplSpiChannel {
($num: literal) => {
paste::paste! {
#[non_exhaustive]
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>] {
fn init_channel() {
// (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>] {}
impl<'a> TxChannel<[<Spi $num DmaChannel>]> for [<Spi $num DmaChannelTxImpl>] {
@ -205,6 +213,7 @@ macro_rules! ImplSpiChannel {
}
}
#[non_exhaustive]
pub struct [<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>] {}
impl [<Spi $num DmaChannelCreator>] {
/// 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>(
self,
burst_mode: bool,
tx_descriptors: &'a mut [u32],
rx_descriptors: &'a mut [u32],
priority: DmaPriority,
) -> Channel<
ChannelTx<'a,[<Spi $num DmaChannelTxImpl>], [<Spi $num DmaChannel>]>,
ChannelRx<'a,[<Spi $num DmaChannelRxImpl>], [<Spi $num DmaChannel>]>,
[<Spi $num DmaSuitablePeripheral>],
> {
) -> Channel<'a, [<Spi $num DmaChannel>]> {
let mut tx_impl = [<Spi $num DmaChannelTxImpl>] {};
tx_impl.init(burst_mode, priority);
@ -265,7 +272,6 @@ macro_rules! ImplSpiChannel {
Channel {
tx: tx_channel,
rx: rx_channel,
_phantom: PhantomData::default(),
}
}
}
@ -278,6 +284,12 @@ macro_rules! ImplI2sChannel {
paste::paste! {
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>] {
fn init_channel() {
// nothing to do
@ -458,18 +470,15 @@ macro_rules! ImplI2sChannel {
impl [<I2s $num DmaChannelCreator>] {
/// 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>(
self,
burst_mode: bool,
tx_descriptors: &'a mut [u32],
rx_descriptors: &'a mut [u32],
priority: DmaPriority,
) -> Channel<
ChannelTx<'a,[<I2s $num DmaChannelTxImpl>], [<I2s $num DmaChannel>]>,
ChannelRx<'a,[<I2s $num DmaChannelRxImpl>], [<I2s $num DmaChannel>]>,
[<I2s $num DmaSuitablePeripheral>],
> {
) -> Channel<'a, [<I2s $num DmaChannel>]> {
let mut tx_impl = [<I2s $num DmaChannelTxImpl>] {};
tx_impl.init(burst_mode, priority);
@ -503,7 +512,6 @@ macro_rules! ImplI2sChannel {
Channel {
tx: tx_channel,
rx: rx_channel,
_phantom: PhantomData::default(),
}
}
}
@ -511,11 +519,13 @@ macro_rules! ImplI2sChannel {
};
}
#[non_exhaustive]
pub struct Spi2DmaSuitablePeripheral {}
impl PeripheralMarker for Spi2DmaSuitablePeripheral {}
impl SpiPeripheral for Spi2DmaSuitablePeripheral {}
impl Spi2Peripheral for Spi2DmaSuitablePeripheral {}
#[non_exhaustive]
pub struct Spi3DmaSuitablePeripheral {}
impl PeripheralMarker for Spi3DmaSuitablePeripheral {}
impl SpiPeripheral for Spi3DmaSuitablePeripheral {}
@ -524,6 +534,7 @@ impl Spi3Peripheral for Spi3DmaSuitablePeripheral {}
ImplSpiChannel!(2);
ImplSpiChannel!(3);
#[non_exhaustive]
pub struct I2s0DmaSuitablePeripheral {}
impl PeripheralMarker for I2s0DmaSuitablePeripheral {}
impl I2sPeripheral for I2s0DmaSuitablePeripheral {}
@ -531,6 +542,7 @@ impl I2s0Peripheral for I2s0DmaSuitablePeripheral {}
ImplI2sChannel!(0, "I2S0");
#[non_exhaustive]
pub struct I2s1DmaSuitablePeripheral {}
impl PeripheralMarker for I2s1DmaSuitablePeripheral {}
impl I2sPeripheral for I2s1DmaSuitablePeripheral {}

View File

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

View File

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

View File

@ -250,7 +250,10 @@ where
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()
.enable_input(true)
.internal_pull_up(true)

View File

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

View File

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

View File

@ -69,7 +69,8 @@ pub enum InterruptKind {
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.
/// `interrupt3`)
#[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) {
unsafe {
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
/// default). Avoid interrupts 1 - 15 when interrupt vectoring is enabled.

View File

@ -7,6 +7,7 @@ use crate::{
};
/// Enumeration of available CPU interrupts
///
/// It's possible to create one handler per priority level. (e.g
/// `level1_interrupt`)
#[allow(unused)]
@ -47,7 +48,7 @@ pub enum CpuInterrupt {
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
/// 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);
}
/// Disable the given peripheral interrupt.
/// Disable the given peripheral interrupt
pub fn disable(core: Cpu, interrupt: Interrupt) {
unsafe {
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> {
let cpu_interrupt =
interrupt_level_to_cpu_interrupt(level, chip_specific::interrupt_is_edge(interrupt))?;

View File

@ -50,8 +50,8 @@ pub use self::delay::Delay;
pub use self::dma::gdma;
#[cfg(pdma)]
pub use self::dma::pdma;
#[cfg(any(dport, interrupt_core0, interrupt_core1))]
pub use self::interrupt::*;
#[cfg(gpio)]
pub use self::gpio::IO;
#[cfg(rmt)]
pub use self::pulse_control::PulseControl;
#[cfg(rng)]
@ -63,6 +63,8 @@ pub use self::soc::cpu_control;
#[cfg(efuse)]
pub use self::soc::efuse;
pub use self::soc::peripherals;
#[cfg(psram)]
pub use self::soc::psram;
#[cfg(any(spi0, spi1, spi2, spi3))]
pub use self::spi::Spi;
#[cfg(any(timg0, timg1))]
@ -117,7 +119,6 @@ pub mod rsa;
pub mod rtc_cntl;
#[cfg(sha)]
pub mod sha;
pub mod soc;
#[cfg(any(spi0, spi1, spi2, spi3))]
pub mod spi;
#[cfg(any(dport, pcr, system))]
@ -141,6 +142,10 @@ pub mod 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]
extern "C" fn EspDefaultHandler(_level: u32, _interrupt: peripherals::Interrupt) {}
@ -148,16 +153,8 @@ extern "C" fn EspDefaultHandler(_level: u32, _interrupt: peripherals::Interrupt)
#[no_mangle]
extern "C" fn DefaultHandler() {}
#[cfg(esp32c6)]
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
/// Available CPU cores
///
/// The actual number of available cores depends on the target.
#[derive(Debug, PartialEq, Eq)]
pub enum Cpu {
@ -168,6 +165,7 @@ pub enum Cpu {
AppCpu,
}
/// Which core the application is currently executing on
pub fn get_core() -> Cpu {
#[cfg(all(xtensa, multi_core))]
match ((xtensa_lx::get_processor_id() >> 13) & 1) != 0 {

View File

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

View File

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

View File

@ -70,7 +70,7 @@ pub use crate::pulse_control::{
};
#[cfg(radio)]
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;
#[cfg(any(spi0, spi1, spi2, spi3))]
pub use crate::spi::{

View File

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

View File

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

View File

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

View File

@ -8,11 +8,11 @@
//!
//! The ROM provides the following polynomials for each CRC width:
//!
//! | CRC Width | Polynomial |
//! | --------- | ---------- |
//! | CRC-8 | 0x07 |
//! | CRC-16 | 0x1021 |
//! | CRC-32 | 0x0411db7 |
//! | CRC Width | Polynomial |
//! | --------- | ----------- |
//! | CRC-8 | 0x07 |
//! | CRC-16 | 0x1021 |
//! | CRC-32 | 0x04c11db7 |
//!
//! The "big-endian" `*_be()` functions are left-shifting algorithms to be used
//! when input and output reflection are **not** needed. If input and output
@ -37,26 +37,35 @@
//! <https://reveng.sourceforge.io/crc-catalogue/all.htm>
//!
//! CRC-32/ISO-HDLC poly=0x04c11db7 init=0xffffffff refin=true refout=true
//! xorout=0xffffffff ```
//! xorout=0xffffffff
//!
//! ```
//! let crc = crc32_le(!0xffffffff, &data);
//! ```
//!
//!
//! CRC-32/BZIP2 poly=0x04c11db7 init=0xffffffff refin=false refout=false
//! xorout=0xffffffff ```
//! xorout=0xffffffff
//!
//! ```
//! let crc = crc32_be(!0xffffffff, &data);
//! ```
//!
//! CRC-32/MPEG-2 poly=0x04c11db7 init=0xffffffff refin=false refout=false
//! xorout=0x00000000 ```
//! xorout=0x00000000
//!
//! ```
//! let crc = !crc32_be(!0xffffffff, &data);
//! ```
//!
//!
//! CRC-32/CKSUM poly=0x04c11db7 init=0x00000000 refin=false refout=false
//! xorout=0xffffffff ```
//! xorout=0xffffffff
//!
//! ```
//! let crc = crc32_be(!0, &data);
//! ```
//!
//! CRC-16/KERMIT poly=0x1021 init=0x0000 refin=true refout=true xorout=0x0000
//!
//! ```
//! let crc = !crc16_le(!0, &data);
//! ```
@ -65,7 +74,7 @@
// needed to access them, they are all referentially transparent, and the size
// 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)]
#[inline(always)]
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) }
}
/// Right-shifting CRC-32 with polynomial 0x0411db7
/// Right-shifting CRC-32 with polynomial 0x04c11db7
#[cfg(rom_crc_le)]
#[inline(always)]
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
];
/// Left-shifting CRC-32 with polynomial 0x0411db7
/// Left-shifting CRC-32 with polynomial 0x04c11db7
#[cfg(not(rom_crc_be))]
pub fn crc32_be(crc: u32, buf: &[u8]) -> u32 {
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
];
/// Right-shifting CRC-32 with polynomial 0x0411db7
/// Right-shifting CRC-32 with polynomial 0x04c11db7
#[cfg(not(rom_crc_le))]
pub fn crc32_le(crc: u32, buf: &[u8]) -> u32 {
let mut crc = !crc;

View File

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

View File

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

View File

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

View File

@ -646,6 +646,8 @@ impl RtcClock {
let minor: u8 = Efuse::read_field_le(WAFER_VERSION_MINOR);
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.
// So we need to divide the calibrate cycles of the FOSC for ECO1 and above
// 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)
if (major * 100 + minor) > 0 {
if cal_clk == RtcCalSel::RtcCalRcFast {
let slowclk_cycles = slowclk_cycles >> 5;
slowclk_cycles >>= 5;
}
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

File diff suppressed because it is too large Load Diff

View File

@ -411,6 +411,7 @@ pub trait HalfDuplexReadWrite {
) -> Result<(), Self::Error>;
}
/// SPI peripheral driver
pub struct Spi<'d, T, M> {
spi: PeripheralRef<'d, T>,
_mode: PhantomData<M>,
@ -752,42 +753,48 @@ pub mod dma {
use crate::dma::Spi3Peripheral;
use crate::{
clock::Clocks,
dma::{Channel, DmaTransfer, DmaTransferRxTx, Rx, Spi2Peripheral, SpiPeripheral, Tx},
dma::{
Channel,
ChannelTypes,
DmaTransfer,
DmaTransferRxTx,
RxPrivate,
Spi2Peripheral,
SpiPeripheral,
TxPrivate,
},
peripheral::PeripheralRef,
};
pub trait WithDmaSpi2<'d, T, RX, TX, P, M>
pub trait WithDmaSpi2<'d, T, C, M>
where
T: Instance + Spi2Instance,
TX: Tx,
RX: Rx,
P: SpiPeripheral,
C: ChannelTypes,
C::P: SpiPeripheral,
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))]
pub trait WithDmaSpi3<'d, T, RX, TX, P, M>
pub trait WithDmaSpi3<'d, T, C, M>
where
T: Instance + Spi3Instance,
TX: Tx,
RX: Rx,
P: SpiPeripheral,
C: ChannelTypes,
C::P: SpiPeripheral,
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
T: Instance + Spi2Instance,
TX: Tx,
RX: Rx,
P: SpiPeripheral + Spi2Peripheral,
C: ChannelTypes,
C::P: SpiPeripheral + Spi2Peripheral,
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
SpiDma {
@ -799,51 +806,47 @@ pub mod dma {
}
#[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
T: Instance + Spi3Instance,
TX: Tx,
RX: Rx,
P: SpiPeripheral + Spi3Peripheral,
C: ChannelTypes,
C::P: SpiPeripheral + Spi3Peripheral,
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
SpiDma {
spi: self.spi,
channel,
_mode: PhantomData::default(),
_mode: PhantomData,
}
}
}
/// 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
T: InstanceDma<TX, RX>,
TX: Tx,
RX: Rx,
P: SpiPeripheral,
T: InstanceDma<C::Tx<'d>, C::Rx<'d>>,
C: ChannelTypes,
C::P: SpiPeripheral,
M: DuplexMode,
{
spi_dma: SpiDma<'d, T, TX, RX, P, M>,
spi_dma: SpiDma<'d, T, C, M>,
rbuffer: RBUFFER,
tbuffer: TBUFFER,
}
impl<'d, T, TX, RX, P, RXBUF, TXBUF, M>
DmaTransferRxTx<RXBUF, TXBUF, SpiDma<'d, T, TX, RX, P, M>>
for SpiDmaTransferRxTx<'d, T, TX, RX, P, RXBUF, TXBUF, M>
impl<'d, T, C, RXBUF, TXBUF, M> DmaTransferRxTx<RXBUF, TXBUF, SpiDma<'d, T, C, M>>
for SpiDmaTransferRxTx<'d, T, C, RXBUF, TXBUF, M>
where
T: InstanceDma<TX, RX>,
TX: Tx,
RX: Rx,
P: SpiPeripheral,
T: InstanceDma<C::Tx<'d>, C::Rx<'d>>,
C: ChannelTypes,
C::P: SpiPeripheral,
M: DuplexMode,
{
/// Wait for the DMA transfer to complete and return the buffers and the
/// 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
// `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
for SpiDmaTransferRxTx<'d, T, TX, RX, P, RXBUF, TXBUF, M>
impl<'d, T, C, RXBUF, TXBUF, M> Drop for SpiDmaTransferRxTx<'d, T, C, RXBUF, TXBUF, M>
where
T: InstanceDma<TX, RX>,
TX: Tx,
RX: Rx,
P: SpiPeripheral,
T: InstanceDma<C::Tx<'d>, C::Rx<'d>>,
C: ChannelTypes,
C::P: SpiPeripheral,
M: DuplexMode,
{
fn drop(&mut self) {
@ -884,30 +885,28 @@ pub mod dma {
}
/// An in-progress DMA transfer.
pub struct SpiDmaTransfer<'d, T, TX, RX, P, BUFFER, M>
pub struct SpiDmaTransfer<'d, T, C, BUFFER, M>
where
T: InstanceDma<TX, RX>,
TX: Tx,
RX: Rx,
P: SpiPeripheral,
T: InstanceDma<C::Tx<'d>, C::Rx<'d>>,
C: ChannelTypes,
C::P: SpiPeripheral,
M: DuplexMode,
{
spi_dma: SpiDma<'d, T, TX, RX, P, M>,
spi_dma: SpiDma<'d, T, C, M>,
buffer: BUFFER,
}
impl<'d, T, TX, RX, P, BUFFER, M> DmaTransfer<BUFFER, SpiDma<'d, T, TX, RX, P, M>>
for SpiDmaTransfer<'d, T, TX, RX, P, BUFFER, M>
impl<'d, T, C, BUFFER, M> DmaTransfer<BUFFER, SpiDma<'d, T, C, M>>
for SpiDmaTransfer<'d, T, C, BUFFER, M>
where
T: InstanceDma<TX, RX>,
TX: Tx,
RX: Rx,
P: SpiPeripheral,
T: InstanceDma<C::Tx<'d>, C::Rx<'d>>,
C: ChannelTypes,
C::P: SpiPeripheral,
M: DuplexMode,
{
/// Wait for the DMA transfer to complete and return the buffers and the
/// 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
// `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
T: InstanceDma<TX, RX>,
TX: Tx,
RX: Rx,
P: SpiPeripheral,
T: InstanceDma<C::Tx<'d>, C::Rx<'d>>,
C: ChannelTypes,
C::P: SpiPeripheral,
M: DuplexMode,
{
fn drop(&mut self) {
@ -946,24 +944,22 @@ pub mod dma {
}
/// A DMA capable SPI instance.
pub struct SpiDma<'d, T, TX, RX, P, M>
pub struct SpiDma<'d, T, C, M>
where
TX: Tx,
RX: Rx,
P: SpiPeripheral,
C: ChannelTypes,
C::P: SpiPeripheral,
M: DuplexMode,
{
pub(crate) spi: PeripheralRef<'d, T>,
pub(crate) channel: Channel<TX, RX, P>,
pub(crate) channel: Channel<'d, C>,
_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
T: InstanceDma<TX, RX>,
TX: Tx,
RX: Rx,
P: SpiPeripheral,
T: InstanceDma<C::Tx<'d>, C::Rx<'d>>,
C: ChannelTypes,
C::P: SpiPeripheral,
M: DuplexMode,
{
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
T: InstanceDma<TX, RX>,
TX: Tx,
RX: Rx,
P: SpiPeripheral,
T: InstanceDma<C::Tx<'d>, C::Rx<'d>>,
C: ChannelTypes,
C::P: SpiPeripheral,
M: IsFullDuplex,
{
/// Perform a DMA write.
@ -987,7 +982,7 @@ pub mod dma {
pub fn dma_write<TXBUF>(
mut self,
words: TXBUF,
) -> Result<SpiDmaTransfer<'d, T, TX, RX, P, TXBUF, M>, super::Error>
) -> Result<SpiDmaTransfer<'d, T, C, TXBUF, M>, super::Error>
where
TXBUF: ReadBuffer<Word = u8>,
{
@ -1013,7 +1008,7 @@ pub mod dma {
pub fn dma_read<RXBUF>(
mut self,
mut words: RXBUF,
) -> Result<SpiDmaTransfer<'d, T, TX, RX, P, RXBUF, M>, super::Error>
) -> Result<SpiDmaTransfer<'d, T, C, RXBUF, M>, super::Error>
where
RXBUF: WriteBuffer<Word = u8>,
{
@ -1040,7 +1035,7 @@ pub mod dma {
mut self,
words: TXBUF,
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
TXBUF: ReadBuffer<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
T: InstanceDma<TX, RX>,
TX: Tx,
RX: Rx,
P: SpiPeripheral,
T: InstanceDma<C::Tx<'d>, C::Rx<'d>>,
C: ChannelTypes,
C::P: SpiPeripheral,
M: IsHalfDuplex,
{
pub fn read<RXBUF>(
@ -1083,7 +1077,7 @@ pub mod dma {
address: Address,
dummy: u8,
mut buffer: RXBUF,
) -> Result<SpiDmaTransfer<'d, T, TX, RX, P, RXBUF, M>, super::Error>
) -> Result<SpiDmaTransfer<'d, T, C, RXBUF, M>, super::Error>
where
RXBUF: WriteBuffer<Word = u8>,
{
@ -1156,7 +1150,7 @@ pub mod dma {
address: Address,
dummy: u8,
buffer: TXBUF,
) -> Result<SpiDmaTransfer<'d, T, TX, RX, P, TXBUF, M>, super::Error>
) -> Result<SpiDmaTransfer<'d, T, C, TXBUF, M>, super::Error>
where
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
T: InstanceDma<TX, RX>,
TX: Tx,
RX: Rx,
P: SpiPeripheral,
T: InstanceDma<C::Tx<'d>, C::Rx<'d>>,
C: ChannelTypes,
C::P: SpiPeripheral,
M: IsFullDuplex,
{
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
T: InstanceDma<TX, RX>,
TX: Tx,
RX: Rx,
P: SpiPeripheral,
T: InstanceDma<C::Tx<'d>, C::Rx<'d>>,
C: ChannelTypes,
C::P: SpiPeripheral,
M: IsFullDuplex,
{
type Error = super::Error;
@ -1260,12 +1252,11 @@ pub mod dma {
mod asynch {
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
T: InstanceDma<TX, RX>,
TX: Tx,
RX: Rx,
P: SpiPeripheral,
T: InstanceDma<C::Tx<'d>, C::Rx<'d>>,
C: ChannelTypes,
C::P: SpiPeripheral,
M: IsFullDuplex,
{
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
T: InstanceDma<TX, RX>,
TX: Tx,
RX: Rx,
P: SpiPeripheral,
T: InstanceDma<C::Tx<'d>, C::Rx<'d>>,
C: ChannelTypes,
C::P: SpiPeripheral,
M: IsFullDuplex,
{
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
T: InstanceDma<TX, RX>,
TX: Tx,
RX: Rx,
P: SpiPeripheral,
T: InstanceDma<C::Tx<'d>, C::Rx<'d>>,
C: ChannelTypes,
C::P: SpiPeripheral,
M: IsFullDuplex,
{
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
T: InstanceDma<TX, RX>,
TX: Tx,
RX: Rx,
P: SpiPeripheral,
T: InstanceDma<C::Tx<'d>, C::Rx<'d>>,
C: ChannelTypes,
C::P: SpiPeripheral,
M: IsFullDuplex,
{
async fn transfer<'a>(
@ -1406,28 +1394,23 @@ pub mod dma {
use embedded_hal_1::spi::{SpiBus, SpiBusFlush, SpiBusRead, SpiBusWrite};
use super::{super::InstanceDma, SpiDma, SpiPeripheral};
use crate::{
dma::{Rx, Tx},
spi::IsFullDuplex,
};
use crate::{dma::ChannelTypes, 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
T: InstanceDma<TX, RX>,
TX: Tx,
RX: Rx,
P: SpiPeripheral,
T: InstanceDma<C::Tx<'d>, C::Rx<'d>>,
C: ChannelTypes,
C::P: SpiPeripheral,
M: IsFullDuplex,
{
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
T: InstanceDma<TX, RX>,
TX: Tx,
RX: Rx,
P: SpiPeripheral,
T: InstanceDma<C::Tx<'d>, C::Rx<'d>>,
C: ChannelTypes,
C::P: SpiPeripheral,
M: IsFullDuplex,
{
/// 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
T: InstanceDma<TX, RX>,
TX: Tx,
RX: Rx,
P: SpiPeripheral,
T: InstanceDma<C::Tx<'d>, C::Rx<'d>>,
C: ChannelTypes,
C::P: SpiPeripheral,
M: IsFullDuplex,
{
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
T: InstanceDma<TX, RX>,
TX: Tx,
RX: Rx,
P: SpiPeripheral,
T: InstanceDma<C::Tx<'d>, C::Rx<'d>>,
C: ChannelTypes,
C::P: SpiPeripheral,
M: IsFullDuplex,
{
/// 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
T: InstanceDma<TX, RX>,
TX: Tx,
RX: Rx,
P: SpiPeripheral,
T: InstanceDma<C::Tx<'d>, C::Rx<'d>>,
C: ChannelTypes,
C::P: SpiPeripheral,
M: IsFullDuplex,
{
fn flush(&mut self) -> Result<(), Self::Error> {

View File

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

View File

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

View File

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

View File

@ -19,7 +19,10 @@ const UART_FIFO_SIZE: u16 = 128;
/// Custom serial error type
#[derive(Debug)]
pub enum Error {}
pub enum Error {
#[cfg(feature = "async")]
ReadBufferFull,
}
/// UART configuration
pub mod config {
@ -994,11 +997,15 @@ mod asynch {
use core::task::Poll;
use cfg_if::cfg_if;
use embassy_futures::select::select;
use embassy_sync::waitqueue::AtomicWaker;
use procmacros::interrupt;
use super::{Error, Instance};
use crate::{uart::UART_FIFO_SIZE, Uart};
use crate::{
uart::{RegisterBlock, UART_FIFO_SIZE},
Uart,
};
cfg_if! {
if #[cfg(all(uart0, uart1, uart2))] {
@ -1016,6 +1023,8 @@ mod asynch {
pub(crate) enum Event {
TxDone,
TxFiFoEmpty,
RxFifoFull,
RxCmdCharDetected,
}
pub(crate) struct UartFuture<'a, T: Instance> {
@ -1034,6 +1043,14 @@ mod asynch {
.register_block()
.int_ena
.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 }
@ -1055,6 +1072,20 @@ mod asynch {
.read()
.txfifo_empty_int_ena()
.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
T: Instance,
{
async fn write(&mut self, words: &[u8]) -> Result<(), Error> {
for chunk in words.chunks(UART_FIFO_SIZE as usize) {
for &byte in chunk {
self.write_byte(byte).unwrap() // should never fail
pub async fn read(&mut self, buf: &mut [u8]) -> Result<usize, Error> {
let mut read_bytes = 0;
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;
}
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)]
#[interrupt]
fn UART0() {
let uart = unsafe { &*crate::peripherals::UART0::ptr() };
uart.int_ena.modify(|_, w| {
w.txfifo_empty_int_ena()
.clear_bit()
.tx_done_int_ena()
.clear_bit()
});
WAKERS[0].wake();
if intr_handler(uart) {
WAKERS[0].wake();
}
}
#[cfg(uart1)]
#[interrupt]
fn UART1() {
let uart = unsafe { &*crate::peripherals::UART1::ptr() };
uart.int_ena.modify(|_, w| {
w.txfifo_empty_int_ena()
.clear_bit()
.tx_done_int_ena()
.clear_bit()
});
WAKERS[1].wake();
if intr_handler(uart) {
WAKERS[1].wake();
}
}
#[cfg(uart2)]
#[interrupt]
fn UART2() {
let uart = unsafe { &*crate::peripherals::UART2::ptr() };
uart.int_ena.modify(|_, w| {
w.txfifo_empty_int_ena()
.clear_bit()
.tx_done_int_ena()
.clear_bit()
});
WAKERS[2].wake();
if intr_handler(uart) {
WAKERS[2].wake();
}
}
}

View File

@ -1,3 +1,5 @@
//! USB Serial JTAG peripheral driver
use core::convert::Infallible;
use crate::{
@ -6,6 +8,7 @@ use crate::{
system::PeripheralClockControl,
};
/// USB Serial JTAG driver
pub struct UsbSerialJtag<'d> {
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 {
fn register_block(&self) -> &RegisterBlock;

View File

@ -3,8 +3,13 @@ runner = "espflash flash --monitor"
[build]
rustflags = [
"-C", "link-arg=-nostartfiles",
"-C", "link-arg=-Wl,-Tlinkall.x",
# GNU LD
# "-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"

View File

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

View File

@ -9,7 +9,7 @@ use esp32_hal::{
clock::ClockControl,
peripherals::Peripherals,
prelude::*,
rom::crc,
rom::{crc, md5},
timer::TimerGroup,
Rtc,
Uart,
@ -40,6 +40,7 @@ fn main() -> ! {
timer0.start(1u64.secs());
let data = "123456789";
let sentence = "The quick brown fox jumps over a lazy dog";
writeln!(
serial0,
@ -66,10 +67,38 @@ fn main() -> ! {
assert_eq!(crc_rohc, 0xd0);
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!(
serial0,
"{:08x} {:08x} {:08x} {:08x} {:04x} {:04x} {:02x} {:02x}",
crc_hdlc, crc_bzip2, crc_mpeg2, crc_cksum, crc_kermit, crc_genibus, crc_rohc, crc_smbus
"{:08x} {:08x} {:08x} {:08x} {:04x} {:04x} {:02x} {:02x} {}",
crc_hdlc,
crc_bzip2,
crc_mpeg2,
crc_cksum,
crc_kermit,
crc_genibus,
crc_rohc,
crc_smbus,
md5_digest
)
.unwrap();

View File

@ -20,10 +20,10 @@ use esp32_hal::{
clock::ClockControl,
embassy,
i2c::I2C,
interrupt,
peripherals::{Interrupt, Peripherals, I2C0},
prelude::*,
timer::TimerGroup,
Priority,
Rtc,
IO,
};
@ -77,7 +77,7 @@ fn main() -> ! {
&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());
executor.run(|spawner| {

View File

@ -1,17 +1,20 @@
//! embassy serial
//!
//! This is an example of running the embassy executor and asynchronously
//! writing to a uart.
//! writing to and reading from uart
#![no_std]
#![no_main]
#![feature(type_alias_impl_trait)]
use core::fmt::Write;
use embassy_executor::Executor;
use embassy_time::{Duration, Timer};
use embassy_time::{with_timeout, Duration};
use esp32_hal::{
clock::ClockControl,
embassy,
interrupt,
peripherals::{Interrupt, Peripherals, UART0},
prelude::*,
timer::TimerGroup,
@ -19,18 +22,79 @@ use esp32_hal::{
Uart,
};
use esp_backtrace as _;
use esp_hal_common::uart::config::AtCmdConfig;
use heapless::Vec;
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]
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 {
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
.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)
.await
.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")]
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());
executor.run(|spawner| {

View File

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

View File

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

View File

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

View File

@ -1,13 +1,15 @@
//! `no_std` HAL for the ESP32 from Espressif.
//!
//! Implements a number of the traits defined by the various packages in the
//! [embedded-hal] repository.
//!
//! [embedded-hal]: https://github.com/rust-embedded/embedded-hal
#![no_std]
#![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 self::gpio::IO;
/// Common module for analog functions
pub mod analog {
pub use esp_hal_common::analog::{AvailableAnalog, SensExt};

View File

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

View File

@ -9,7 +9,7 @@ use esp32c2_hal::{
clock::ClockControl,
peripherals::Peripherals,
prelude::*,
rom::crc,
rom::{crc, md5},
timer::TimerGroup,
Rtc,
Uart,
@ -41,6 +41,7 @@ fn main() -> ! {
timer0.start(1u64.secs());
let data = "123456789";
let sentence = "The quick brown fox jumps over a lazy dog";
writeln!(
serial0,
@ -67,10 +68,38 @@ fn main() -> ! {
assert_eq!(crc_rohc, 0xd0);
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!(
serial0,
"{:08x} {:08x} {:08x} {:08x} {:04x} {:04x} {:02x} {:02x}",
crc_hdlc, crc_bzip2, crc_mpeg2, crc_cksum, crc_kermit, crc_genibus, crc_rohc, crc_smbus
"{:08x} {:08x} {:08x} {:08x} {:04x} {:04x} {:02x} {:02x} {}",
crc_hdlc,
crc_bzip2,
crc_mpeg2,
crc_cksum,
crc_kermit,
crc_genibus,
crc_rohc,
crc_smbus,
md5_digest
)
.unwrap();

View File

@ -20,10 +20,10 @@ use esp32c2_hal::{
clock::ClockControl,
embassy,
i2c::I2C,
interrupt,
peripherals::{Interrupt, Peripherals, I2C0},
prelude::*,
timer::TimerGroup,
Priority,
Rtc,
IO,
};
@ -85,7 +85,7 @@ fn main() -> ! {
&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());
executor.run(|spawner| {

View File

@ -1,17 +1,20 @@
//! embassy serial
//!
//! This is an example of running the embassy executor and asynchronously
//! writing to a uart.
//! writing to and reading from uart
#![no_std]
#![no_main]
#![feature(type_alias_impl_trait)]
use core::fmt::Write;
use embassy_executor::Executor;
use embassy_time::{Duration, Timer};
use embassy_time::{with_timeout, Duration};
use esp32c2_hal::{
clock::ClockControl,
embassy,
interrupt,
peripherals::{Interrupt, Peripherals, UART0},
prelude::*,
timer::TimerGroup,
@ -19,18 +22,79 @@ use esp32c2_hal::{
Uart,
};
use esp_backtrace as _;
use esp_hal_common::uart::config::AtCmdConfig;
use heapless::Vec;
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]
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 {
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
.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)
.await
.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")]
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());
executor.run(|spawner| {

View File

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

View File

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

View File

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

View File

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

View File

@ -1,13 +1,15 @@
//! `no_std` HAL for the ESP32-C2/ESP8684 from Espressif.
//!
//! Implements a number of the traits defined by the various packages in the
//! [embedded-hal] repository.
//!
//! [embedded-hal]: https://github.com/rust-embedded/embedded-hal
#![no_std]
#![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 self::gpio::IO;
/// Common module for analog functions
pub mod analog {
pub use esp_hal_common::analog::{AvailableAnalog, SarAdcExt};

View File

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

View File

@ -9,7 +9,7 @@ use esp32c3_hal::{
clock::ClockControl,
peripherals::Peripherals,
prelude::*,
rom::crc,
rom::{crc, md5},
timer::TimerGroup,
Rtc,
Uart,
@ -48,6 +48,7 @@ fn main() -> ! {
timer0.start(1u64.secs());
let data = "123456789";
let sentence = "The quick brown fox jumps over a lazy dog";
writeln!(
uart0,
@ -74,10 +75,38 @@ fn main() -> ! {
assert_eq!(crc_rohc, 0xd0);
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!(
uart0,
"{:08x} {:08x} {:08x} {:08x} {:04x} {:04x} {:02x} {:02x}",
crc_hdlc, crc_bzip2, crc_mpeg2, crc_cksum, crc_kermit, crc_genibus, crc_rohc, crc_smbus
"{:08x} {:08x} {:08x} {:08x} {:04x} {:04x} {:02x} {:02x} {}",
crc_hdlc,
crc_bzip2,
crc_mpeg2,
crc_cksum,
crc_kermit,
crc_genibus,
crc_rohc,
crc_smbus,
md5_digest
)
.unwrap();

View File

@ -20,10 +20,10 @@ use esp32c3_hal::{
clock::ClockControl,
embassy,
i2c::I2C,
interrupt,
peripherals::{Interrupt, Peripherals, I2C0},
prelude::*,
timer::TimerGroup,
Priority,
Rtc,
IO,
};
@ -92,7 +92,7 @@ fn main() -> ! {
&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());
executor.run(|spawner| {

View File

@ -1,17 +1,20 @@
//! embassy serial
//!
//! This is an example of running the embassy executor and asynchronously
//! writing to a uart.
//! writing to and reading from uart
#![no_std]
#![no_main]
#![feature(type_alias_impl_trait)]
use core::fmt::Write;
use embassy_executor::Executor;
use embassy_time::{Duration, Timer};
use embassy_time::{with_timeout, Duration};
use esp32c3_hal::{
clock::ClockControl,
embassy,
interrupt,
peripherals::{Interrupt, Peripherals, UART0},
prelude::*,
timer::TimerGroup,
@ -19,18 +22,79 @@ use esp32c3_hal::{
Uart,
};
use esp_backtrace as _;
use esp_hal_common::uart::config::AtCmdConfig;
use heapless::Vec;
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]
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 {
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
.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)
.await
.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")]
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());
executor.run(|spawner| {

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,16 +1,15 @@
//! `no_std` HAL for the ESP32-C3/ESP8685 from Espressif.
//!
//! Implements a number of the traits defined by the various packages in the
//! [embedded-hal] repository.
//!
//! [embedded-hal]: https://github.com/rust-embedded/embedded-hal
#![no_std]
#![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 self::gpio::IO;
/// Common module for analog functions
pub mod analog {
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 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;
for i in 0..FLASH_MMU_TABLE_SIZE {

View File

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

View File

@ -33,7 +33,7 @@ By default, [espflash](https://github.com/esp-rs/espflash) fetches the required
#### Direct Boot
[Direct Boot](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

View File

@ -9,7 +9,7 @@ use esp32c6_hal::{
clock::ClockControl,
peripherals::Peripherals,
prelude::*,
rom::crc,
rom::{crc, md5},
timer::TimerGroup,
Rtc,
Uart,
@ -48,6 +48,7 @@ fn main() -> ! {
timer0.start(1u64.secs());
let data = "123456789";
let sentence = "The quick brown fox jumps over a lazy dog";
writeln!(
uart0,
@ -74,10 +75,38 @@ fn main() -> ! {
assert_eq!(crc_rohc, 0xd0);
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!(
uart0,
"{:08x} {:08x} {:08x} {:08x} {:04x} {:04x} {:02x} {:02x}",
crc_hdlc, crc_bzip2, crc_mpeg2, crc_cksum, crc_kermit, crc_genibus, crc_rohc, crc_smbus
"{:08x} {:08x} {:08x} {:08x} {:04x} {:04x} {:02x} {:02x} {}",
crc_hdlc,
crc_bzip2,
crc_mpeg2,
crc_cksum,
crc_kermit,
crc_genibus,
crc_rohc,
crc_smbus,
md5_digest
)
.unwrap();

View File

@ -20,10 +20,10 @@ use esp32c6_hal::{
clock::ClockControl,
embassy,
i2c::I2C,
interrupt,
peripherals::{Interrupt, Peripherals, I2C0},
prelude::*,
timer::TimerGroup,
Priority,
Rtc,
IO,
};
@ -92,7 +92,7 @@ fn main() -> ! {
&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());
executor.run(|spawner| {

View File

@ -1,17 +1,20 @@
//! embassy serial
//!
//! This is an example of running the embassy executor and asynchronously
//! writing to a uart.
//! writing to and reading from uart
#![no_std]
#![no_main]
#![feature(type_alias_impl_trait)]
use core::fmt::Write;
use embassy_executor::Executor;
use embassy_time::{Duration, Timer};
use embassy_time::{with_timeout, Duration};
use esp32c6_hal::{
clock::ClockControl,
embassy,
interrupt,
peripherals::{Interrupt, Peripherals, UART0},
prelude::*,
timer::TimerGroup,
@ -19,18 +22,79 @@ use esp32c6_hal::{
Uart,
};
use esp_backtrace as _;
use esp_hal_common::uart::config::AtCmdConfig;
use heapless::Vec;
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]
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 {
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
.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)
.await
.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")]
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());
executor.run(|spawner| {

View File

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

View File

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

View File

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

View File

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

View File

@ -1,13 +1,15 @@
//! `no_std` HAL for the ESP32-C6 from Espressif.
//!
//! Implements a number of the traits defined by the various packages in the
//! [embedded-hal] repository.
//!
//! [embedded-hal]: https://github.com/rust-embedded/embedded-hal
#![no_std]
#![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 self::gpio::IO;
/// Common module for analog functions
pub mod analog {
pub use esp_hal_common::analog::{AvailableAnalog, SarAdcExt};

View File

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

View File

@ -1,17 +1,17 @@
# esp32h2-hal
<!-- [![Crates.io](https://img.shields.io/crates/v/esp32h2-hal?labelColor=1C2C2E&color=C96329&logo=Rust&style=flat-square)](https://crates.io/crates/esp32h2-hal)
[![Crates.io](https://img.shields.io/crates/v/esp32h2-hal?labelColor=1C2C2E&color=C96329&logo=Rust&style=flat-square)](https://crates.io/crates/esp32h2-hal)
[![docs.rs](https://img.shields.io/docsrs/esp32h2-hal?labelColor=1C2C2E&color=C96329&logo=rust&style=flat-square)](https://docs.rs/esp32h2-hal)
![Crates.io](https://img.shields.io/crates/l/esp32h2-hal?labelColor=1C2C2E&style=flat-square) -->
![Crates.io](https://img.shields.io/crates/l/esp32h2-hal?labelColor=1C2C2E&style=flat-square)
[![Matrix](https://img.shields.io/matrix/esp-rs:matrix.org?label=join%20matrix&labelColor=1C2C2E&color=BEC5C9&logo=matrix&style=flat-square)](https://matrix.to/#/#esp-rs:matrix.org)
`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.
<!-- ## [Documentation]
## [Documentation]
[documentation]: https://docs.rs/esp32h2-hal/ -->
[documentation]: https://docs.rs/esp32h2-hal/
## Getting Started
@ -33,7 +33,7 @@ By default, [espflash](https://github.com/esp-rs/espflash) fetches the required
#### 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
@ -73,4 +73,4 @@ at your option.
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in
the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without
any additional terms or conditions.
any additional terms or conditions.

View File

@ -9,7 +9,7 @@ use esp32h2_hal::{
clock::ClockControl,
peripherals::Peripherals,
prelude::*,
rom::crc,
rom::{crc, md5},
timer::TimerGroup,
Rtc,
Uart,
@ -49,6 +49,7 @@ fn main() -> ! {
timer0.start(1u64.secs());
let data = "123456789";
let sentence = "The quick brown fox jumps over a lazy dog";
writeln!(
uart0,
@ -75,10 +76,38 @@ fn main() -> ! {
assert_eq!(crc_rohc, 0xd0);
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!(
uart0,
"{:08x} {:08x} {:08x} {:08x} {:04x} {:04x} {:02x} {:02x}",
crc_hdlc, crc_bzip2, crc_mpeg2, crc_cksum, crc_kermit, crc_genibus, crc_rohc, crc_smbus
"{:08x} {:08x} {:08x} {:08x} {:04x} {:04x} {:02x} {:02x} {}",
crc_hdlc,
crc_bzip2,
crc_mpeg2,
crc_cksum,
crc_kermit,
crc_genibus,
crc_rohc,
crc_smbus,
md5_digest
)
.unwrap();

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